go to bug id or search bugs for
When I prepare the following query:
SELECT * FROM post WHERE locations ? :location;
The following warning occur:
Warning: PDO::prepare(): SQLSTATE[HY093]: Invalid parameter number: mixed named and positional parameters in /path/file.php on line xx
The question mark is an valid PostgreSQL operator but PDO condsider it as a placeholder. - http://www.postgresql.org/docs/9.5/static/functions-json.html
I thought of several solutions:
1. Allow to disable question mark as placeholder. Leaving you with named placeholders.
2. Allow to change the placeholder char from a default value (?).
3. Teach pg driver to distinguish when it is a placeholder or an operator.
I think I favor point 2.
I also discussed it here:
Add a Patch
Add a Pull Request
Turn off emulated prepares.
Enabling or disabling emulated prepares does not work around this issue, it just changes which error messages you see.
In the simplest case, with no actual parameters:
- When emulation is enabled, the ? will be treated as a placeholder by the emulation code itself, and raise an error about the parameter not being filled.
- When emulation is disabled, PDO will still parse it and replace ? with $1, so that Postgres will expect a parameter. (This then gives a syntax error because that's an illegal position for a placeholder.)
In the case where there is a real named parameter alongside the ? operator (as in the OP's example), PDO parses the statement to detect whether named or positional parameters were used (because the driver may need to rewrite the syntax) and will complain that it's found a mixture *before even attempting to prepare it*.
The ability to change (or disable) the placeholder char would fix all these cases, since the ? placeholder is being read by PDO in all cases: either to emulate prepares, or to rewrite to the syntax appropriate for the selected DB driver.
The following code failed:
$sql = "SELECT * FROM post WHERE locations ? :location ORDER BY locations->:location"
$stmt = $pdo->prepare($sql); // tried this and version bellow
$stmt = $pdo->prepare($sql, [\PDO::ATTR_EMULATE_PREPARES=>false]);
$stmt->bindValue(':location', 'bar', \PDO::PARAM_STR);
Error when ATTR_EMULATE_PREPARES is false that happen at the line of the prepare():
Warning: PDO::prepare(): SQLSTATE[HY093]: Invalid parameter number: mixed named and positional parameters in /path/file.php on line 57
Error when ATTR_EMULATE_PREPARES is true that happen at the line of the execute():
Warning: PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number: mixed named and positional parameters in /path/file.php on line 48
I missed rowan answer.
So I guess ATTR_EMULATE_PREPARES is irrelevant
I don't maintain PDO pgsql, but I think it cannot workaround unless introducing new place holder. i.e. Specify meta char like "LIKE" query.
Obvious workaround is to use pgsql module. One needs native extension to use most out of PostgreSQL.
PDO has its own advantages. For example the named placeholders and its general abstraction.
If only we could set the placeholder char or disable the question mark it would be perfect.
There are plenty of alternatives on the postgres side, i.e. using the underlying function, or defining a new operator. Adapting PDO is not going to be that easy, in comparison.
All of the proposed solutions sound rather complex to me.
I would suggest a much simpler approach: just allow us to escape the question mark placeholder to make PDO ignore it, e.g. as "\?" - consistent with the way it's done by virtually every other string template facility in PHP.
Confirmed, same bug here as well. Ubuntu 14, PHP 5.5, PostgreSQL 9.4.
The "?" is a pretty commonly used operator within PostgreSQL, so this is most definitely going to become a problem as people begin migrating to newer versions of PostgreSQL.
For those of you stumbling onto this page in the same predicament, here is an in-line solution-- No stored procedures necessary, still indexable.
SELECT * FROM my_table WHERE my_col ? 'my_key'
Do one of the following, depending on the PostgreSQL data-type you're working with:
SELECT * FROM my_table WHERE EXIST(my_col, my_key)
SELECT * FROM my_table WHERE JSONB_EXISTS(my_col, my_key)
To query for a full list of functions bound to the "?" operator (this will help you find other functions for data types not covered above) on your database, perform the following query:
SELECT oprname, oprcode FROM pg_operator WHERE oprname = '?'