5

我是不是疯了,或者 Postgres PDO 驱动程序不支持准备好的语句,而是在客户端模拟它们?

以下代码为 prepare() 调用返回 NO ERROR,即使它应该返回。相反,它在调用 execute() 时返回适用的错误。

编辑:因为根据 Daniel Vérité 我错了,我添加了他建议的代码。我仍然得到错误。我的代码现在如下所示,添加了 Daniel 的行。

<?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 版本 5.3.15,PHP Postgres 客户端版本 9.1.4,Postgres 服务器版本 9.2.1。

4

1 回答 1

9

http://www.php.net/manual/en/pdo.prepare.php

笔记:

模拟的预处理语句不与数据库服务器通信,因此 PDO::prepare() 不检查语句。

(事实上​​,无论如何都不会立即发送真正准备好的语句,请参阅下面对 Q2 的回答)

无论如何,您可能会发出:

$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES,false); 

使用 SQL PREPARE 命令实现真正的准备好的语句。有关更多信息,请参见http://www.php.net/manual/en/pdo.setattribute.php

在进一步的讨论和测试中,出现了两个问题:

Q1。为什么会pdo::getAttribute(PDO::ATTR_EMULATE_PREPARES)产生错误?
IndeedsetAttribute不会出错,但会getAttribute(PDO::ATTR_EMULATE_PREPARES)说:

'SQLSTATE[IM001]:驱动程序不支持此功能:驱动程序不支持该属性'

查看 pdo::getAttribute的文档,它说适用于数据库连接的常量如下,并且从PDO::ATTR_AUTOCOMMITto后面跟着一些常量PDO::ATTR_TIMEOUT,值得注意的PDO::ATTR_EMULATE_PREPARES不在其中getAttribute(PDO::ATTR_EMULATE_PREPARES)所以严格来说,无论如何,我们不应该期望工作。

现在查看源代码可以确定,pdo_pgsql驱动程序似乎提供了一个pdo_pgsql_get_attribute具有 switch 语句的函数:

  • PDO_ATTR_CLIENT_VERSION
  • PDO_ATTR_SERVER_VERSION
  • PDO_ATTR_CONNECTION_STATUS
  • PDO_ATTR_SERVER_INFO

就是这样。没有 PDO_ATTR_EMULATE_PREPARES 的痕迹,这就是最终出现此错误的原因。

另一方面,该函数pdo_pgsql_set_attr有一个 switch 语句:

  • PDO_ATTR_EMULATE_PREPARES
  • PDO_PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT

这确认了在设置时实际上考虑了该属性。所以 PDO 只是与getAttributethat doesn't match不一致setAttribute

Q2 - 当prepare emulation 为false 时,为什么虚假语句在prepared 时不会立即引发错误?

考虑以下代码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);

它表明PQprepare已使用(所以这是一个“真正的”准备好的语句),但也表明该语句不会立即发送到服务器。这就是为什么dbo::prepare("bogus statement")不会返回 false 的原因:由于缺少参数类型,它实际上没有发送到服务器。

于 2013-07-05T16:40:40.067 回答