PHP Postgres PDO驱动程序不支持预处理语句?

时间:2013-07-05 16:07:35

标签: php postgresql pdo

我是否会失去理智,或者Postgres PDO驱动程序是否不支持预备语句,而是模仿客户端?

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

编辑:因为根据DanielVé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。

1 个答案:

答案 0 :(得分:8)

请参阅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)会产生错误?
确实setAttribute没有错误,但getAttribute(PDO::ATTR_EMULATE_PREPARES)说:

  

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

查看documentation for pdo::getAttribute,它说适用于数据库连接的常量如下,并且从PDO::ATTR_AUTOCOMMITPDO::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与getAttribute的{​​{1}}不一致。

Q2 - 当准备仿真为假时,为什么伪造的声明在准备好后不会立即引发错误?

setAttribute中考虑这段代码:

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不会返回false的原因:由于缺少参数类型,它实际上没有被发送到服务器。