]> granicus.if.org Git - php/commitdiff
Start adding new attribute to control multi statements
authorpwolanin <pwolanin@49851.no-reply.drupal.org>
Fri, 7 Nov 2014 22:18:44 +0000 (17:18 -0500)
committerJulien Pauli <jpauli@php.net>
Fri, 5 Dec 2014 16:03:31 +0000 (17:03 +0100)
ext/pdo_mysql/mysql_driver.c
ext/pdo_mysql/pdo_mysql.c
ext/pdo_mysql/php_pdo_mysql_int.h
ext/pdo_mysql/tests/pdo_mysql_attr_multi_statements.phpt [new file with mode: 0644]
ext/pdo_mysql/tests/pdo_mysql_class_constants.phpt
ext/pdo_mysql/tests/pdo_mysql_multi_stmt_nextrowset.phpt [new file with mode: 0644]

index 825fe2647f4246cced11ecf7e09920fe5822e761..348af3ed6a69cf55df17d511dc1fcacad249f36c 100644 (file)
@@ -551,10 +551,14 @@ static int pdo_mysql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_
 #ifdef CLIENT_MULTI_RESULTS
                |CLIENT_MULTI_RESULTS
 #endif
+               ;
 #ifdef CLIENT_MULTI_STATEMENTS
-               |CLIENT_MULTI_STATEMENTS
+       if (!driver_options) {
+               connect_opts |= CLIENT_MULTI_STATEMENTS;
+       } else if (pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_MULTI_STATEMENTS, 1 TSRMLS_CC)) {
+               connect_opts |= CLIENT_MULTI_STATEMENTS;
+       }
 #endif
-               ;
 
 #if defined(PDO_USE_MYSQLND)
        int dbname_len = 0;
index 6f4e9d5265d878a3d6beaedfe84d725a7f720cde..50da0ba783799c7e2401fe9d8416a21eca66fefd 100644 (file)
@@ -126,7 +126,7 @@ static PHP_MINIT_FUNCTION(pdo_mysql)
 #if MYSQL_VERSION_ID > 50605 || defined(PDO_USE_MYSQLND)
         REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_SERVER_PUBLIC_KEY", (long)PDO_MYSQL_ATTR_SERVER_PUBLIC_KEY);
 #endif
-
+       REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_MULTI_STATEMENTS", (zend_long)PDO_MYSQL_ATTR_MULTI_STATEMENTS);
 
 #ifdef PDO_USE_MYSQLND
        mysqlnd_reverse_api_register_api(&pdo_mysql_reverse_api TSRMLS_CC);
index 26263222b98563b79826d44f9dfe8492830ce972..36604b8dce5dca82926d914c01975c3624017fc6 100644 (file)
@@ -172,8 +172,9 @@ enum {
        PDO_MYSQL_ATTR_SSL_CAPATH,
        PDO_MYSQL_ATTR_SSL_CIPHER,
 #if MYSQL_VERSION_ID > 50605 || defined(PDO_USE_MYSQLND)
-       PDO_MYSQL_ATTR_SERVER_PUBLIC_KEY
+       PDO_MYSQL_ATTR_SERVER_PUBLIC_KEY,
 #endif
+       PDO_MYSQL_ATTR_MULTI_STATEMENTS,
 };
 
 #endif
diff --git a/ext/pdo_mysql/tests/pdo_mysql_attr_multi_statements.phpt b/ext/pdo_mysql/tests/pdo_mysql_attr_multi_statements.phpt
new file mode 100644 (file)
index 0000000..312dedd
--- /dev/null
@@ -0,0 +1,95 @@
+--TEST--
+PDO::MYSQL_ATTR_MULTI_STATEMENTS
+--SKIPIF--
+<?php
+require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
+require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
+MySQLPDOTest::skip();
+$db = MySQLPDOTest::factory();
+?>
+--INI--
+error_reporting=E_ALL
+--FILE--
+<?php
+       require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
+
+       $dsn = MySQLPDOTest::getDSN();
+       $user = PDO_MYSQL_TEST_USER;
+       $pass = PDO_MYSQL_TEST_PASS;
+
+       $table = sprintf("test_%s", md5(mt_rand(0, PHP_INT_MAX)));
+       $db = new PDO($dsn, $user, $pass);
+       $db->exec(sprintf('DROP TABLE IF EXISTS %s', $table));
+       $create = sprintf('CREATE TABLE %s(id INT)', $table);
+       $db->exec($create);
+       $db->exec(sprintf('INSERT INTO %s(id) VALUES (1)', $table));
+       $stmt = $db->query(sprintf('SELECT * FROM %s; INSERT INTO %s(id) VALUES (2)', $table, $table));
+       $stmt->closeCursor();
+       $info = $db->errorInfo();
+       var_dump($info[0]);
+       $stmt = $db->query(sprintf('SELECT id FROM %s', $table));
+       var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
+        // A single query with a trailing delimiter.
+       $stmt = $db->query('SELECT 1 AS value;');
+       var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
+
+       // New connection, does not allow multiple statements.
+       $db = new PDO($dsn, $user, $pass, array(PDO::MYSQL_ATTR_MULTI_STATEMENTS => false));
+       $stmt = $db->query(sprintf('SELECT * FROM %s; INSERT INTO %s(id) VALUES (3)', $table, $table));
+       var_dump($stmt);
+       $info = $db->errorInfo();
+       var_dump($info[0]);
+
+       $stmt = $db->query(sprintf('SELECT id FROM %s', $table));
+       var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
+        // A single query with a trailing delimiter.
+        $stmt = $db->query('SELECT 1 AS value;');
+        var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
+
+       $db->exec(sprintf('DROP TABLE IF EXISTS %s', $table));
+       print "done!";
+?>
+--EXPECTF--
+string(5) "00000"
+array(2) {
+  [0]=>
+  array(1) {
+    ["id"]=>
+    string(1) "1"
+  }
+  [1]=>
+  array(1) {
+    ["id"]=>
+    string(1) "2"
+  }
+}
+array(1) {
+  [0]=>
+  array(1) {
+    ["value"]=>
+    string(1) "1"
+  }
+}
+bool(false)
+string(5) "42000"
+array(2) {
+  [0]=>
+  array(1) {
+    ["id"]=>
+    string(1) "1"
+  }
+  [1]=>
+  array(1) {
+    ["id"]=>
+    string(1) "2"
+  }
+}
+array(1) {
+  [0]=>
+  array(1) {
+    ["value"]=>
+    string(1) "1"
+  }
+}
+done!
+
index ee0f12358d0ba92a5da8bc400e41da69ebf43f98..f3d0fa631319827ad25412793b89286d17c6d32a 100644 (file)
@@ -26,6 +26,7 @@ if (!extension_loaded('mysqli') && !extension_loaded('mysqlnd')) {
                "MYSQL_ATTR_SSL_CAPATH"                                         => true,
                "MYSQL_ATTR_SSL_CIPHER"                                         => true,
                "MYSQL_ATTR_COMPRESS"                                           => true,
+               "MYSQL_ATTR_MULTI_STATEMENTS"                                   => true,
        );
 
        if (!MySQLPDOTest::isPDOMySQLnd()) {
diff --git a/ext/pdo_mysql/tests/pdo_mysql_multi_stmt_nextrowset.phpt b/ext/pdo_mysql/tests/pdo_mysql_multi_stmt_nextrowset.phpt
new file mode 100644 (file)
index 0000000..f327aa4
--- /dev/null
@@ -0,0 +1,261 @@
+--TEST--
+MySQL PDOStatement->nextRowSet() with PDO::MYSQL_ATTR_MULTI_STATEMENTS either true or false
+--SKIPIF--
+<?php
+require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
+require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
+MySQLPDOTest::skip();
+$db = MySQLPDOTest::factory();
+$row = $db->query('SELECT VERSION() as _version')->fetch(PDO::FETCH_ASSOC);
+$matches = array();
+if (!preg_match('/^(\d+)\.(\d+)\.(\d+)/ismU', $row['_version'], $matches))
+       die(sprintf("skip Cannot determine MySQL Server version\n"));
+
+$version = $matches[0] * 10000 + $matches[1] * 100 + $matches[2];
+if ($version < 50000)
+       die(sprintf("skip Need MySQL Server 5.0.0+, found %d.%02d.%02d (%d)\n",
+               $matches[0], $matches[1], $matches[2], $version));
+
+if (!MySQLPDOTest::isPDOMySQLnd())
+       die("skip This will not work with libmysql");
+?>
+--FILE--
+<?php
+       require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
+       $db = MySQLPDOTest::factory();
+       $db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
+
+       MySQLPDOTest::createTestTable($db);
+
+       function test_proc($db) {
+
+               $db->exec('DROP PROCEDURE IF EXISTS p');
+               $db->exec('CREATE PROCEDURE p() BEGIN SELECT id FROM test ORDER BY id ASC LIMIT 3; SELECT id, label FROM test WHERE id < 4 ORDER BY id DESC LIMIT 3; END;');
+               $stmt = $db->query('CALL p()');
+               do {
+                       var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
+               } while ($stmt->nextRowSet());
+               var_dump($stmt->nextRowSet());
+
+       }
+
+       try {
+
+               // Using native PS for proc, since emulated fails.
+               printf("Native PS...\n");
+               foreach (array(false, true) as $multi) {
+                       $value = $multi ? 'true' : 'false';
+                       echo "\nTesting with PDO::MYSQL_ATTR_MULTI_STATEMENTS set to {$value}\n";
+                       $dsn = MySQLPDOTest::getDSN();
+                       $user = PDO_MYSQL_TEST_USER;
+                       $pass = PDO_MYSQL_TEST_PASS;
+                       $db = new PDO($dsn, $user, $pass, array(PDO::MYSQL_ATTR_MULTI_STATEMENTS => $multi));
+                       $db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
+                       $db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, 1);
+                       $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0);
+                       test_proc($db);
+
+                       $db = new PDO($dsn, $user, $pass, array(PDO::MYSQL_ATTR_MULTI_STATEMENTS => $multi));
+                       $db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
+                       $db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, 0);
+                       $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0);
+
+                       test_proc($db);
+
+                       // Switch back to emulated prepares to verify multi statement attribute.
+                       $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1);
+                       // This will fail when $multi is false.
+                       $stmt = $db->query("SELECT * FROM test; INSERT INTO test (id, label) VALUES (99, 'x')");
+                       if ($stmt !== false) {
+                               $stmt->closeCursor();
+                       }
+                       $info = $db->errorInfo();
+                       var_dump($info[0]);
+               }
+               @$db->exec('DROP PROCEDURE IF EXISTS p');
+
+       } catch (PDOException $e) {
+               printf("[001] %s [%s] %s\n",
+                       $e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
+       }
+
+       print "done!";
+?>
+--CLEAN--
+<?php
+require dirname(__FILE__) . '/mysql_pdo_test.inc';
+MySQLPDOTest::dropTestTable();
+?>
+--EXPECTF--
+Native PS...
+
+Testing with PDO::MYSQL_ATTR_MULTI_STATEMENTS set to false
+array(3) {
+  [0]=>
+  array(1) {
+    ["id"]=>
+    string(1) "1"
+  }
+  [1]=>
+  array(1) {
+    ["id"]=>
+    string(1) "2"
+  }
+  [2]=>
+  array(1) {
+    ["id"]=>
+    string(1) "3"
+  }
+}
+array(3) {
+  [0]=>
+  array(2) {
+    ["id"]=>
+    string(1) "3"
+    ["label"]=>
+    string(1) "c"
+  }
+  [1]=>
+  array(2) {
+    ["id"]=>
+    string(1) "2"
+    ["label"]=>
+    string(1) "b"
+  }
+  [2]=>
+  array(2) {
+    ["id"]=>
+    string(1) "1"
+    ["label"]=>
+    string(1) "a"
+  }
+}
+bool(false)
+array(3) {
+  [0]=>
+  array(1) {
+    ["id"]=>
+    string(1) "1"
+  }
+  [1]=>
+  array(1) {
+    ["id"]=>
+    string(1) "2"
+  }
+  [2]=>
+  array(1) {
+    ["id"]=>
+    string(1) "3"
+  }
+}
+array(3) {
+  [0]=>
+  array(2) {
+    ["id"]=>
+    string(1) "3"
+    ["label"]=>
+    string(1) "c"
+  }
+  [1]=>
+  array(2) {
+    ["id"]=>
+    string(1) "2"
+    ["label"]=>
+    string(1) "b"
+  }
+  [2]=>
+  array(2) {
+    ["id"]=>
+    string(1) "1"
+    ["label"]=>
+    string(1) "a"
+  }
+}
+bool(false)
+string(5) "42000"
+
+Testing with PDO::MYSQL_ATTR_MULTI_STATEMENTS set to true
+array(3) {
+  [0]=>
+  array(1) {
+    ["id"]=>
+    string(1) "1"
+  }
+  [1]=>
+  array(1) {
+    ["id"]=>
+    string(1) "2"
+  }
+  [2]=>
+  array(1) {
+    ["id"]=>
+    string(1) "3"
+  }
+}
+array(3) {
+  [0]=>
+  array(2) {
+    ["id"]=>
+    string(1) "3"
+    ["label"]=>
+    string(1) "c"
+  }
+  [1]=>
+  array(2) {
+    ["id"]=>
+    string(1) "2"
+    ["label"]=>
+    string(1) "b"
+  }
+  [2]=>
+  array(2) {
+    ["id"]=>
+    string(1) "1"
+    ["label"]=>
+    string(1) "a"
+  }
+}
+bool(false)
+array(3) {
+  [0]=>
+  array(1) {
+    ["id"]=>
+    string(1) "1"
+  }
+  [1]=>
+  array(1) {
+    ["id"]=>
+    string(1) "2"
+  }
+  [2]=>
+  array(1) {
+    ["id"]=>
+    string(1) "3"
+  }
+}
+array(3) {
+  [0]=>
+  array(2) {
+    ["id"]=>
+    string(1) "3"
+    ["label"]=>
+    string(1) "c"
+  }
+  [1]=>
+  array(2) {
+    ["id"]=>
+    string(1) "2"
+    ["label"]=>
+    string(1) "b"
+  }
+  [2]=>
+  array(2) {
+    ["id"]=>
+    string(1) "1"
+    ["label"]=>
+    string(1) "a"
+  }
+}
+bool(false)
+string(5) "00000"
+done!