Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
Am I losing my mind, or does the Postgres PDO driver just not support prepared statements, but instead emulates them client side?
The following code returns NO ERROR for the prepare() call, even though it should. Instead, it returns the applicable error when execute() is called.
Edit: Since according to Daniel Vérité I'm wrong, I added his suggested code. I still get the error. My code now looks like the below, with Daniel's line added.
$pdo = new PDO("pgsql:host=myhost;dbname=mydatabase");
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); // as suggested by Daniel
$sth = $pdo->prepare('COMPLETE GARBAGE');
echo "[prepare] errorInfo = " . print_r($sth->errorInfo(), true);
$sth->execute();
echo "[execute] errorInfo = " . print_r($sth->errorInfo(), true);
PHP version 5.3.15, PHP Postgres client version 9.1.4, Postgres server version 9.2.1.
Emulated prepared statements does not communicate with the database
server so PDO::prepare() does not check the statement.
(in fact real prepared statements are not sent immediately anyway, see answer to Q2 below)
Anyway you may issue:
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES,false);
to get real prepared statements implemented with the SQL PREPARE command.
See http://www.php.net/manual/en/pdo.setattribute.php for more.
On further discussion and tests, two questions arise:
Q1. Why does pdo::getAttribute(PDO::ATTR_EMULATE_PREPARES)
yield an error?
Indeed setAttribute
doesn't error out but getAttribute(PDO::ATTR_EMULATE_PREPARES)
says:
'SQLSTATE[IM001]: Driver does not support this function: driver does
not support that attribute'
Looking at the documentation for pdo::getAttribute, it says The constants that apply to database connections are as follows, and a number of constants follow from PDO::ATTR_AUTOCOMMIT
to PDO::ATTR_TIMEOUT
, and it's remarkable that PDO::ATTR_EMULATE_PREPARES
is not in them. So strictly speaking, we should not expect getAttribute(PDO::ATTR_EMULATE_PREPARES)
to work, anyway.
Now looking at the source code to be sure, it appears that the pdo_pgsql
driver provides a pdo_pgsql_get_attribute
function that has a switch statement on:
PDO_ATTR_CLIENT_VERSION
PDO_ATTR_SERVER_VERSION
PDO_ATTR_CONNECTION_STATUS
PDO_ATTR_SERVER_INFO
and that's it. No trace of PDO_ATTR_EMULATE_PREPARES which is why ultimately this error appears.
On the other hand, the function pdo_pgsql_set_attr
has a switch statement on:
PDO_ATTR_EMULATE_PREPARES
PDO_PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT
which confirms that this attribute is actually taken into account when set.
So PDO is just inconsistent with getAttribute
that doesn't match setAttribute
.
Q2 - When prepare emulation is false, why doesn't a bogus statement immediately raise an error when prepared?
Consider this piece of code in pgsql_statement.c
:
if (!S->is_prepared) {
stmt_retry:
/* we deferred the prepare until now, because we didn't
* know anything about the parameter types; now we do */
S->result = PQprepare(H->server, S->stmt_name, S->query,
stmt->bound_params ? zend_hash_num_elements(stmt->bound_params) : 0,
S->param_types);
It shows that PQprepare
is used (so that's a "real" prepared statement), but also that the statement is not immediately sent to the server. That's why the dbo::prepare("bogus statement")
won't return false: it's actually not sent to the server for lack of parameter types.
–
–
–
–
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.