問題描述
我是不是瘋了,還是 Postgres PDO 驅動程序不支持準備好的語句,而是在客戶端模擬它們?
Am I losing my mind, or does the Postgres PDO driver just not support prepared statements, but instead emulates them client side?
以下代碼為 prepare() 調用返回 NO ERROR,即使它應該.相反,它在調用 execute() 時返回適用的錯誤.
The following code returns NO ERROR for the prepare() call, even though it should. Instead, it returns the applicable error when execute() is called.
因為根據 Daniel Vérité 我錯了,我添加了他建議的代碼.我仍然收到錯誤.我的代碼現在看起來像下面這樣,添加了 Daniel 的行.
Since according to Daniel Vérité I'm wrong, I added his suggested code. I still get the error. My code now looks like the below, with Daniel's line added.
<?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.
PHP version 5.3.15, PHP Postgres client version 9.1.4, Postgres server version 9.2.1.
推薦答案
參見 http://www.php.net/manual/en/pdo.prepare.php
注意:
模擬的預處理語句不與數據庫通信服務器,因此 PDO::prepare() 不檢查語句.
Emulated prepared statements does not communicate with the database server so PDO::prepare() does not check the statement.
(實際上,無論如何都不會立即發送真正的準備好的語句,請參閱下面對 Q2 的回答)
(in fact real prepared statements are not sent immediately anyway, see answer to Q2 below)
無論如何你可以發出:
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES,false);
獲得使用 SQL PREPARE 命令實現的真正準備好的語句.請參閱http://www.php.net/manual/en/pdo.setattribute.php了解更多.
to get real prepared statements implemented with the SQL PREPARE command. See http://www.php.net/manual/en/pdo.setattribute.php for more.
在進一步的討論和測試中,出現了兩個問題:
On further discussion and tests, two questions arise:
第一季度.為什么 pdo::getAttribute(PDO::ATTR_EMULATE_PREPARES)
會產生錯誤?
實際上 setAttribute
沒有出錯,但是 getAttribute(PDO::ATTR_EMULATE_PREPARES)
說:
Q1. Why does pdo::getAttribute(PDO::ATTR_EMULATE_PREPARES)
yield an error?
Indeed setAttribute
doesn't error out but getAttribute(PDO::ATTR_EMULATE_PREPARES)
says:
'SQLSTATE[IM001]: 驅動程序不支持此功能:驅動程序支持不支持該屬性'
'SQLSTATE[IM001]: Driver does not support this function: driver does not support that attribute'
查看 pdo::getAttribute 的文檔,它說常量適用于數據庫連接的如下,從PDO::ATTR_AUTOCOMMIT
到PDO::ATTR_TIMEOUT
的一些常量,值得注意的是PDO::ATTR_EMULATE_PREPARES
不在其中.所以嚴格來說,無論如何,我們不應該期望 getAttribute(PDO::ATTR_EMULATE_PREPARES)
起作用.
Looking at the documentation for pdo::getAttribute, it says The constants that apply to database connections are as follows, and a number of constants follow from PDO::ATTR_AUTOCOMMIT
to PDO::ATTR_TIMEOUT
, and it's remarkable that PDO::ATTR_EMULATE_PREPARES
is not in them. So strictly speaking, we should not expect getAttribute(PDO::ATTR_EMULATE_PREPARES)
to work, anyway.
現在查看源代碼可以肯定的是,pdo_pgsql
驅動程序似乎提供了一個 pdo_pgsql_get_attribute
函數,該函數具有一個 switch 語句:
Now looking at the source code to be sure, it appears that the pdo_pgsql
driver provides a pdo_pgsql_get_attribute
function that has a switch statement on:
- PDO_ATTR_CLIENT_VERSION
- PDO_ATTR_SERVER_VERSION
- PDO_ATTR_CONNECTION_STATUS
- PDO_ATTR_SERVER_INFO
就是這樣.沒有 PDO_ATTR_EMULATE_PREPARES 的痕跡,這就是最終出現此錯誤的原因.
and that's it. No trace of PDO_ATTR_EMULATE_PREPARES which is why ultimately this error appears.
另一方面,函數pdo_pgsql_set_attr
有一個switch語句:
On the other hand, the function pdo_pgsql_set_attr
has a switch statement on:
- PDO_ATTR_EMULATE_PREPARES
- PDO_PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT
確認在設置時實際考慮了此屬性.所以 PDO 只是與 getAttribute
不一致,不匹配 setAttribute
.
which confirms that this attribute is actually taken into account when set.
So PDO is just inconsistent with getAttribute
that doesn't match setAttribute
.
Q2 - 當準備模擬為假時,為什么虛假語句在準備時不會立即引發錯誤?
考慮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 的原因:它實際上不會因為缺少參數類型而發送到服務器.
It shows that PQprepare
is used (so that's a "real" prepared statement), but also that the statement is not immediately sent to the server. That's why the dbo::prepare("bogus statement")
won't return false: it's actually not sent to the server for lack of parameter types.
這篇關于PHP Postgres PDO 驅動不支持prepared statement?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!