Php PDO未使用未绑定参数引发异常(查询中没有变量)

Php PDO未使用未绑定参数引发异常(查询中没有变量),php,postgresql,pdo,Php,Postgresql,Pdo,所以我不知道这里发生了什么 $link = new PDO('pgsql:dbname=' . $name . ';host=' . $host, $user, $password); $link->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); try { $stmt = $link->pr

所以我不知道这里发生了什么

$link = new PDO('pgsql:dbname=' . $name . ';host=' . $host, $user, $password);
$link->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

try {
    $stmt = $link->prepare("SELECT s.*, d.invalid_column FROM students s ORDER BY s.student_id");
    $stmt->execute(array(1));
}
catch (PDOException $e) {
    print $e->getMessage();
}
当我运行这个小代码示例时,我希望抛出一个异常(因为d.invalid_column不是实列,并且我正在传递无法绑定的参数),但唯一发生的事情是execute返回false,而其他什么都没有。此外,
$stmt->errorInfo()
为空,代码为
00000
,这使得除了超级通用之外很难添加适当的异常抛出,而日志中没有其他内容,以帮助我在某些最终用户报告错误时跟踪错误

如果我在查询的某个地方添加了一个“?”,则会抛出正确的执行(该
d.invalid_column
不是有效的列),即使我添加了更多不绑定任何内容的参数

因此,如何使此查询正确返回错误:
1) 清除所有参数
2) 将“?”添加到查询中

这只是PDO中的一个bug还是什么

编辑: 将引发异常的设置(无效列):


只有当我的查询中没有
并将某些内容传递给
execute()
时,事情才会无声地失败,PDO也没有解释。

这种行为在当前的PHP(5.6.13)中是可复制的,查询甚至不会发送到服务器

您的案例描述如下:

绑定的值不能超过指定值;如果中存在更多密钥 在PDO::prepare()中指定的SQL中输入_参数,然后 语句将失败并发出错误

应为0值,给出1值,语句失败,返回
false
。到目前为止,它的工作是有据可查的

您可能认为“发出错误”意味着当启用
ERRMODE\u EXCEPTION
时,将引发异常。这是一个论点,但PDO开发人员是否会同意这一点并不明显

更新:

为什么未设置
SQLCode

查看PDO源代码,特别是处理PDO::execute()的
静态PHP_方法(PDOStatement,execute)
,您可以看到所有错误都由宏处理:
PDO_HANDLE\u STMT_ERR()

关键是,当PDO期望无时传递绑定参数时,查询永远不会将其传递给SQL引擎,因此SQL引擎永远没有机会报告伴随SQLSTATE的错误

PDO本身不会自己创建一个伪的
SQLSTATE
,在这种情况下至少不会,因此
stmt->error\u code
停留在
PDO\u ERR\u NONE
,即
“00000”

您希望提出例外是可以理解的,但是您应该建议

与MySQL相同吗?

是的,根的行为是相同的,除了MySQL驱动程序外,
prepare
会立即发送到SQL引擎,因此如果它因为列错误而不正确,它会更早失败,并出现真正的SQL错误。另一方面,PgSQL驱动程序有一个不同的实现,使其延迟服务器端
prepare
。有关此特定行为的详细讨论,请参阅

无论如何,这里有一个MySQL的案例,演示了我的解释,即:

  • 查询需要0个参数,如果给定1
  • $stmt->execute
    返回false
  • 没有引发异常
  • PDO::错误代码为
    00000
代码:

结果:

查询失败,错误代码=00000

引擎罩下发生的情况是,
prepare
被发送到服务器并成功,但是由于参数不匹配,
execute
步骤被PDO取消

这里有一个不同的例子,查询引用了一个不存在的列。我正在添加一个打印,以显示甚至没有调用
$stmt->execute
,因为异常是由
$stmt->prepare
引发的

代码:

结果:

发生PDO异常DsqlState[42S22]:未找到列:1054 “字段列表”中的未知列“不存在”

请注意,“执行查询”步骤是如何从不发生的,因为服务器端的
prepare
失败了

结论

  • 当查询被发送到服务器时,无论是在prepare()还是execute()中,并且是服务器生成了一个错误,那么我们可以期望引发一个异常

  • 当查询没有发送到服务器执行步骤时,PDO execute()可能会失败(返回false),但不会引发异常,
    errorCode()
    保持在
    00000


    • 这是PDO中的一个bug,NikiC最近修复了它。请参阅bug和

      问题是PDO没有检查来自
      EVT_ALLOC
      的错误。这是过去几个月修复的与错误报告相关的许多问题之一


      如果PDO中的任何方法在异常模式下返回false而不引发异常,那么它就是一个bug。请向GitHub PR报告任何未来的错误,如果可能,请建议GitHub PR进行修复。

      为什么不能绑定参数?这没有任何意义。因为在本例中,它们(在
      PDOStatement::execute()
      中的
      $input_参数
      )没有要绑定的对象?对于指定太多的输入参数是否会引发异常,我发现了相互矛盾的答案。使用您的原始代码,我可以确认没有引发异常。但是我确实在
      $stmt->errorInfo()
      中看到了一个错误:
      字段列表中的未知列“d.invalid\u column”。实际上,我忘了包含您的
      setAttribute
      语句。此时会引发异常:
      SQLSTATE[42S22]:未找到列:1054未知列“d.invalid\u Column”位于“field list”
      。错误也出现在
      $link->errorInfo()
      中。PHP可能正在评估
      数组(1)
      a
          $stmt = $link->prepare("SELECT s.*, d.invalid_column, ? FROM students s ORDER BY s.student_id");
          $stmt->execute(array(1));
      
          $stmt = $link->prepare("SELECT s.*, d.invalid_column, ? FROM students s ORDER BY s.student_id");
          $stmt->execute(array(1,2,3));
      
          $stmt = $link->prepare("SELECT s.*, d.invalid_column, ? FROM students s ORDER BY s.student_id");
          $stmt->execute();
      
          $stmt = $link->prepare("SELECT s.*, d.invalid_column FROM students s ORDER BY s.student_id");
          $stmt->execute();
      
      #define PDO_HANDLE_STMT_ERR()   if (strcmp(stmt->error_code, PDO_ERR_NONE)) { pdo_handle_error(stmt->dbh, stmt TSRMLS_CC); }
      
      $link = new PDO('mysql:dbname=' . $name . ';host=' . $host, $user, $password);
      $link->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
      $link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
      
      try {
          $stmt = $link->prepare("SELECT 1");
          $rc=$stmt->execute(array(1));
         if ($rc===false)
          echo "query failed, errorCode=", $link->errorCode(), "\n";
         else
          echo "query succeeded, errorCode=", $link->errorCode(), "\n";
      }
      catch (PDOException $e) {
          print "A PDOException has occurred";
          print $e->getMessage();
      }
      
      $link = new PDO('mysql:dbname=' . $name . ';host=' . $host, $user, $password);
      $link->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
      $link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
      
      try {
          $stmt = $link->prepare("SELECT nonexisting");
          echo "Executing query\n";
          $rc=$stmt->execute(array(1));
         if ($rc===false)
          echo "query failed, errorCode=", $link->errorCode(), "\n";
         else
          echo "query succeeded, errorCode=", $link->errorCode(), "\n";
      }
      catch (PDOException $e) {
        print "A PDOException has occurred";
          print $e->getMessage();
      }