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.

    It certainly appears to be emulated. I'm asking why, when Postgres natively supports prepared statements, and in fact, PHP's "native" API to Postgres, e.g. pg_prepare(), does this correctly. It's the PDO driver that's strange. Is it broken? Undocumented? Just my version? – CXJ Jul 5, 2013 at 16:45 Prepared statements were implemented in the client-server protocol in PG-7.4 released in 2003. PDO for PG was first released at about the same time, so it had to work with the existing base 7.3 and lower, hence the need for emulation. – Daniel Vérité Jul 5, 2013 at 17:32 @CXJ: as for your remark that the driver doesn't support ATTR_EMULATE_PREPARES, you're just plain wrong, read the source code. – Daniel Vérité Jul 5, 2013 at 17:33 $pdo->getAttribute(PDO::ATTR_EMULATE_PREPARES); returns this error message: PHP Warning: PDO::getAttribute(): SQLSTATE[IM001]: Driver does not support this function: driver does not support that attribute in /Users/cxj/test.php on line 10 That sure looks like "does not support" to me. – CXJ Jul 5, 2013 at 17:52

    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.