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.
<?php
$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.
PDO will emulate prepared statements/bound parameters for drivers that do not natively support them, and can also rewrite named or question mark style parameter markers to something more appropriate, if the driver supports one style but not the other.
Fetch data from a result set by calling one of the following fetch methods: To return a single row from a result set as an array or object, call the PDOStatement::fetch method. To return all of the rows from the result set as an array of arrays or objects, call the PDOStatement::fetchAll method.
PDO::query() prepares and executes an SQL statement in a single function call, returning the statement as a PDOStatement object.
See http://www.php.net/manual/en/pdo.prepare.php
Note:
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:
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:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With