PostgreSQL syntax error in parameterized query on “date $1”

后端 未结 2 932
被撕碎了的回忆
被撕碎了的回忆 2021-01-24 14:47

Trying to parameterize my SQL queries (using libpq function PQexecParams), I was stuck on a syntax error:

SELECT date $1

The error is:

2条回答
  •  时光说笑
    2021-01-24 15:10

    Prepared statements

    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, the type '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 :: or CAST() 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');
    

    Similar for PQexecParams in the libpq C library

    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 as bigint, 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 is NULL, 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.

提交回复
热议问题