2013-07-05 69 views
4

我是否會失去主意,還是Postgres PDO驅動程序不支持預準備語句,而是模擬它們的客戶端?PHP Postgres PDO驅動程序不支持預準備語句?

以下代碼對prepare()調用返回NO ERROR,即使它應該如此。相反,它會在調用execute()時返回適用的錯誤。

編輯:由於根據丹尼爾Vé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。

回答

8

http://www.php.net/manual/en/pdo.prepare.php

注:

模擬預處理語句不與數據庫 服務器通信,以PDO ::準備()不檢查語句。

(其實真正準備好的語句不是立即發送反正看答案下面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功能,有一個開關聲明:

  • 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不符,與setAttribute不符。

Q2 - 當準備仿真爲false時,爲什麼準備好時虛假聲明不立即引發錯誤?

考慮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:由於缺少參數類型,它實際上不會發送到服務器。

+0

Postgres PDO驅動程序沒有實現ATTR_EMULATE_PREPARES。 – CXJ

+0

它似乎被仿效。我在問爲什麼,當Postgres本地支持準備好的語句,實際上,PHP的Postgres的「本地」API,例如pg_prepare(),正確執行此操作。這是奇怪的PDO驅動程序。它壞了嗎?無證?只是我的版本? – CXJ

+0

準備好的語句是在2003年發佈的PG-7.4的客戶端 - 服務器協議中實現的。PDO for PG幾乎在同一時間首次發佈,所以它必須與現有的7.3以下版本一起工作,因此需要仿真。 –