Trying to parameterize my SQL queries (using libpq function PQexecParams), I was stuck on a syntax error:
SELECT date $1
The error is:
The explanation for this can be found in the chapter Constants of Other Types of the manual:
The
::
,CAST()
, and function-call syntaxes can also be used to specify run-time type conversions of arbitrary expressions, as discussed in Section 4.2.9. To avoid syntactic ambiguity, thetype 'string'
syntax can only be used to specify the type of a simple literal constant. Another restriction on the type'string' syntax
is that it does not work for array types; use::
orCAST()
to specify the type of an array constant.
Bold emphasis mine.
Parameters for prepared statements are not actually sting literals but typed values, so you cannot use the form type 'string'
. Use one of the other two forms to cast the value to a different type, like you found yourself already.
Example:
PREPARE foo AS SELECT $1::date;
EXECUTE foo('2005-1-1');
The documentation:
... In the SQL command text, attach an explicit cast to the parameter symbol to show what data type you will send. For example:
SELECT * FROM mytable WHERE x = $1::bigint;
This forces parameter
$1
to be treated asbigint
, whereas by default it would be assigned the same type as x. Forcing the parameter type decision, either this way or by specifying a numeric type OID, is strongly recommended. ...
The alternative, as mentioned in the quote above, is to pass the OIDs of respective data types with paramTypes[]
- if you actually need the cast. In most cases it should work just fine to let Postgres derive data types from the query context.
paramTypes[]
Specifies, by OID, the data types to be assigned to the parameter symbols. If
paramTypes
isNULL
, or any particular element in the array is zero, the server infers a data type for the parameter symbol in the same way it would do for an untyped literal string.
You can get the OID of data types from the system catalog pg_type:
SELECT oid FROM pg_type WHERE typname = 'date';
You must use the correct internal type name. For instance: int4
for integer
.
Or with a convenience cast to regtype:
SELECT 'date'::regtype::oid;
This is more flexible as known aliases for the type name are accepted as well. For instance: int4
, int
or integer
for integer
.