[英]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 的案例,它展示了我的解釋,即:
$stmt->execute
返回 false00000
代碼:
$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.