ZF-11110: Zend_Db_Statement_Pdo uses unsuitable PDO methods

Description

Some PDO methods have different semantics compared to Zend_Db:

When no $type argument is given to PDOStatement::bindValue(...), it always assumes a string type. However, Zend_Db_Statement::bindValue(...) is expected to determine the database type from the value's PHP type.

PDOStatement::execute($params) treats all values of $params as strings, while Zend_Db_Statement::execute($params) is expected to respect their PHP types.

This means that the Zend_Db_Statement_Pdo implementation can only make use of:

* PDOStatement::bindValue(...) with an explicit $type argument
* PDOStatement::execute() without the $params argument

The attached patch fixes both issues for ZF 1.11.3, so all types including Boolean types will work properly.

This solves, among others, the issue with PDO/PostgreSQL and FALSE (ZF-538). However, in contrast to the solution discussed in ZF-538, this patch only affects the Pdo adapter and does not force all other adapters to use explicit binds.

Comments

Since this issue tracking system doesn't allow me to upload a patch, I'm providing it here. Sorry for the inconvenience:


fix type issues (e.g. PostgreSQL/FALSE is encoded as empty string "''" instead of "false") by avoiding unsuitable PDO methods in Zend_Db_Statement_Pdo

diff --git a/library/Zend/Db/Statement/Pdo.php b/library/Zend/Db/Statement/Pdo.php
index 775e401..d17cc87 100644
--- a/library/Zend/Db/Statement/Pdo.php
+++ b/library/Zend/Db/Statement/Pdo.php
@@ -137,10 +137,17 @@ class Zend_Db_Statement_Pdo extends Zend_Db_Statement implements IteratorAggrega
 
         try {
             if ($type === null) {
-                return $this->_stmt->bindValue($parameter, $value);
-            } else {
-                return $this->_stmt->bindValue($parameter, $value, $type);
+                if (is_bool($value)) {
+                    $type = PDO::PARAM_BOOL;
+                } elseif ($value === null) {
+                    $type = PDO::PARAM_NULL;
+                } elseif (is_integer($value)) {
+                    $type = PDO::PARAM_INT;
+                } else {
+                    $type = PDO::PARAM_STR;
+                }
             }
+            return $this->_stmt->bindValue($parameter, $value, $type);
         } catch (PDOException $e) {
             require_once 'Zend/Db/Statement/Exception.php';
             throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e);
@@ -225,10 +232,15 @@ class Zend_Db_Statement_Pdo extends Zend_Db_Statement implements IteratorAggrega
     {
         try {
             if ($params !== null) {
-                return $this->_stmt->execute($params);
-            } else {
-                return $this->_stmt->execute();
+                foreach ($params as $parameter => $value) {
+                    if (is_int($parameter)) {
+                        $this->bindValue($parameter + 1, $value);
+                    } else {
+                        $this->bindValue($parameter, $value);
+                    }
+                }
             }
+            return $this->_stmt->execute();
         } catch (PDOException $e) {
             require_once 'Zend/Db/Statement/Exception.php';
             throw new Zend_Db_Statement_Exception($e->getMessage(), (int) $e->getCode(), $e);

This is duplicate of ZF-538.