PHP Postgres PDO driver does not support prepared statement?

后端 未结 1 1225
陌清茗
陌清茗 2020-12-19 12:44

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

相关标签:
1条回答
  • 2020-12-19 13:00

    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:

    • 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.

    0 讨论(0)
提交回复
热议问题