簡體   English   中英

PDO 不會拋出帶有未綁定參數的異常(並且查詢中沒有變量)

[英]PDO not throwing exception with unbound parameters (and no variables in query)

所以我不知道這里發生了什么

$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 中的錯誤還是什么?

編輯:將引發異常的設置(無效列):

    $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();

只有當我沒有? 在我的查詢中並將某些內容傳遞給execute() ,這些內容只是默默地失敗,而 PDO 沒有任何解釋。

該行為可在當前的 PHP (5.6.13) 中重現,並且查詢甚至不會發送到服務器。

您的案例在文檔中描述為:

您不能綁定比指定更多的值; 如果 input_parameters 中存在的鍵多於 PDO::prepare() 中指定的 SQL 中的鍵,則該語句將失敗並發出錯誤。

預期值為 0,給出 1 值,語句失敗,返回false 到目前為止,按照文檔工作。

您可能會爭辯說“發出錯誤”意味着當ERRMODE_EXCEPTION開啟時,會拋出異常。 這是一個論點,但 PDO 開發人員是否同意這一點並不明顯。

更新:

為什么沒有設置SQLCode

查看 PDO 源代碼,特別是處理 PDO::execute() 的static PHP_METHOD(PDOStatement, execute) ),您可以看到所有錯誤都由一個宏處理: PDO_HANDLE_STMT_ERR()

#define PDO_HANDLE_STMT_ERR()   if (strcmp(stmt->error_code, PDO_ERR_NONE)) { pdo_handle_error(stmt->dbh, stmt TSRMLS_CC); }

關鍵是,當 PDO 期望沒有時傳遞綁定參數時,查詢永遠不會將其發送到 SQL 引擎,因此 SQL 引擎永遠沒有機會報告伴隨 SQLSTATE 的錯誤

PDO 本身不會自行創建假SQLSTATE ,至少在那種情況下不會,因此stmt->error_code停留在PDO_ERR_NONE ,即"00000"

可以理解您希望引發異常,但是您應該向https://bugs.php.net提出建議

和 MySQL 一樣嗎?

是的,root 行為是相同的,除了使用 MySQL 驅動程序時, prepare會立即發送到 SQL 引擎,因此如果由於列錯誤而導致錯誤,它會更早失敗並出現真正的 SQL 錯誤。 另一方面,PgSQL 驅動程序有一個不同的實現,使它推遲服務器端prepare 這種特殊行為在PHP Postgres PDO 驅動程序不支持准備好的語句中有詳細討論

無論如何,這是一個 MySQL 的案例,它展示了我的解釋,即:

  • 查詢需要 0 個參數,給出 1
  • $stmt->execute返回 false
  • 沒有異常被提出
  • PDO::errorCode 是00000

代碼:

$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();
}

結果:

查詢失敗,errorCode=00000

幕后發生的事情是prepare發送到服務器並成功,但由於參數不匹配, execute步驟被 PDO 取消。

這是一個不同的情況,即查詢引用了一個不存在的列。 我正在添加一個打印來顯示$stmt->execute甚至沒有被調用,因為$stmt->prepare引發了異常

代碼:

$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();
}

結果:

發生 PDOExceptionSQLSTATE[42S22]: Column not found: 1054 Unknown column 'nonexisting' in 'field list'

請注意“執行查詢”步驟如何永遠不會發生,因為它是服務器端的prepare失敗。

結論

  • 當查詢被發送到服務器時,無論是在 prepare() 還是 execute() 中,並且是服務器產生錯誤,那么我們可以預期會引發 PDOException。

  • 當查詢未發送到服務器進行執行步驟時,PDO execute() 可能會失敗(返回 false)但不會拋出異常並且errorCode()保持在00000

這是 PDO 中的一個錯誤,NikiC 最近修復了它。 請參閱錯誤#72368#79131

問題是 PDO 沒有檢查來自EVT_ALLOC錯誤。 這是過去幾個月修復的與錯誤報告相關的眾多問題之一。

如果 PDO 中的任何方法在異常模式下返回 false 而不拋出異常,那么它就是一個錯誤。 請向https://bugs.php.net/報告任何未來的錯誤,並在可能的情況下建議 GitHub PR 來修復它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM