summaryrefslogtreecommitdiff
path: root/ext/pdo_mysql
diff options
context:
space:
mode:
authorAnatol Belski <ab@php.net>2014-12-06 21:37:15 +0100
committerAnatol Belski <ab@php.net>2014-12-06 21:37:15 +0100
commitba35b22bc4a7af791ff2ab7c2ca8e9f4aa6d64df (patch)
tree92d7a7d9dd424b53e50a194af06ec3cfb514633e /ext/pdo_mysql
parent88bb9fedc4b5fc750524a7b00be1d46fde2f5929 (diff)
parentaa52fcf179d9e233075e4d213d5708cc5b5e1ae2 (diff)
downloadphp-git-ba35b22bc4a7af791ff2ab7c2ca8e9f4aa6d64df.tar.gz
Merge remote-tracking branch 'origin/master' into native-tls
* origin/master: (35 commits) Fixed bug #68398 msooxml matches too many archives Fix zpp call in apache_getenv() Drop unnecessary zval containers fixed test C89 compat add include for missing localeconv_r proto updated NEWS Fixed bug #65230 setting locale randomly broken Fix compilation error (ref #68424) Removed useless handlers Move checks for references into slow paths of operator functions. Remove duplicate opcode handlers. Revert unintentional docblock change Restored zip/oci8 PHP 4 code, add PHP 7 checks Note macro removal in UPGRADING.INTERNALS Removed ZEND_ENGINE_2 checks (and ZE1 code, it's been a decade!) Zend Engine 3 Updated NEWS Updated NEWS Updated NEWS Start adding new attribute to control multi statements ...
Diffstat (limited to 'ext/pdo_mysql')
-rw-r--r--ext/pdo_mysql/mysql_driver.c13
-rw-r--r--ext/pdo_mysql/pdo_mysql.c2
-rw-r--r--ext/pdo_mysql/php_pdo_mysql_int.h3
-rw-r--r--ext/pdo_mysql/tests/pdo_mysql_attr_multi_statements.phpt95
-rw-r--r--ext/pdo_mysql/tests/pdo_mysql_class_constants.phpt1
-rw-r--r--ext/pdo_mysql/tests/pdo_mysql_multi_stmt_nextrowset.phpt261
6 files changed, 369 insertions, 6 deletions
diff --git a/ext/pdo_mysql/mysql_driver.c b/ext/pdo_mysql/mysql_driver.c
index 7e4945a7b8..73889af5ea 100644
--- a/ext/pdo_mysql/mysql_driver.c
+++ b/ext/pdo_mysql/mysql_driver.c
@@ -556,15 +556,20 @@ 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
-#endif
;
-
#if defined(PDO_USE_MYSQLND)
int dbname_len = 0;
int password_len = 0;
#endif
+
+#ifdef 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
+
PDO_DBG_ENTER("pdo_mysql_handle_factory");
PDO_DBG_INF_FMT("dbh=%p", dbh);
#ifdef CLIENT_MULTI_RESULTS
diff --git a/ext/pdo_mysql/pdo_mysql.c b/ext/pdo_mysql/pdo_mysql.c
index 82dbdbc83a..0e997b1dc7 100644
--- a/ext/pdo_mysql/pdo_mysql.c
+++ b/ext/pdo_mysql/pdo_mysql.c
@@ -129,7 +129,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", (zend_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);
diff --git a/ext/pdo_mysql/php_pdo_mysql_int.h b/ext/pdo_mysql/php_pdo_mysql_int.h
index accac8a25e..9493fda6f8 100644
--- a/ext/pdo_mysql/php_pdo_mysql_int.h
+++ b/ext/pdo_mysql/php_pdo_mysql_int.h
@@ -175,8 +175,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
index 0000000000..312deddb81
--- /dev/null
+++ b/ext/pdo_mysql/tests/pdo_mysql_attr_multi_statements.phpt
@@ -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!
+
diff --git a/ext/pdo_mysql/tests/pdo_mysql_class_constants.phpt b/ext/pdo_mysql/tests/pdo_mysql_class_constants.phpt
index ee0f12358d..f3d0fa6313 100644
--- a/ext/pdo_mysql/tests/pdo_mysql_class_constants.phpt
+++ b/ext/pdo_mysql/tests/pdo_mysql_class_constants.phpt
@@ -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
index 0000000000..f327aa4089
--- /dev/null
+++ b/ext/pdo_mysql/tests/pdo_mysql_multi_stmt_nextrowset.phpt
@@ -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!