summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/mysql/php_mysql.c10
-rw-r--r--ext/mysqli/mysqli.c1
-rw-r--r--ext/mysqli/mysqli_api.c16
-rw-r--r--ext/mysqli/mysqli_fe.c15
-rw-r--r--ext/mysqli/mysqli_nonapi.c15
-rw-r--r--ext/mysqli/mysqli_priv.h2
-rw-r--r--ext/mysqli/tests/bug66043.phpt4
-rw-r--r--ext/mysqli/tests/bug66762.phpt5
-rw-r--r--ext/mysqli/tests/mysqli_begin_transaction.phpt140
-rw-r--r--ext/mysqli/tests/mysqli_change_user.phpt92
-rw-r--r--ext/mysqli/tests/mysqli_change_user_new.phpt44
-rw-r--r--ext/mysqli/tests/mysqli_change_user_old.phpt39
-rw-r--r--ext/mysqli/tests/mysqli_change_user_oo.phpt3
-rw-r--r--ext/mysqli/tests/mysqli_class_mysqli_reflection.phpt9
-rw-r--r--ext/mysqli/tests/mysqli_constants.phpt4
-rw-r--r--ext/mysqli/tests/mysqli_fetch_all.phpt20
-rw-r--r--ext/mysqli/tests/mysqli_fetch_lengths.phpt6
-rw-r--r--ext/mysqli/tests/mysqli_poll.phpt31
-rw-r--r--ext/mysqli/tests/mysqli_poll_kill.phpt27
-rw-r--r--ext/mysqli/tests/mysqli_poll_mixing_insert_select.phpt6
-rw-r--r--ext/mysqli/tests/mysqli_reap_async_query.phpt97
-rw-r--r--ext/mysqli/tests/mysqli_release_savepoint.phpt84
-rw-r--r--ext/mysqli/tests/mysqli_report.phpt5
-rw-r--r--ext/mysqli/tests/mysqli_report_new.phpt50
-rw-r--r--ext/mysqli/tests/mysqli_report_wo_ps.phpt9
-rw-r--r--ext/mysqli/tests/mysqli_savepoint.phpt72
-rw-r--r--ext/mysqli/tests/mysqli_stmt_get_warnings.phpt31
-rw-r--r--ext/mysqli/tests/mysqli_store_result_buffered_c.phpt42
-rw-r--r--ext/mysqli/tests/mysqli_store_result_copy.phpt285
-rw-r--r--ext/mysqlnd/mysqlnd.c61
-rw-r--r--ext/mysqlnd/mysqlnd.h8
-rw-r--r--ext/mysqlnd/mysqlnd_enum_n_def.h10
-rw-r--r--ext/mysqlnd/mysqlnd_ext_plugin.c16
-rw-r--r--ext/mysqlnd/mysqlnd_ext_plugin.h6
-rw-r--r--ext/mysqlnd/mysqlnd_ps.c171
-rw-r--r--ext/mysqlnd/mysqlnd_result.c594
-rw-r--r--ext/mysqlnd/mysqlnd_result.h3
-rw-r--r--ext/mysqlnd/mysqlnd_reverse_api.c5
-rw-r--r--ext/mysqlnd/mysqlnd_reverse_api.h3
-rw-r--r--ext/mysqlnd/mysqlnd_structs.h84
-rw-r--r--ext/mysqlnd/mysqlnd_wireprotocol.c48
-rw-r--r--ext/mysqlnd/mysqlnd_wireprotocol.h6
-rw-r--r--ext/mysqlnd/php_mysqlnd.c7
-rw-r--r--ext/pdo_mysql/mysql_driver.c4
44 files changed, 1810 insertions, 380 deletions
diff --git a/ext/mysql/php_mysql.c b/ext/mysql/php_mysql.c
index 3d092b2d6a..ff4de0f5a8 100644
--- a/ext/mysql/php_mysql.c
+++ b/ext/mysql/php_mysql.c
@@ -877,7 +877,7 @@ static void php_mysql_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
#ifndef MYSQL_USE_MYSQLND
mysql->conn = mysql_init(NULL);
#else
- mysql->conn = mysql_init(persistent);
+ mysql->conn = mysqlnd_init(MYSQLND_CLIENT_KNOWS_RSET_COPY_DATA, persistent);
#endif
if (connect_timeout != -1) {
@@ -886,7 +886,7 @@ static void php_mysql_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
#ifndef MYSQL_USE_MYSQLND
if (mysql_real_connect(mysql->conn, host, user, passwd, NULL, port, socket, client_flags)==NULL)
#else
- if (mysqlnd_connect(mysql->conn, host, user, passwd, passwd_len, NULL, 0, port, socket, client_flags TSRMLS_CC) == NULL)
+ if (mysqlnd_connect(mysql->conn, host, user, passwd, passwd_len, NULL, 0, port, socket, client_flags, MYSQLND_CLIENT_KNOWS_RSET_COPY_DATA TSRMLS_CC) == NULL)
#endif
{
/* Populate connect error globals so that the error functions can read them */
@@ -934,7 +934,7 @@ static void php_mysql_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
#ifndef MYSQL_USE_MYSQLND
if (mysql_real_connect(mysql->conn, host, user, passwd, NULL, port, socket, client_flags)==NULL)
#else
- if (mysqlnd_connect(mysql->conn, host, user, passwd, passwd_len, NULL, 0, port, socket, client_flags TSRMLS_CC) == NULL)
+ if (mysqlnd_connect(mysql->conn, host, user, passwd, passwd_len, NULL, 0, port, socket, client_flags, MYSQLND_CLIENT_KNOWS_RSET_COPY_DATA TSRMLS_CC) == NULL)
#endif
{
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Link to server lost, unable to reconnect");
@@ -996,7 +996,7 @@ static void php_mysql_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
#ifndef MYSQL_USE_MYSQLND
mysql->conn = mysql_init(NULL);
#else
- mysql->conn = mysql_init(persistent);
+ mysql->conn = mysqlnd_init(MYSQLND_CLIENT_KNOWS_RSET_COPY_DATA, persistent);
#endif
if (!mysql->conn) {
MySG(connect_error) = estrdup("OOM");
@@ -1013,7 +1013,7 @@ static void php_mysql_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
#ifndef MYSQL_USE_MYSQLND
if (mysql_real_connect(mysql->conn, host, user, passwd, NULL, port, socket, client_flags)==NULL)
#else
- if (mysqlnd_connect(mysql->conn, host, user, passwd, passwd_len, NULL, 0, port, socket, client_flags TSRMLS_CC) == NULL)
+ if (mysqlnd_connect(mysql->conn, host, user, passwd, passwd_len, NULL, 0, port, socket, client_flags, MYSQLND_CLIENT_KNOWS_RSET_COPY_DATA TSRMLS_CC) == NULL)
#endif
{
/* Populate connect error globals so that the error functions can read them */
diff --git a/ext/mysqli/mysqli.c b/ext/mysqli/mysqli.c
index 0cea68a33f..120c194964 100644
--- a/ext/mysqli/mysqli.c
+++ b/ext/mysqli/mysqli.c
@@ -721,6 +721,7 @@ PHP_MINIT_FUNCTION(mysqli)
REGISTER_LONG_CONSTANT("MYSQLI_USE_RESULT", MYSQLI_USE_RESULT, CONST_CS | CONST_PERSISTENT);
#if defined (MYSQLI_USE_MYSQLND)
REGISTER_LONG_CONSTANT("MYSQLI_ASYNC", MYSQLI_ASYNC, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("MYSQLI_STORE_RESULT_COPY_DATA", MYSQLI_STORE_RESULT_COPY_DATA, CONST_CS | CONST_PERSISTENT);
#endif
/* for mysqli_fetch_assoc */
diff --git a/ext/mysqli/mysqli_api.c b/ext/mysqli/mysqli_api.c
index 53639a0670..d14625e0f7 100644
--- a/ext/mysqli/mysqli_api.c
+++ b/ext/mysqli/mysqli_api.c
@@ -1477,7 +1477,7 @@ void php_mysqli_init(INTERNAL_FUNCTION_PARAMETERS)
We create always persistent, as if the user want to connecto
to p:somehost, we can't convert the handle then
*/
- if (!(mysql->mysql = mysql_init(TRUE)))
+ if (!(mysql->mysql = mysqlnd_init(MYSQLND_CLIENT_KNOWS_RSET_COPY_DATA, TRUE)))
#endif
{
efree(mysql);
@@ -2557,7 +2557,7 @@ PHP_FUNCTION(mysqli_stmt_sqlstate)
}
/* }}} */
-/* {{{ proto object mysqli_store_result(object link)
+/* {{{ proto object mysqli_store_result(object link [, flags])
Buffer result set on client */
PHP_FUNCTION(mysqli_store_result)
{
@@ -2565,13 +2565,19 @@ PHP_FUNCTION(mysqli_store_result)
MYSQL_RES *result;
zval *mysql_link;
MYSQLI_RESOURCE *mysqli_resource;
+ long flags = 0;
- if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O|l", &mysql_link, mysqli_link_class_entry, &flags) == FAILURE) {
return;
}
MYSQLI_FETCH_RESOURCE_CONN(mysql, &mysql_link, MYSQLI_STATUS_VALID);
-
- if (!(result = mysql_store_result(mysql->mysql))) {
+#if MYSQLI_USE_MYSQLND
+ result = flags & MYSQLI_STORE_RESULT_COPY_DATA? mysqlnd_store_result_ofs(mysql->mysql) : mysqlnd_store_result(mysql->mysql);
+#else
+ result = mysql_store_result(mysql->mysql);
+#endif
+ if (!result) {
MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
RETURN_FALSE;
}
diff --git a/ext/mysqli/mysqli_fe.c b/ext/mysqli/mysqli_fe.c
index 3d31b8183c..e099fe7194 100644
--- a/ext/mysqli/mysqli_fe.c
+++ b/ext/mysqli/mysqli_fe.c
@@ -142,6 +142,17 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_mysqli_rollback, 0, 0, 0)
ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqli_store_result, 0, 0, 1)
+ MYSQLI_ZEND_ARG_OBJ_INFO_LINK()
+ ZEND_ARG_INFO(0, flags)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_store_result, 0, 0, 0)
+ ZEND_ARG_INFO(0, flags)
+ZEND_END_ARG_INFO()
+
+
ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqli_change_user, 0, 0, 4)
MYSQLI_ZEND_ARG_OBJ_INFO_LINK()
ZEND_ARG_INFO(0, user)
@@ -498,7 +509,7 @@ const zend_function_entry mysqli_functions[] = {
PHP_FE(mysqli_sqlstate, arginfo_mysqli_only_link)
PHP_FE(mysqli_ssl_set, arginfo_mysqli_ssl_set)
PHP_FE(mysqli_stat, arginfo_mysqli_only_link)
- PHP_FE(mysqli_store_result, arginfo_mysqli_only_link)
+ PHP_FE(mysqli_store_result, arginfo_mysqli_store_result)
PHP_FE(mysqli_thread_id, arginfo_mysqli_only_link)
PHP_FE(mysqli_thread_safe, arginfo_mysqli_no_params)
PHP_FE(mysqli_use_result, arginfo_mysqli_only_link)
@@ -568,7 +579,7 @@ const zend_function_entry mysqli_link_methods[] = {
PHP_FALIAS(ssl_set, mysqli_ssl_set, arginfo_class_mysqli_ssl_set)
PHP_FALIAS(stat, mysqli_stat, arginfo_mysqli_no_params)
PHP_FALIAS(stmt_init, mysqli_stmt_init, arginfo_mysqli_no_params)
- PHP_FALIAS(store_result, mysqli_store_result, arginfo_mysqli_no_params)
+ PHP_FALIAS(store_result, mysqli_store_result, arginfo_class_store_result)
PHP_FALIAS(thread_safe, mysqli_thread_safe, arginfo_mysqli_no_params)
PHP_FALIAS(use_result, mysqli_use_result, arginfo_mysqli_no_params)
PHP_FALIAS(refresh,mysqli_refresh, arginfo_class_mysqli_refresh)
diff --git a/ext/mysqli/mysqli_nonapi.c b/ext/mysqli/mysqli_nonapi.c
index 312f2806ce..25a88c0984 100644
--- a/ext/mysqli/mysqli_nonapi.c
+++ b/ext/mysqli/mysqli_nonapi.c
@@ -217,7 +217,7 @@ void mysqli_common_connect(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_real_conne
#if !defined(MYSQLI_USE_MYSQLND)
if (!(mysql->mysql = mysql_init(NULL))) {
#else
- if (!(mysql->mysql = mysqlnd_init(persistent))) {
+ if (!(mysql->mysql = mysqlnd_init(MYSQLND_CLIENT_KNOWS_RSET_COPY_DATA, persistent))) {
#endif
goto err;
}
@@ -240,7 +240,7 @@ void mysqli_common_connect(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_real_conne
if (mysql_real_connect(mysql->mysql, hostname, username, passwd, dbname, port, socket, flags) == NULL)
#else
if (mysqlnd_connect(mysql->mysql, hostname, username, passwd, passwd_len, dbname, dbname_len,
- port, socket, flags TSRMLS_CC) == NULL)
+ port, socket, flags, MYSQLND_CLIENT_KNOWS_RSET_COPY_DATA TSRMLS_CC) == NULL)
#endif
{
/* Save error messages - for mysqli_connect_error() & mysqli_connect_errno() */
@@ -575,7 +575,7 @@ PHP_FUNCTION(mysqli_query)
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty query");
RETURN_FALSE;
}
- if ((resultmode & ~MYSQLI_ASYNC) != MYSQLI_USE_RESULT && (resultmode & ~MYSQLI_ASYNC) != MYSQLI_STORE_RESULT) {
+ if ((resultmode & ~MYSQLI_ASYNC) != MYSQLI_USE_RESULT && (resultmode & ~(MYSQLI_ASYNC | MYSQLI_STORE_RESULT_COPY_DATA)) != MYSQLI_STORE_RESULT) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid value for resultmode");
RETURN_FALSE;
}
@@ -609,9 +609,14 @@ PHP_FUNCTION(mysqli_query)
RETURN_TRUE;
}
- switch (resultmode) {
+ switch (resultmode & ~(MYSQLI_ASYNC | MYSQLI_STORE_RESULT_COPY_DATA)) {
case MYSQLI_STORE_RESULT:
- result = mysql_store_result(mysql->mysql);
+#ifdef MYSQLI_USE_MYSQLND
+ if (resultmode & MYSQLI_STORE_RESULT_COPY_DATA) {
+ result = mysqlnd_store_result_ofs(mysql->mysql);
+ } else
+#endif
+ result = mysql_store_result(mysql->mysql);
break;
case MYSQLI_USE_RESULT:
result = mysql_use_result(mysql->mysql);
diff --git a/ext/mysqli/mysqli_priv.h b/ext/mysqli/mysqli_priv.h
index 190572b689..e28caebf92 100644
--- a/ext/mysqli/mysqli_priv.h
+++ b/ext/mysqli/mysqli_priv.h
@@ -114,9 +114,11 @@ PHP_MYSQLI_EXPORT(zend_object_value) mysqli_objects_new(zend_class_entry * TSRML
#define MYSQLI_USE_RESULT 1
#ifdef MYSQLI_USE_MYSQLND
#define MYSQLI_ASYNC 8
+#define MYSQLI_STORE_RESULT_COPY_DATA 16
#else
/* libmysql */
#define MYSQLI_ASYNC 0
+#define MYSQLI_STORE_RESULT_OFS 0
#endif
/* for mysqli_fetch_assoc */
diff --git a/ext/mysqli/tests/bug66043.phpt b/ext/mysqli/tests/bug66043.phpt
index d0e8b1c3d3..52e42b6177 100644
--- a/ext/mysqli/tests/bug66043.phpt
+++ b/ext/mysqli/tests/bug66043.phpt
@@ -12,7 +12,9 @@ require_once('skipifconnectfailure.inc');
--FILE--
<?php
require 'connect.inc';
-$db = new mysqli($host, $user, $passwd, 'mysql');
+if (!$db = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket)) {
+ printf("[001] Connect failed, [%d] %s\n", mysqli_connect_errno(), mysqli_connect_error());
+}
$stmt = $db->stmt_init();
$stmt->prepare("SELECT User FROM user WHERE password=\"\"");
diff --git a/ext/mysqli/tests/bug66762.phpt b/ext/mysqli/tests/bug66762.phpt
index 2b8a92c7fd..cf1309e5a2 100644
--- a/ext/mysqli/tests/bug66762.phpt
+++ b/ext/mysqli/tests/bug66762.phpt
@@ -9,7 +9,9 @@ require_once('skipifconnectfailure.inc');
<?php
require_once("connect.inc");
- $mysqli = new mysqli($host, $user, $passwd, $db);
+ if (!$mysqli = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket)) {
+ printf("[001] Connect failed, [%d] %s\n", mysqli_connect_errno(), mysqli_connect_error());
+ }
$read_stmt = $mysqli->prepare("SELECT 1");
@@ -17,7 +19,6 @@ require_once('skipifconnectfailure.inc');
unset($mysqli);
var_dump($read_stmt->bind_result($data));
-
?>
done!
--EXPECT--
diff --git a/ext/mysqli/tests/mysqli_begin_transaction.phpt b/ext/mysqli/tests/mysqli_begin_transaction.phpt
new file mode 100644
index 0000000000..7e708316b4
--- /dev/null
+++ b/ext/mysqli/tests/mysqli_begin_transaction.phpt
@@ -0,0 +1,140 @@
+--TEST--
+mysqli_begin_transaction()
+--SKIPIF--
+<?php
+require_once('skipif.inc');
+require_once('skipifemb.inc');
+require_once('skipifconnectfailure.inc');
+
+require_once('connect.inc');
+if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
+ die(sprintf("Cannot connect, [%d] %s", mysqli_connect_errno(), mysqli_connect_error()));
+
+if (!have_innodb($link))
+ die(sprintf("Needs InnoDB support, [%d] %s", $link->errno, $link->error));
+?>
+--FILE--
+<?php
+ require_once("connect.inc");
+ /* {{{ proto bool mysqli_begin_transaction(object link, [int flags [, string name]]) */
+ $tmp = NULL;
+ $link = NULL;
+
+ if (!is_null($tmp = @mysqli_begin_transaction()))
+ printf("[001] Expecting NULL, got %s/%s\n", gettype($tmp), $tmp);
+
+ if (!is_null($tmp = @mysqli_begin_transaction($link)))
+ printf("[002] Expecting NULL, got %s/%s\n", gettype($tmp), $tmp);
+
+ if (!is_null($tmp = @mysqli_begin_transaction($link, $link)))
+ printf("[003] Expecting NULL, got %s/%s\n", gettype($tmp), $tmp);
+
+ if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
+ printf("[004] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
+ $host, $user, $db, $port, $socket);
+
+ if (!is_null($tmp = @mysqli_begin_transaction($link, $link)))
+ printf("[005] Expecting NULL, got %s/%s\n", gettype($tmp), $tmp);
+
+ if (!is_null($tmp = @mysqli_begin_transaction($link, 0, $link)))
+ printf("[006] Expecting NULL, got %s/%s\n", gettype($tmp), $tmp);
+
+ if (!is_null($tmp = @mysqli_begin_transaction($link, 0, "mytrx", $link)))
+ printf("[007] Expecting NULL, got %s/%s\n", gettype($tmp), $tmp);
+
+ if (!mysqli_query($link, 'DROP TABLE IF EXISTS test'))
+ printf("[008] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+ if (!mysqli_query($link, 'CREATE TABLE test(id INT) ENGINE = InnoDB'))
+ printf("[009] Cannot create test table, [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+ if (true !== ($tmp = mysqli_autocommit($link, true)))
+ printf("[010] Cannot turn on autocommit, expecting true, got %s/%s\n", gettype($tmp), $tmp);
+
+ /* overrule autocommit */
+ if (true !== ($tmp = mysqli_begin_transaction($link)))
+ printf("[011] Got %s - [%d] %s\n", var_dump($tmp, true), mysqli_errno($link), mysqli_error($link));
+
+ if (!mysqli_query($link, 'INSERT INTO test(id) VALUES (1)'))
+ printf("[012] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+ $tmp = mysqli_rollback($link);
+ if ($tmp !== true)
+ printf("[013] Expecting boolean/true, got %s/%s\n", gettype($tmp), $tmp);
+
+ /* empty */
+ $res = mysqli_query($link, "SELECT * FROM test");
+ var_dump($res->fetch_assoc());
+
+ /* valid flags */
+ $flags = array(
+ MYSQLI_TRANS_START_WITH_CONSISTENT_SNAPSHOT,
+ MYSQLI_TRANS_START_READ_WRITE,
+ MYSQLI_TRANS_START_READ_ONLY,
+ MYSQLI_TRANS_COR_AND_CHAIN,
+ MYSQLI_TRANS_COR_AND_NO_CHAIN,
+ MYSQLI_TRANS_COR_RELEASE,
+ MYSQLI_TRANS_COR_NO_RELEASE);
+
+ /* just coverage */
+ foreach ($flags as $flag) {
+ if (!mysqli_begin_transaction($link, $flag, sprintf("flag %d", $flag))) {
+ printf("[014] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+ }
+ if (!mysqli_query($link, 'SELECT * FROM test') ||
+ !mysqli_rollback($link)) {
+ printf("[015] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+ }
+ }
+
+ /* does it really set a flag? */
+ if (mysqli_get_server_version($link) >= 50600) {
+ if (!mysqli_begin_transaction($link, MYSQLI_TRANS_START_READ_ONLY, sprintf("flag %d", $flag))) {
+ printf("[016] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+ }
+ if (!mysqli_query($link, "INSERT INTO test(id) VALUES (2)") ||
+ !mysqli_commit($link)) {
+ printf("[017] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+ } else {
+ $res = mysqli_query($link, "SELECT id FROM test WHERE id = 2");
+ var_dump($res->fetch_assoc());
+ }
+ }
+
+ /* invalid flag */
+ do {
+ $invalid_flag = mt_rand(0, 10000);
+ } while (isset(array_flip($flags)[$invalid_flag]));
+ /* we may or may not hit an invalid combination provoking a SQL error */
+ if (!mysqli_begin_transaction($link, $invalid_flag, sprintf("flag %d", $invalid_flag))) {
+ printf("[018] invalid_flag = %d [%d] %s\n", $invalid_flag, mysqli_errno($link), mysqli_error($link));
+ } else {
+ printf("[018] invalid_flag = %d [%d] %s\n", $invalid_flag, mysqli_errno($link), mysqli_error($link));
+ }
+ if (!mysqli_begin_transaction($link, -1)) {
+ printf("[019] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+ }
+
+ /* does it like stupid names? */
+ if (!$link->begin_transaction(MYSQLI_TRANS_START_READ_WRITE, "*/trick me?\n\0"))
+ printf("[020] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+ /* does it like stupid names? */
+ if (!$link->begin_transaction(MYSQLI_TRANS_START_READ_WRITE, "az09"))
+ printf("[021] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+ print "done!";
+?>
+--CLEAN--
+<?php
+ require_once("clean_table.inc");
+?>
+--EXPECTF--
+NULL
+[017] [1792] %s
+[018] invalid_flag = %d [%d]%A
+
+Warning: mysqli_begin_transaction(): Invalid value for parameter flags (-1) in %s on line %d
+[019] [%d]%A
+[020] [%d]%A
+done! \ No newline at end of file
diff --git a/ext/mysqli/tests/mysqli_change_user.phpt b/ext/mysqli/tests/mysqli_change_user.phpt
index bfea423c9e..7a4530f0d5 100644
--- a/ext/mysqli/tests/mysqli_change_user.phpt
+++ b/ext/mysqli/tests/mysqli_change_user.phpt
@@ -32,79 +32,91 @@ require_once('skipifconnectfailure.inc');
printf("[006] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
$host, $user, $db, $port, $socket);
- if (false !== ($tmp = mysqli_change_user($link, $user . '_unknown_really', $passwd . 'non_empty', $db)))
+ if (false !== ($tmp = @mysqli_change_user($link, $user . '_unknown_really', $passwd . 'non_empty', $db)))
printf("[007] Expecting false, got %s/%s\n", gettype($tmp), $tmp);
- if (false !== ($tmp = mysqli_change_user($link, $user, $passwd . '_unknown_really', $db)))
- printf("[008] Expecting false, got %s/%s\n", gettype($tmp), $tmp);
+ if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
+ printf("[008] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
+ $host, $user, $db, $port, $socket);
- if (false !== ($tmp = mysqli_change_user($link, $user, $passwd, $db . '_unknown_really')))
+ if (false !== ($tmp = @mysqli_change_user($link, $user, $passwd . '_unknown_really', $db)))
printf("[009] Expecting false, got %s/%s\n", gettype($tmp), $tmp);
- if (!mysqli_query($link, 'SET @mysqli_change_user_test_var=1'))
- printf("[010] Failed to set test variable: [%d] %s\n", mysqli_errno($link), mysqli_error($link));
-
- if (!$res = mysqli_query($link, 'SELECT @mysqli_change_user_test_var AS test_var'))
- printf("[011] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
- $tmp = mysqli_fetch_assoc($res);
- mysqli_free_result($res);
- if (1 != $tmp['test_var'])
- printf("[012] Cannot set test variable\n");
-
- if (true !== ($tmp = mysqli_change_user($link, $user, $passwd, $db)))
- printf("[013] Expecting true, got %s/%s\n", gettype($tmp), $tmp);
-
- if (!$res = mysqli_query($link, 'SELECT database() AS dbname, user() AS user'))
- printf("[014] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
- $tmp = mysqli_fetch_assoc($res);
- mysqli_free_result($res);
-
- if (substr($tmp['user'], 0, strlen($user)) !== $user)
- printf("[015] Expecting user %s, got user() %s\n", $user, $tmp['user']);
- if ($tmp['dbname'] != $db)
- printf("[016] Expecting database %s, got database() %s\n", $db, $tmp['dbname']);
+ if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
+ printf("[010] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
+ $host, $user, $db, $port, $socket);
- if (!$res = mysqli_query($link, 'SELECT @mysqli_change_user_test_var AS test_var'))
- printf("[017] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
- $tmp = mysqli_fetch_assoc($res);
- mysqli_free_result($res);
- if (NULL !== $tmp['test_var'])
- printf("[019] Test variable is still set!\n");
+ if (false !== ($tmp = @mysqli_change_user($link, $user, $passwd, $db . '_unknown_really')))
+ printf("[011] Expecting false, got %s/%s\n", gettype($tmp), $tmp);
mysqli_close($link);
if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket)) {
- printf("[020] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
+ printf("[012] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
$host, $user, $db, $port, $socket);
}
- if (false !== ($tmp = mysqli_change_user($link, str_repeat('user', 16384), str_repeat('pass', 16384), str_repeat('dbase', 16384))))
- printf("[021] Expecting false, got %s/%s\n", gettype($tmp), $tmp);
+ if (false !== ($tmp = @mysqli_change_user($link, str_repeat('user', 16384), str_repeat('pass', 16384), str_repeat('dbase', 16384))))
+ printf("[013] Expecting false, got %s/%s\n", gettype($tmp), $tmp);
mysqli_close($link);
if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket)) {
- printf("[022] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
+ printf("[014] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
$host, $user, $db, $port, $socket);
}
/* silent protocol change if no db which requires workaround in mysqlnd/libmysql
(empty db = no db send with COM_CHANGE_USER) */
if (true !== ($tmp = mysqli_change_user($link, $user, $passwd, "")))
- printf("[023] Expecting true, got %s/%s\n", gettype($tmp), $tmp);
+ printf("[015] Expecting true, got %s/%s\n", gettype($tmp), $tmp);
if (!$res = mysqli_query($link, 'SELECT database() AS dbname, user() AS user'))
- printf("[024] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+ printf("[016] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
$tmp = mysqli_fetch_assoc($res);
mysqli_free_result($res);
if ($tmp['dbname'] != "")
- printf("[025] Expecting database '', got database() '%s'\n", $tmp['dbname']);
+ printf("[017] Expecting database '', got database() '%s'\n", $tmp['dbname']);
mysqli_close($link);
if (NULL !== ($tmp = @mysqli_change_user($link, $user, $passwd, $db)))
- printf("[026] Expecting NULL, got %s/%s\n", gettype($tmp), $tmp);
+ printf("[018] Expecting NULL, got %s/%s\n", gettype($tmp), $tmp);
+
+ if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
+ printf("[019] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
+ $host, $user, $db, $port, $socket);
+
+ if (!mysqli_query($link, 'SET @mysqli_change_user_test_var=1'))
+ printf("[020] Failed to set test variable: [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+ if (!$res = mysqli_query($link, 'SELECT @mysqli_change_user_test_var AS test_var'))
+ printf("[021] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+ $tmp = mysqli_fetch_assoc($res);
+ mysqli_free_result($res);
+ if (1 != $tmp['test_var'])
+ printf("[022] Cannot set test variable\n");
+
+ if (true !== ($tmp = mysqli_change_user($link, $user, $passwd, $db)))
+ printf("[023] Expecting true, got %s/%s\n", gettype($tmp), $tmp);
+
+ if (!$res = mysqli_query($link, 'SELECT database() AS dbname, user() AS user'))
+ printf("[024] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+ $tmp = mysqli_fetch_assoc($res);
+ mysqli_free_result($res);
+
+ if (substr($tmp['user'], 0, strlen($user)) !== $user)
+ printf("[025] Expecting user %s, got user() %s\n", $user, $tmp['user']);
+ if ($tmp['dbname'] != $db)
+ printf("[026] Expecting database %s, got database() %s\n", $db, $tmp['dbname']);
+
+ if (!$res = mysqli_query($link, 'SELECT @mysqli_change_user_test_var AS test_var'))
+ printf("[027] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+ $tmp = mysqli_fetch_assoc($res);
+ mysqli_free_result($res);
+ if (NULL !== $tmp['test_var'])
+ printf("[028] Test variable is still set!\n");
print "done!";
?>
diff --git a/ext/mysqli/tests/mysqli_change_user_new.phpt b/ext/mysqli/tests/mysqli_change_user_new.phpt
new file mode 100644
index 0000000000..a87afa84a3
--- /dev/null
+++ b/ext/mysqli/tests/mysqli_change_user_new.phpt
@@ -0,0 +1,44 @@
+--TEST--
+mysqli_change_user(), MySQL 5.6+
+--SKIPIF--
+<?php
+require_once('skipif.inc');
+require_once('skipifemb.inc');
+require_once('skipifconnectfailure.inc');
+
+if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
+ die(sprintf("SKIP Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
+ $host, $user, $db, $port, $socket));
+
+if (mysqli_get_server_version($link) < 50600)
+ die("SKIP For MySQL >= 5.6.0");
+?>
+--FILE--
+<?php
+ require_once("connect.inc");
+
+ $tmp = NULL;
+ $link = NULL;
+
+ if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
+ printf("[001] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
+ $host, $user, $db, $port, $socket);
+
+ /* Pre 5.6: link remains useable */
+ if (false !== ($tmp = @mysqli_change_user($link, $user . '_unknown_really', $passwd . 'non_empty', $db)))
+ printf("[002] Expecting false, got %s/%s\n", gettype($tmp), $tmp);
+
+ if (!$res = mysqli_query($link, 'SELECT 1 AS _one'))
+ printf("[003] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+ var_dump($res->fetch_assoc());
+
+ print "done!";
+?>
+--EXPECTF--
+Warning: mysqli_query(): MySQL server has gone away in %s on line %d
+
+Warning: mysqli_query(): Error reading result set's header in %s on line %d
+[003] [2006] MySQL server has gone away
+
+Fatal error: Call to a member function fetch_assoc() on a non-object in %s on line %d \ No newline at end of file
diff --git a/ext/mysqli/tests/mysqli_change_user_old.phpt b/ext/mysqli/tests/mysqli_change_user_old.phpt
new file mode 100644
index 0000000000..370bb344da
--- /dev/null
+++ b/ext/mysqli/tests/mysqli_change_user_old.phpt
@@ -0,0 +1,39 @@
+--TEST--
+mysqli_change_user(), MySQL < 5.6
+--SKIPIF--
+<?php
+require_once('skipif.inc');
+require_once('skipifemb.inc');
+require_once('skipifconnectfailure.inc');
+
+if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
+ die(sprintf("SKIP Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
+ $host, $user, $db, $port, $socket));
+
+if (mysqli_get_server_version($link) >= 50600)
+ die("SKIP For MySQL < 5.6.0");
+?>
+--FILE--
+<?php
+ require_once("connect.inc");
+
+ $tmp = NULL;
+ $link = NULL;
+
+ if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
+ printf("[001] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
+ $host, $user, $db, $port, $socket);
+
+ /* Pre 5.6: link remains useable */
+ if (false !== ($tmp = mysqli_change_user($link, $user . '_unknown_really', $passwd . 'non_empty', $db)))
+ printf("[011] Expecting false, got %s/%s\n", gettype($tmp), $tmp);
+
+ if (!$res = mysqli_query($link, 'SELECT 1 AS _one'))
+ printf("[012] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+ var_dump($res->fetch_assoc());
+
+ print "done!";
+?>
+--EXPECTF--
+done! \ No newline at end of file
diff --git a/ext/mysqli/tests/mysqli_change_user_oo.phpt b/ext/mysqli/tests/mysqli_change_user_oo.phpt
index 61444ae235..7ed2d08933 100644
--- a/ext/mysqli/tests/mysqli_change_user_oo.phpt
+++ b/ext/mysqli/tests/mysqli_change_user_oo.phpt
@@ -10,6 +10,9 @@ require_once('table.inc');
if (!$IS_MYSQLND && (mysqli_get_server_version($link) < 50118 && mysqli_get_server_version($link) > 50100)) {
die("skip Your MySQL Server version has a known bug that will cause a crash");
}
+
+if (mysqli_get_server_version($link) >= 50600)
+ die("SKIP For MySQL < 5.6.0");
?>
--FILE--
<?php
diff --git a/ext/mysqli/tests/mysqli_class_mysqli_reflection.phpt b/ext/mysqli/tests/mysqli_class_mysqli_reflection.phpt
index 63ec7ca3c0..8f6c24900a 100644
--- a/ext/mysqli/tests/mysqli_class_mysqli_reflection.phpt
+++ b/ext/mysqli/tests/mysqli_class_mysqli_reflection.phpt
@@ -1140,9 +1140,16 @@ isInternal: yes
isUserDefined: no
returnsReference: no
Modifiers: 256
-Number of Parameters: 0
+Number of Parameters: 1
Number of Required Parameters: 0
+Inspecting parameter 'flags' of method 'store_result'
+isArray: no
+allowsNull: no
+isPassedByReference: no
+isOptional: yes
+isDefaultValueAvailable: no
+
Inspecting method 'thread_safe'
isFinal: no
isAbstract: no
diff --git a/ext/mysqli/tests/mysqli_constants.phpt b/ext/mysqli/tests/mysqli_constants.phpt
index 7c6dacd393..bed9d53419 100644
--- a/ext/mysqli/tests/mysqli_constants.phpt
+++ b/ext/mysqli/tests/mysqli_constants.phpt
@@ -108,6 +108,10 @@ require_once('skipifconnectfailure.inc');
$expected_constants['MYSQLI_OPT_INT_AND_FLOAT_NATIVE'] = true;
}
+ if ($IS_MYSQLND && defined('MYSQLI_STORE_RESULT_COPY_DATA')) {
+ $expected_constants['MYSQLI_STORE_RESULT_COPY_DATA'] = true;
+ }
+
if ($IS_MYSQLND || defined('MYSQLI_REFRESH_BACKUP_LOG')) {
$expected_constants['MYSQLI_REFRESH_BACKUP_LOG'] = true;
}
diff --git a/ext/mysqli/tests/mysqli_fetch_all.phpt b/ext/mysqli/tests/mysqli_fetch_all.phpt
index 63b6ad2848..854b8160f0 100644
--- a/ext/mysqli/tests/mysqli_fetch_all.phpt
+++ b/ext/mysqli/tests/mysqli_fetch_all.phpt
@@ -299,6 +299,26 @@ if (!function_exists('mysqli_fetch_all'))
if (null !== ($tmp = mysqli_fetch_array($res, MYSQLI_ASSOC)))
printf("[015] Expecting NULL, got %s/%s\n", gettype($tmp), $tmp);
+ if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket)) {
+ printf("[016] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
+ $host, $user, $db, $port, $socket);
+ }
+
+ if (!$res = mysqli_real_query($link, "SELECT 1 AS _one"))
+ printf("[017] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+ /* on mysqlnd level this would not be allowed */
+ if (!is_object($res = mysqli_use_result($link)))
+ printf("[018] Expecting object, got %s/%s. [%d] %s\n",
+ gettype($res), $res, mysqli_errno($link), mysqli_error($link));
+
+ $rows = mysqli_fetch_all($res, MYSQLI_ASSOC);
+ if (!is_array($rows) || (count($rows) > 1) || !isset($rows[0]['_one']) || ($rows[0]['_one'] != 1)) {
+ printf("[019] Results seem wrong, dumping\n");
+ var_dump($rows);
+ }
+
+
print "done!";
?>
--CLEAN--
diff --git a/ext/mysqli/tests/mysqli_fetch_lengths.phpt b/ext/mysqli/tests/mysqli_fetch_lengths.phpt
index 1abc61170e..6d0b698ee7 100644
--- a/ext/mysqli/tests/mysqli_fetch_lengths.phpt
+++ b/ext/mysqli/tests/mysqli_fetch_lengths.phpt
@@ -10,8 +10,10 @@ require_once('skipifconnectfailure.inc');
<?php
require_once("connect.inc");
- if (!$mysqli = new mysqli($host, $user, $passwd, $db, $port, $socket))
- printf("[001] Cannot connect\n");
+ if (!$mysqli = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket)) {
+ printf("[001] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
+ $host, $user, $db, $port, $socket);
+ }
if (!is_null($tmp = @mysqli_fetch_lengths()))
printf("[001] Expecting NULL, got %s/%s\n", gettype($tmp), $tmp);
diff --git a/ext/mysqli/tests/mysqli_poll.phpt b/ext/mysqli/tests/mysqli_poll.phpt
index dd4f9b9710..8a49ba3f82 100644
--- a/ext/mysqli/tests/mysqli_poll.phpt
+++ b/ext/mysqli/tests/mysqli_poll.phpt
@@ -52,6 +52,13 @@ if (!$IS_MYSQLND)
if (0 !== ($tmp = (mysqli_poll($read, $error, $reject, 0, 1))))
printf("[009] Expecting int/0 got %s/%s\n", gettype($tmp), var_export($tmp, true));
+ $read = $error = $reject = array($link);
+ if (false !== ($tmp = (mysqli_poll($read, $error, $reject, -1, 1))))
+ printf("[010] Expecting false got %s/%s\n", gettype($tmp), var_export($tmp, true));
+
+ $read = $error = $reject = array($link);
+ if (false !== ($tmp = (mysqli_poll($read, $error, $reject, 0, -1))))
+ printf("[011] Expecting false got %s/%s\n", gettype($tmp), var_export($tmp, true));
function poll_async($offset, $link, $links, $errors, $reject, $exp_ready, $use_oo_syntax) {
@@ -90,14 +97,14 @@ if (!$IS_MYSQLND)
$links = array($link);
$errors = array($link);
$reject = array($link);
- poll_async(10, $link, $links, $errors, $reject, 0, false);
+ poll_async(12, $link, $links, $errors, $reject, 0, false);
mysqli_close($link);
$link = get_connection();
$links = array($link);
$errors = array($link);
$reject = array($link);
- poll_async(11, $link, $links, $errors, $reject, 0, true);
+ poll_async(13, $link, $links, $errors, $reject, 0, true);
mysqli_close($link);
// Connections on which no query has been send - 2
@@ -106,7 +113,7 @@ if (!$IS_MYSQLND)
$links = array($link, $link);
$errors = array($link, $link);
$reject = array();
- poll_async(12, $link, $links, $errors, $reject, 0, false);
+ poll_async(14, $link, $links, $errors, $reject, 0, false);
// Connections on which no query has been send - 3
// Difference: pass two connections
@@ -114,7 +121,7 @@ if (!$IS_MYSQLND)
$links = array($link, get_connection());
$errors = array($link, $link);
$reject = array();
- poll_async(13, $link, $links, $errors, $reject, 0, false);
+ poll_async(15, $link, $links, $errors, $reject, 0, false);
// Reference mess...
$link = get_connection();
@@ -122,16 +129,20 @@ if (!$IS_MYSQLND)
$errors = array($link);
$ref_errors =& $errors;
$reject = array();
- poll_async(14, $link, $links, $ref_errors, $reject, 0, false);
+ poll_async(16, $link, $links, $ref_errors, $reject, 0, false);
print "done!";
?>
--EXPECTF--
-[010 + 6] Rejecting thread %d: 0/
-[011 + 6] Rejecting thread %d: 0/
-[012 + 6] Rejecting thread %d: 0/
+
+Warning: mysqli_poll(): Negative values passed for sec and/or usec in %s on line %d
+
+Warning: mysqli_poll(): Negative values passed for sec and/or usec in %s on line %d
[012 + 6] Rejecting thread %d: 0/
[013 + 6] Rejecting thread %d: 0/
-[013 + 6] Rejecting thread %d: 0/
[014 + 6] Rejecting thread %d: 0/
-done!
+[014 + 6] Rejecting thread %d: 0/
+[015 + 6] Rejecting thread %d: 0/
+[015 + 6] Rejecting thread %d: 0/
+[016 + 6] Rejecting thread %d: 0/
+done! \ No newline at end of file
diff --git a/ext/mysqli/tests/mysqli_poll_kill.phpt b/ext/mysqli/tests/mysqli_poll_kill.phpt
index b068d64e8f..c69a251111 100644
--- a/ext/mysqli/tests/mysqli_poll_kill.phpt
+++ b/ext/mysqli/tests/mysqli_poll_kill.phpt
@@ -90,6 +90,7 @@ if (!$IS_MYSQLND)
// Yes, 1 - fetch OK packet of kill!
$processed = 0;
+ $begin = microtime(true);
do {
$links = array($link, $link);
$errors = array($link, $link);
@@ -106,9 +107,14 @@ if (!$IS_MYSQLND)
break;
}
+ if (FALSE === $ready) {
+ printf("[013] MySQLi indicates some error\n");
+ break;
+ }
+
if (!empty($reject)) {
foreach ($reject as $mysqli) {
- printf("[013] Rejecting thread %d: %s/%s\n",
+ printf("[014] Rejecting thread %d: %s/%s\n",
mysqli_thread_id($mysqli),
mysqli_errno($mysqli),
mysqli_error($mysqli));
@@ -121,11 +127,16 @@ if (!$IS_MYSQLND)
printf("Fetching from thread %d...\n", mysqli_thread_id($mysqli));
var_dump(mysqli_fetch_assoc($res));
} else if (mysqli_errno($mysqli) > 0) {
- printf("[014] %d/%s\n", mysqli_errno($mysqli), mysqli_error($mysqli));
+ printf("[015] %d/%s\n", mysqli_errno($mysqli), mysqli_error($mysqli));
}
$processed++;
}
+ if ((microtime(true) - $begin) > 5) {
+ printf("[016] Pulling the emergency break after 5s, something is wrong...\n");
+ break;
+ }
+
} while ($processed < 2);
@@ -137,17 +148,17 @@ if (!$IS_MYSQLND)
// Sleep 0.1s to ensure the KILL gets recognized
usleep(100000);
if (false !== ($tmp = mysqli_query($link, "SELECT 1 AS 'processed before killed'", MYSQLI_ASYNC | MYSQLI_USE_RESULT)))
- printf("[015] Expecting boolean/false got %s/%s\n", gettype($tmp), var_export($tmp, true));
+ printf("[017] Expecting boolean/false got %s/%s\n", gettype($tmp), var_export($tmp, true));
$links = array($link);
$errors = array($link);
$reject = array($link);
if (0 !== ($tmp = (mysqli_poll($links, $errors, $reject, 0, 10000))))
- printf("[016] Expecting int/0 got %s/%s\n", gettype($tmp), var_export($tmp, true));
+ printf("[018] Expecting int/0 got %s/%s\n", gettype($tmp), var_export($tmp, true));
if (!is_array($links) || empty($links))
- printf("[017] Expecting non-empty array got %s/%s\n", gettype($links), var_export($links, true));
+ printf("[019] Expecting non-empty array got %s/%s\n", gettype($links), var_export($links, true));
else
foreach ($links as $link) {
if (is_object($res = mysqli_reap_async_query($link))) {
@@ -156,16 +167,16 @@ if (!$IS_MYSQLND)
mysqli_free_result($res);
} else if ($link->errno > 0) {
// But you are supposed to handle the error the way its shown here!
- printf("[018] Error: %d/%s\n", $link->errno, $link->error);
+ printf("[020] Error: %d/%s\n", $link->errno, $link->error);
}
}
// None of these will indicate an error, check errno on the list of returned connections!
if (!is_array($errors) || !empty($errors))
- printf("[019] Expecting non-empty array got %s/%s\n", gettype($errors), var_export($errors, true));
+ printf("[021] Expecting non-empty array got %s/%s\n", gettype($errors), var_export($errors, true));
if (!is_array($reject) || !empty($reject))
- printf("[020] Expecting empty array got %s/%s\n", gettype($reject), var_export($reject, true));
+ printf("[021] Expecting empty array got %s/%s\n", gettype($reject), var_export($reject, true));
mysqli_close($link);
diff --git a/ext/mysqli/tests/mysqli_poll_mixing_insert_select.phpt b/ext/mysqli/tests/mysqli_poll_mixing_insert_select.phpt
index 9c02cf9760..9068f6f708 100644
--- a/ext/mysqli/tests/mysqli_poll_mixing_insert_select.phpt
+++ b/ext/mysqli/tests/mysqli_poll_mixing_insert_select.phpt
@@ -80,13 +80,17 @@ if (!$IS_MYSQLND)
if (0 == count($poll_links))
break;
- if (0 == ($num_ready = mysqli_poll($poll_links, $poll_errors, $poll_reject, 0, 200000)))
+ if (0 === ($num_ready = mysqli_poll($poll_links, $poll_errors, $poll_reject, 0, 200000)))
continue;
if (!empty($poll_errors)) {
die(var_dump($poll_errors));
}
+ if (FALSE === $num_ready) {
+ die("Some mysqli indicated error");
+ }
+
foreach ($poll_links as $link) {
$thread_id = mysqli_thread_id($link);
$links[$thread_id]['processed'] = true;
diff --git a/ext/mysqli/tests/mysqli_reap_async_query.phpt b/ext/mysqli/tests/mysqli_reap_async_query.phpt
new file mode 100644
index 0000000000..e3858e6172
--- /dev/null
+++ b/ext/mysqli/tests/mysqli_reap_async_query.phpt
@@ -0,0 +1,97 @@
+--TEST--
+mysqli_reap_async_query()
+--SKIPIF--
+<?php
+require_once('skipif.inc');
+require_once('skipifemb.inc');
+require_once('connect.inc');
+require_once('skipifconnectfailure.inc');
+
+if (!$IS_MYSQLND)
+ die("skip mysqlnd only feature, compile PHP using --with-mysqli=mysqlnd");
+?>
+--FILE--
+<?php
+ require_once('connect.inc');
+
+ function get_connection() {
+ global $host, $user, $passwd, $db, $port, $socket;
+
+ if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
+ printf("[001] [%d] %s\n", mysqli_connect_errno(), mysqli_connect_error());
+ return $link;
+ }
+
+ if (!$link = get_connection())
+ printf("[001] [%d] %s\n", mysqli_connect_errno(), mysqli_connect_error());
+
+ if (NULL !== ($tmp = @mysqli_reap_async_query()))
+ printf("[002] Expecting NULL got %s\n", var_export($tmp, true));
+
+ $l = array($link);
+ if (NULL !== ($tmp = @mysqli_reap_async_query($l)))
+ printf("[003] Expecting NULL got %s\n", var_export($tmp, true));
+
+ if (NULL !== ($tmp = @mysqli_reap_async_query($link, $link)))
+ printf("[004] Expecting NULL got %s\n", var_export($tmp, true));
+
+
+ function poll_async($offset, $link, $links, $errors, $reject, $exp_ready, $use_oo_syntax) {
+
+ if ($exp_ready !== ($tmp = mysqli_poll($links, $errors, $reject, 0, 1000)))
+ printf("[%03d + 1] There should be %d links ready to read from, %d ready\n",
+ $offset, $exp_ready, $tmp);
+
+ foreach ($links as $mysqli) {
+ if ($use_oo_syntax) {
+ $res = $mysqli->reap_async_query();
+ } else {
+ $res = mysqli_reap_async_query($mysqli);
+ }
+ if (is_object($res)) {
+ printf("[%03d + 2] %s\n", $offset, var_export($res->fetch_assoc(), true));
+ } else if (mysqli_errno($mysqli) > 0) {
+ printf("[%03d + 3] Error indicated through links array: %d/%s",
+ $offset, mysqli_errno($mysqli), mysqli_error($mysqli));
+ } else {
+ printf("[%03d + 4] Cannot fetch and no error set - non resultset query (no SELECT)!\n", $offset);
+ }
+ }
+
+ foreach ($errors as $mysqli)
+ printf("[%03d + 5] Error on %d: %d/%s\n",
+ $offset, mysqli_thread_id($mysqli), mysqli_errno($mysqli), mysqli_error($mysqli));
+
+ foreach ($reject as $mysqli)
+ printf("[%03d + 6] Rejecting thread %d: %d/%s\n",
+ $offset, mysqli_thread_id($mysqli), mysqli_errno($mysqli), mysqli_error($mysqli));
+
+ }
+
+ // Connections on which no query has been send - 1
+ $link = get_connection();
+ $link->query("SELECT 1 AS _one", MYSQLI_ASYNC | MYSQLI_STORE_RESULT);
+ $links = array($link);
+ $errors = array($link);
+ $reject = array($link);
+ poll_async(12, $link, $links, $errors, $reject, 1, false);
+ mysqli_close($link);
+
+ $link = get_connection();
+ $link->query("SELECT 2 AS _two", MYSQLI_ASYNC | MYSQLI_USE_RESULT);
+ $links = array($link);
+ $errors = array($link);
+ $reject = array($link);
+ poll_async(13, $link, $links, $errors, $reject, 1, true);
+ mysqli_close($link);
+
+ print "done!";
+?>
+--EXPECTF--
+[012 + 2] array (
+ '_one' => '1',
+)
+[013 + 2] array (
+ '_two' => '2',
+)
+done!
diff --git a/ext/mysqli/tests/mysqli_release_savepoint.phpt b/ext/mysqli/tests/mysqli_release_savepoint.phpt
new file mode 100644
index 0000000000..ba4c564385
--- /dev/null
+++ b/ext/mysqli/tests/mysqli_release_savepoint.phpt
@@ -0,0 +1,84 @@
+--TEST--
+mysqli_release_savepoint()
+--SKIPIF--
+<?php
+require_once('skipif.inc');
+require_once('skipifemb.inc');
+require_once('skipifconnectfailure.inc');
+
+require_once('connect.inc');
+if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
+ die(sprintf("Cannot connect, [%d] %s", mysqli_connect_errno(), mysqli_connect_error()));
+
+if (!have_innodb($link))
+ die(sprintf("Needs InnoDB support, [%d] %s", $link->errno, $link->error));
+?>
+--FILE--
+<?php
+ require_once("connect.inc");
+ /* {{{ proto bool mysqli_release_savepoint(object link, string name) */
+ $tmp = NULL;
+ $link = NULL;
+
+ if (!is_null($tmp = @mysqli_release_savepoint()))
+ printf("[001] Expecting NULL, got %s/%s\n", gettype($tmp), $tmp);
+
+ if (!is_null($tmp = @mysqli_release_savepoint($link)))
+ printf("[002] Expecting NULL, got %s/%s\n", gettype($tmp), $tmp);
+
+ if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
+ printf("[003] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
+ $host, $user, $db, $port, $socket);
+
+ $name = array();
+ if (!is_null($tmp = @mysqli_release_savepoint($link, $name)))
+ printf("[004] Expecting NULL, got %s/%s\n", gettype($tmp), $tmp);
+
+ if (!is_null($tmp = @mysqli_release_savepoint($link, 'foo', $link)))
+ printf("[005] Expecting NULL, got %s/%s\n", gettype($tmp), $tmp);
+
+ if (false !== ($tmp = mysqli_release_savepoint($link, '')))
+ printf("[006] Expecting false, got %s/%s\n", gettype($tmp), $tmp);
+
+ if (!mysqli_query($link, 'DROP TABLE IF EXISTS test'))
+ printf("[007] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+ if (!mysqli_query($link, 'CREATE TABLE test(id INT) ENGINE = InnoDB'))
+ printf("[008] Cannot create test table, [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+ if (true !== ($tmp = mysqli_autocommit($link, false)))
+ printf("[009] Cannot turn off autocommit, expecting true, got %s/%s\n", gettype($tmp), $tmp);
+
+ /* note that there is no savepoint my... */
+ if (true !== ($tmp = mysqli_release_savepoint($link, 'my')))
+ printf("[010] Got %s - [%d] %s\n", var_dump($tmp, true), mysqli_errno($link), mysqli_error($link));
+
+ if (!mysqli_query($link, 'INSERT INTO test(id) VALUES (1)'))
+ printf("[011] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+ $tmp = mysqli_commit($link);
+ if ($tmp !== true)
+ printf("[012] Expecting boolean/true, got %s/%s\n", gettype($tmp), $tmp);
+
+ if (true !== ($tmp = mysqli_savepoint($link, 'my')))
+ printf("[013] Got %s - [%d] %s\n", var_dump($tmp, true), mysqli_errno($link), mysqli_error($link));
+
+ $res = mysqli_query($link, "SELECT * FROM test");
+ var_dump($res->fetch_assoc());
+
+ if (true !== ($tmp = mysqli_release_savepoint($link, 'my')))
+ printf("[014] Got %s - [%d] %s\n", var_dump($tmp, true), mysqli_errno($link), mysqli_error($link));
+
+ print "done!";
+?>
+--CLEAN--
+<?php
+ require_once("clean_table.inc");
+?>
+--EXPECTF--
+Warning: mysqli_release_savepoint(): Savepoint name cannot be empty in %s on line %d
+array(1) {
+ ["id"]=>
+ string(1) "1"
+}
+done! \ No newline at end of file
diff --git a/ext/mysqli/tests/mysqli_report.phpt b/ext/mysqli/tests/mysqli_report.phpt
index f5d77e38bc..4d2d3553d1 100644
--- a/ext/mysqli/tests/mysqli_report.phpt
+++ b/ext/mysqli/tests/mysqli_report.phpt
@@ -43,8 +43,6 @@ require_once('skipifconnectfailure.inc');
mysqli_multi_query($link, "BAR; FOO;");
mysqli_query($link, "FOO");
- /* This might work if you accept anonymous users in your setup */
- mysqli_change_user($link, "0123456789-10-456789-20-456789-30-456789-40-456789-50-456789-60-456789-70-456789-80-456789-90-456789", "password", $db);
mysqli_kill($link, -1);
// mysqli_ping() cannot be tested, because one would need to cause an error inside the C function to test it
@@ -61,7 +59,6 @@ require_once('skipifconnectfailure.inc');
mysqli_multi_query($link, "BAR; FOO;");
mysqli_query($link, "FOO");
- mysqli_change_user($link, "This might work if you accept anonymous users in your setup", "password", $db);
mysqli_kill($link, -1);
mysqli_prepare($link, "FOO");
mysqli_real_query($link, "FOO");
@@ -291,8 +288,6 @@ Warning: mysqli_multi_query(): (%d/%d): You have an error in your SQL syntax; ch
Warning: mysqli_query(): (%d/%d): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'FOO' at line 1 in %s on line %d
-Warning: mysqli_change_user(): (%d/%d): Access denied for user '%s'@'%s' (using password: %s) in %s on line %d
-
Warning: mysqli_kill(): processid should have positive value in %s on line %d
Warning: mysqli_prepare(): (%d/%d): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'FOO' at line 1 in %s on line %d
diff --git a/ext/mysqli/tests/mysqli_report_new.phpt b/ext/mysqli/tests/mysqli_report_new.phpt
new file mode 100644
index 0000000000..5cf5ca8e3b
--- /dev/null
+++ b/ext/mysqli/tests/mysqli_report_new.phpt
@@ -0,0 +1,50 @@
+--TEST--
+mysqli_report(), change user, MySQL 5.6+
+--SKIPIF--
+<?php
+require_once('skipif.inc');
+require_once('skipifemb.inc');
+require_once('skipifconnectfailure.inc');
+
+if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
+ die(sprintf("SKIP Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
+ $host, $user, $db, $port, $socket));
+
+if (mysqli_get_server_version($link) < 50600)
+ die("SKIP For MySQL >= 5.6.0");
+
+?>
+--FILE--
+<?php
+ require_once("connect.inc");
+
+ $tmp = NULL;
+ $link = NULL;
+
+ require('table.inc');
+
+ /*
+ Internal macro MYSQL_REPORT_ERROR
+ */
+ mysqli_report(MYSQLI_REPORT_ERROR);
+
+ mysqli_change_user($link, "0123456789-10-456789-20-456789-30-456789-40-456789-50-456789-60-456789-70-456789-80-456789-90-456789", "password", $db);
+
+ mysqli_report(MYSQLI_REPORT_OFF);
+
+ if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
+ printf("[001] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
+ $host, $user, $db, $port, $socket);
+
+ mysqli_change_user($link, "This might work if you accept anonymous users in your setup", "password", $db);
+
+ print "done!";
+?>
+--CLEAN--
+<?php
+ require_once("clean_table.inc");
+?>
+--EXPECTF--
+
+Warning: mysqli_change_user(): (%d/%d): Access denied for user '%s'@'%s' (using password: %s) in %s on line %d
+done! \ No newline at end of file
diff --git a/ext/mysqli/tests/mysqli_report_wo_ps.phpt b/ext/mysqli/tests/mysqli_report_wo_ps.phpt
index cc57511b5b..dae81b21cc 100644
--- a/ext/mysqli/tests/mysqli_report_wo_ps.phpt
+++ b/ext/mysqli/tests/mysqli_report_wo_ps.phpt
@@ -1,10 +1,17 @@
--TEST--
-mysqli_report()
+mysqli_report(), MySQL < 5.6
--SKIPIF--
<?php
require_once('skipif.inc');
require_once('skipifemb.inc');
require_once('skipifconnectfailure.inc');
+
+if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
+ die(sprintf("SKIP Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
+ $host, $user, $db, $port, $socket));
+
+if (mysqli_get_server_version($link) >= 50600)
+ die("SKIP For MySQL < 5.6.0");
?>
--FILE--
<?php
diff --git a/ext/mysqli/tests/mysqli_savepoint.phpt b/ext/mysqli/tests/mysqli_savepoint.phpt
new file mode 100644
index 0000000000..5775b0eaec
--- /dev/null
+++ b/ext/mysqli/tests/mysqli_savepoint.phpt
@@ -0,0 +1,72 @@
+--TEST--
+mysqli_savepoint()
+--SKIPIF--
+<?php
+require_once('skipif.inc');
+require_once('skipifemb.inc');
+require_once('skipifconnectfailure.inc');
+
+require_once('connect.inc');
+if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
+ die(sprintf("Cannot connect, [%d] %s", mysqli_connect_errno(), mysqli_connect_error()));
+
+if (!have_innodb($link))
+ die(sprintf("Needs InnoDB support, [%d] %s", $link->errno, $link->error));
+?>
+--FILE--
+<?php
+ require_once("connect.inc");
+ /* {{{ proto bool mysqli_savepoint(object link, string name) */
+ $tmp = NULL;
+ $link = NULL;
+
+ if (!is_null($tmp = @mysqli_savepoint()))
+ printf("[001] Expecting NULL, got %s/%s\n", gettype($tmp), $tmp);
+
+ if (!is_null($tmp = @mysqli_savepoint($link)))
+ printf("[002] Expecting NULL, got %s/%s\n", gettype($tmp), $tmp);
+
+ if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
+ printf("[003] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
+ $host, $user, $db, $port, $socket);
+
+ $name = array();
+ if (!is_null($tmp = @mysqli_savepoint($link, $name)))
+ printf("[004] Expecting NULL, got %s/%s\n", gettype($tmp), $tmp);
+
+ if (!is_null($tmp = @mysqli_savepoint($link, 'foo', $link)))
+ printf("[005] Expecting NULL, got %s/%s\n", gettype($tmp), $tmp);
+
+ if (false !== ($tmp = mysqli_savepoint($link, '')))
+ printf("[006] Expecting false, got %s/%s\n", gettype($tmp), $tmp);
+
+ if (!mysqli_query($link, 'DROP TABLE IF EXISTS test'))
+ printf("[007] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+ if (!mysqli_query($link, 'CREATE TABLE test(id INT) ENGINE = InnoDB'))
+ printf("[008] Cannot create test table, [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+ if (true !== ($tmp = mysqli_autocommit($link, false)))
+ printf("[009] Cannot turn off autocommit, expecting true, got %s/%s\n", gettype($tmp), $tmp);
+
+ /* overrule autocommit */
+ if (true !== ($tmp = mysqli_savepoint($link, 'my')))
+ printf("[010] Got %s - [%d] %s\n", var_dump($tmp, true), mysqli_errno($link), mysqli_error($link));
+
+ if (!mysqli_query($link, 'INSERT INTO test(id) VALUES (1)'))
+ printf("[011] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+ $tmp = mysqli_rollback($link);
+ if ($tmp !== true)
+ printf("[012] Expecting boolean/true, got %s/%s\n", gettype($tmp), $tmp);
+
+ print "done!";
+?>
+--CLEAN--
+<?php
+ require_once("clean_table.inc");
+?>
+--EXPECTF--
+
+Warning: mysqli_savepoint(): Savepoint name cannot be empty in %s on line %d
+done!
diff --git a/ext/mysqli/tests/mysqli_stmt_get_warnings.phpt b/ext/mysqli/tests/mysqli_stmt_get_warnings.phpt
index 2b0e150ded..69755865e9 100644
--- a/ext/mysqli/tests/mysqli_stmt_get_warnings.phpt
+++ b/ext/mysqli/tests/mysqli_stmt_get_warnings.phpt
@@ -17,7 +17,7 @@ if (!mysqli_query($link, "DROP TABLE IF EXISTS test") ||
!mysqli_query($link, "CREATE TABLE test(id SMALLINT)"))
die(sprintf("skip [%d] %s\n", $link->errno, $link->error));
-if (!@mysqli_query("INSERT INTO test(id) VALUES (100001)"))
+if (!@mysqli_query($link, "SET sql_mode=''") || !@mysqli_query($link, "INSERT INTO test(id) VALUES (100001)"))
die("skip Strict sql mode seems to be active. We won't get a warning to check for.");
mysqli_query($link, "DROP TABLE IF EXISTS test");
@@ -43,54 +43,57 @@ mysqli_query($link, "DROP TABLE IF EXISTS test");
if (NULL !== ($tmp = mysqli_stmt_get_warnings($stmt)))
printf("[004] Expecting NULL, got %s/%s\n", gettype($tmp), $tmp);
- if (!mysqli_stmt_prepare($stmt, "DROP TABLE IF EXISTS test") || !mysqli_stmt_execute($stmt))
+ if (!mysqli_stmt_prepare($stmt, "SET sql_mode=''") || !mysqli_stmt_execute($stmt))
printf("[005] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
+ if (!mysqli_stmt_prepare($stmt, "DROP TABLE IF EXISTS test") || !mysqli_stmt_execute($stmt))
+ printf("[006] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
+
if (false !== ($tmp = mysqli_stmt_get_warnings($stmt)))
- printf("[006] Expecting boolean/false, got %s/%s\n", gettype($tmp), $tmp);
+ printf("[007] Expecting boolean/false, got %s/%s\n", gettype($tmp), $tmp);
if (!mysqli_stmt_prepare($stmt, "CREATE TABLE test(id SMALLINT, label CHAR(1))") || !mysqli_stmt_execute($stmt))
- printf("[007] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
+ printf("[008] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
if (false !== ($tmp = mysqli_stmt_get_warnings($stmt)))
- printf("[008] Expecting boolean/false, got %s/%s\n", gettype($tmp), $tmp);
+ printf("[009] Expecting boolean/false, got %s/%s\n", gettype($tmp), $tmp);
if (!mysqli_stmt_prepare($stmt, "INSERT INTO test(id, label) VALUES (100000, 'a'), (100001, 'b')") ||
!mysqli_stmt_execute($stmt))
- printf("[009] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
+ printf("[010] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
if (!is_object($warning = mysqli_stmt_get_warnings($stmt)))
- printf("[010] Expecting mysqli_warning object, got %s/%s\n", gettype($warning), $warning);
+ printf("[011] Expecting mysqli_warning object, got %s/%s\n", gettype($warning), $warning);
if ('mysqli_warning' !== get_class($warning))
- printf("[011] Expecting object of type mysqli_warning got type '%s'", get_class($warning));
+ printf("[012] Expecting object of type mysqli_warning got type '%s'", get_class($warning));
if (!method_exists($warning, 'next'))
- printf("[012] Object mysqli_warning seems to lack method next()\n");
+ printf("[013] Object mysqli_warning seems to lack method next()\n");
$i = 0;
do {
if ('' == $warning->message)
- printf("[013 - %d] Message should not be empty\n", $i);
+ printf("[014 - %d] Message should not be empty\n", $i);
if ('' == $warning->sqlstate)
- printf("[014 - %d] SQL State should not be empty\n", $i);
+ printf("[015 - %d] SQL State should not be empty\n", $i);
if (0 == $warning->errno)
- printf("[015 - %d] Error number should not be zero\n", $i);
+ printf("[016 - %d] Error number should not be zero\n", $i);
$i++;
} while ($warning->next());
if (2 != $i)
- printf("[016] Expected 2 warnings, got %d warnings\n", $i);
+ printf("[017] Expected 2 warnings, got %d warnings\n", $i);
mysqli_stmt_close($stmt);
if (NULL !== ($tmp = mysqli_stmt_get_warnings($stmt)))
- printf("[015] Expecting NULL, got %s/%s\n", gettype($tmp), $tmp);
+ printf("[018] Expecting NULL, got %s/%s\n", gettype($tmp), $tmp);
mysqli_close($link);
print "done!";
diff --git a/ext/mysqli/tests/mysqli_store_result_buffered_c.phpt b/ext/mysqli/tests/mysqli_store_result_buffered_c.phpt
new file mode 100644
index 0000000000..d580ec430f
--- /dev/null
+++ b/ext/mysqli/tests/mysqli_store_result_buffered_c.phpt
@@ -0,0 +1,42 @@
+--TEST--
+mysqli_store_result()
+--SKIPIF--
+<?php
+require_once('skipif.inc');
+require_once('skipifemb.inc');
+require_once('skipifconnectfailure.inc');
+?>
+--INI--
+mysqlnd.debug=d:t:O,/tmp/mysqlnd.trace
+--FILE--
+<?php
+ require_once("connect.inc");
+
+ $tmp = NULL;
+ $link = NULL;
+
+
+ require('table.inc');
+
+ if (!$res = mysqli_real_query($link, "SELECT id, label FROM test ORDER BY id"))
+ printf("[003] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+ if (!is_object($res = mysqli_store_result($link, MYSQLI_STORE_RESULT_COPY_DATA)))
+ printf("[004] Expecting object, got %s/%s. [%d] %s\n",
+ gettype($res), $res, mysqli_errno($link), mysqli_error($link));
+
+ if (true !== ($tmp = mysqli_data_seek($res, 2)))
+ printf("[005] Expecting boolean/true, got %s/%s. [%d] %s\n",
+ gettype($tmp), $tmp, mysqli_errno($link), mysqli_error($link));
+
+ mysqli_free_result($res);
+
+ print "done!";
+?>
+--CLEAN--
+<?php
+ require_once("clean_table.inc");
+?>
+--EXPECTF--
+Warning: mysqli_store_result(): Couldn't fetch mysqli in %s on line %d
+done! \ No newline at end of file
diff --git a/ext/mysqli/tests/mysqli_store_result_copy.phpt b/ext/mysqli/tests/mysqli_store_result_copy.phpt
new file mode 100644
index 0000000000..304300459b
--- /dev/null
+++ b/ext/mysqli/tests/mysqli_store_result_copy.phpt
@@ -0,0 +1,285 @@
+--TEST--
+mysqli_store_result()
+--SKIPIF--
+<?php
+require_once('skipif.inc');
+require_once('skipifemb.inc');
+require_once('skipifconnectfailure.inc');
+if (!$IS_MYSQLND) {
+ die("SKIP mysqlnd only test");
+}
+?>
+--INI--
+mysqlnd.debug=d:t:O,/tmp/mysqlnd.trace
+mysqlnd.net_read_buffer_size=1
+mysqlnd.mempool_default_size=1
+mysqlnd.fetch_data_copy=0
+--FILE--
+<?php
+ require_once("connect.inc");
+
+ $tmp = NULL;
+ $link = NULL;
+
+ require('table.inc');
+
+ if (!$res = mysqli_real_query($link, "SELECT id, label FROM test ORDER BY id"))
+ printf("[003] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+ if (!is_object($res = mysqli_store_result($link, MYSQLI_STORE_RESULT_COPY_DATA)))
+ printf("[004] Expecting object, got %s/%s. [%d] %s\n",
+ gettype($res), $res, mysqli_errno($link), mysqli_error($link));
+
+ if (true !== ($tmp = mysqli_data_seek($res, 2)))
+ printf("[005] Expecting boolean/true, got %s/%s. [%d] %s\n",
+ gettype($tmp), $tmp, mysqli_errno($link), mysqli_error($link));
+
+ var_dump($res->fetch_assoc());
+
+ if (true !== ($tmp = mysqli_data_seek($res, 0)))
+ printf("[006] Expecting boolean/true, got %s/%s. [%d] %s\n",
+ gettype($tmp), $tmp, mysqli_errno($link), mysqli_error($link));
+
+ while ($row = $res->fetch_assoc()) {
+ printf("id = %d, label = %s\n", $row['id'], $row['label']);
+ }
+
+ mysqli_free_result($res);
+ mysqli_close($link);
+
+ if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket)) {
+ printf("[007] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
+ $host, $user, $db, $port, $socket);
+ }
+
+
+ if (!$res = mysqli_real_query($link, "SELECT id, label FROM test ORDER BY id"))
+ printf("[008] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+ if (!is_object($res = mysqli_store_result($link, MYSQLI_STORE_RESULT_COPY_DATA)))
+ printf("[009] Expecting object, got %s/%s. [%d] %s\n",
+ gettype($res), $res, mysqli_errno($link), mysqli_error($link));
+
+ $no_result = 0;
+ for ($i = 0; $i < 1000; $i++) {
+ $idx = mt_rand(-100, 100);
+ if (true === @mysqli_data_seek($res, $idx)) {
+ $row = $res->fetch_assoc();
+ if (!isset($row['id']) || !isset($row['label'])) {
+ printf("[010] Brute force seek %d returned %d\n", $idx, var_export($row, true));
+ }
+ } else {
+ $no_result++;
+ }
+ }
+ printf("No result: %d\n", $no_result);
+
+ /* implicit free, implicit store */
+ /* meta and fetch lenghts code */
+ if (!$res = mysqli_query($link, "SELECT CONCAT(id, id) AS _c, label FROM test ORDER BY id DESC LIMIT 2"))
+ printf("[011] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+ printf("Default\n");
+ var_dump(mysqli_fetch_lengths($res));
+ $fields = $res->fetch_fields();
+ while ($row = $res->fetch_assoc()) {
+ var_dump(mysqli_fetch_lengths($res));
+ }
+ var_dump(mysqli_fetch_lengths($res));
+
+ if (!$res = mysqli_real_query($link, "SELECT CONCAT(id, id) AS _c, label FROM test ORDER BY id DESC LIMIT 2"))
+ printf("[012] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+ if (!is_object($res = mysqli_store_result($link, MYSQLI_STORE_RESULT_COPY_DATA)))
+ printf("[013] Expecting object, got %s/%s. [%d] %s\n",
+ gettype($res), $res, mysqli_errno($link), mysqli_error($link));
+
+ printf("Copy\n");
+ var_dump(mysqli_fetch_lengths($res));
+ $fields_copy = $res->fetch_fields();
+ while ($row = $res->fetch_assoc()) {
+ var_dump(mysqli_fetch_lengths($res));
+ }
+ var_dump(mysqli_fetch_lengths($res));
+
+ /* There's no need for in-depth testing here. If you want in-depth switch mysqlnd
+ globally to copy mode and run all the tests */
+ foreach ($fields as $k => $field_info) {
+ if ($fields_copy[$k] != $field_info) {
+ printf("[014] Metadata seems to differ, dumping\n");
+ var_dump($field_info);
+ var_dump($fields_copy[$k]);
+ }
+ }
+
+ /* fetch all */
+
+ if (!$res = mysqli_real_query($link, "SELECT id, label FROM test ORDER BY id DESC LIMIT 2"))
+ printf("[015] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+ if (!is_object($res = mysqli_store_result($link, MYSQLI_STORE_RESULT_COPY_DATA)))
+ printf("[016] Expecting object, got %s/%s. [%d] %s\n",
+ gettype($res), $res, mysqli_errno($link), mysqli_error($link));
+
+ foreach (mysqli_fetch_all($res, MYSQLI_ASSOC) as $row) {
+ printf("id = %d label = %s\n", $row['id'], $row['label']);
+ }
+
+ if (!$res = mysqli_real_query($link, "SELECT id, label FROM test ORDER BY id DESC LIMIT 2"))
+ printf("[017] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+ if (!is_object($res = mysqli_store_result($link, MYSQLI_STORE_RESULT_COPY_DATA)))
+ printf("[018] Expecting object, got %s/%s. [%d] %s\n",
+ gettype($res), $res, mysqli_errno($link), mysqli_error($link));
+
+ /* provoke out of sync */
+ if (!mysqli_real_query($link, "SELECT id, label FROM test ORDER BY id DESC LIMIT 2"))
+ printf("[019] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+ var_dump($res->fetch_assoc());
+
+ if (!$res = mysqli_real_query($link, "SELECT id, label FROM test ORDER BY id ASC LIMIT 2"))
+ printf("[020] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+ if (!is_object($res = mysqli_store_result($link, MYSQLI_STORE_RESULT_COPY_DATA)))
+ printf("[021] Expecting object, got %s/%s. [%d] %s\n",
+ gettype($res), $res, mysqli_errno($link), mysqli_error($link));
+
+ /* user conn killed, res associated with conn, fetch from res */
+ unset($link);
+ var_dump($res->fetch_assoc());
+
+
+ if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket)) {
+ printf("[022] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
+ $host, $user, $db, $port, $socket);
+ }
+
+ if (!$res = mysqli_real_query($link, "INSERT INTO test(id, label) VALUES (100, 'z')"))
+ printf("[023] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+ mysqli_store_result($link, MYSQLI_STORE_RESULT_COPY_DATA);
+
+ if (mysqli_get_server_version($link) > 50000) {
+ // let's try to play with stored procedures
+ mysqli_real_query($link, 'DROP PROCEDURE IF EXISTS p');
+ if (mysqli_real_query($link, 'CREATE PROCEDURE p(OUT ver_param VARCHAR(25)) READS SQL DATA BEGIN SELECT id FROM test WHERE id >= 100 ORDER BY id; SELECT id + 1, label FROM test WHERE id > 0 AND id < 3 ORDER BY id; SELECT VERSION() INTO ver_param;
+END;')) {
+ mysqli_multi_query($link, "CALL p(@version)");
+ do {
+ if ($res = $link->store_result(MYSQLI_STORE_RESULT_COPY_DATA)) {
+ printf("---\n");
+ var_dump($res->fetch_all());
+ $res->free();
+ } else {
+ if ($link->errno) {
+ echo "Store failed: (" . $link->errno . ") " . $link->error;
+ }
+ }
+ } while ($link->more_results() && $link->next_result());
+ mysqli_real_query($link, 'SELECT @version AS p_version');
+ $res = mysqli_store_result($link, MYSQLI_STORE_RESULT_COPY_DATA);
+
+ $tmp = mysqli_fetch_assoc($res);
+ if (!is_array($tmp) || empty($tmp) || !isset($tmp['p_version']) || ('' == $tmp['p_version'])) {
+ printf("[024] Expecting array [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+ var_dump($tmp);
+ }
+
+ mysqli_free_result($res);
+ } else {
+ printf("[025] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+ }
+ }
+
+ print "done!";
+?>
+--CLEAN--
+<?php
+ require_once("clean_table.inc");
+?>
+--EXPECTF--
+array(2) {
+ ["id"]=>
+ string(1) "3"
+ ["label"]=>
+ string(1) "c"
+}
+id = 1, label = a
+id = 2, label = b
+id = 3, label = c
+id = 4, label = d
+id = 5, label = e
+id = 6, label = f
+No result: %d
+Default
+bool(false)
+array(2) {
+ [0]=>
+ int(2)
+ [1]=>
+ int(1)
+}
+array(2) {
+ [0]=>
+ int(2)
+ [1]=>
+ int(1)
+}
+bool(false)
+Copy
+bool(false)
+array(2) {
+ [0]=>
+ int(2)
+ [1]=>
+ int(1)
+}
+array(2) {
+ [0]=>
+ int(2)
+ [1]=>
+ int(1)
+}
+bool(false)
+id = 6 label = f
+id = 5 label = e
+array(2) {
+ ["id"]=>
+ string(1) "6"
+ ["label"]=>
+ string(1) "f"
+}
+[020] [2014] %s
+array(2) {
+ ["id"]=>
+ string(1) "6"
+ ["label"]=>
+ string(1) "f"
+}
+---
+array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(3) "100"
+ }
+}
+---
+array(2) {
+ [0]=>
+ array(2) {
+ [0]=>
+ string(1) "2"
+ [1]=>
+ string(1) "a"
+ }
+ [1]=>
+ array(2) {
+ [0]=>
+ string(1) "3"
+ [1]=>
+ string(1) "b"
+ }
+}
+done! \ No newline at end of file
diff --git a/ext/mysqlnd/mysqlnd.c b/ext/mysqlnd/mysqlnd.c
index 3c1bc82f44..e64efe9122 100644
--- a/ext/mysqlnd/mysqlnd.c
+++ b/ext/mysqlnd/mysqlnd.c
@@ -1111,7 +1111,8 @@ PHPAPI MYSQLND * mysqlnd_connect(MYSQLND * conn_handle,
const char * db, unsigned int db_len,
unsigned int port,
const char * socket_or_pipe,
- unsigned int mysql_flags
+ unsigned int mysql_flags,
+ unsigned int client_api_flags
TSRMLS_DC)
{
enum_func_status ret = FAIL;
@@ -1122,7 +1123,7 @@ PHPAPI MYSQLND * mysqlnd_connect(MYSQLND * conn_handle,
if (!conn_handle) {
self_alloced = TRUE;
- if (!(conn_handle = mysqlnd_init(FALSE))) {
+ if (!(conn_handle = mysqlnd_init(client_api_flags, FALSE))) {
/* OOM */
DBG_RETURN(NULL);
}
@@ -2570,6 +2571,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, store_result)(MYSQLND_CONN_DATA * const conn,
if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
do {
+ unsigned int f = flags;
if (!conn->current_result) {
break;
}
@@ -2583,7 +2585,24 @@ MYSQLND_METHOD(mysqlnd_conn_data, store_result)(MYSQLND_CONN_DATA * const conn,
MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_BUFFERED_SETS);
- result = conn->current_result->m.store_result(conn->current_result, conn, 0 TSRMLS_CC);
+ /* overwrite */
+ if ((conn->m->get_client_api_capabilities(conn TSRMLS_CC) & MYSQLND_CLIENT_KNOWS_RSET_COPY_DATA)) {
+ if (MYSQLND_G(fetch_data_copy)) {
+ f &= ~MYSQLND_STORE_NO_COPY;
+ f |= MYSQLND_STORE_COPY;
+ }
+ } else {
+ /* if for some reason PDO borks something */
+ if (!(f & (MYSQLND_STORE_NO_COPY | MYSQLND_STORE_COPY))) {
+ f |= MYSQLND_STORE_COPY;
+ }
+ }
+ if (!(f & (MYSQLND_STORE_NO_COPY | MYSQLND_STORE_COPY))) {
+ SET_CLIENT_ERROR(*conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, "Unknown fetch mode");
+ DBG_ERR("Unknown fetch mode");
+ break;
+ }
+ result = conn->current_result->m.store_result(conn->current_result, conn, f TSRMLS_CC);
if (!result) {
conn->current_result->m.free_result(conn->current_result, TRUE TSRMLS_CC);
}
@@ -2839,6 +2858,32 @@ MYSQLND_METHOD(mysqlnd_conn_data, tx_savepoint_release)(MYSQLND_CONN_DATA * conn
/* }}} */
+/* {{{ mysqlnd_conn_data::negotiate_client_api_capabilities */
+static unsigned int
+MYSQLND_METHOD(mysqlnd_conn_data, negotiate_client_api_capabilities)(MYSQLND_CONN_DATA * const conn, const unsigned int flags TSRMLS_DC)
+{
+ unsigned int ret = 0;
+ DBG_ENTER("mysqlnd_conn_data::negotiate_client_api_capabilities");
+ if (conn) {
+ ret = conn->client_api_capabilities;
+ conn->client_api_capabilities = flags;
+ }
+
+ DBG_RETURN(ret);
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_conn_data::get_client_api_capabilities */
+static unsigned int
+MYSQLND_METHOD(mysqlnd_conn_data, get_client_api_capabilities)(const MYSQLND_CONN_DATA * const conn TSRMLS_DC)
+{
+ DBG_ENTER("mysqlnd_conn_data::get_client_api_capabilities");
+ DBG_RETURN(conn? conn->client_api_capabilities : 0);
+}
+/* }}} */
+
+
/* {{{ mysqlnd_conn_data::local_tx_start */
static enum_func_status
MYSQLND_METHOD(mysqlnd_conn_data, local_tx_start)(MYSQLND_CONN_DATA * conn, size_t this_func TSRMLS_DC)
@@ -2967,7 +3012,10 @@ MYSQLND_CLASS_METHODS_START(mysqlnd_conn_data)
MYSQLND_METHOD(mysqlnd_conn_data, simple_command_send_request),
MYSQLND_METHOD(mysqlnd_conn_data, fetch_auth_plugin_by_name),
- MYSQLND_METHOD(mysqlnd_conn_data, set_client_option_2d)
+ MYSQLND_METHOD(mysqlnd_conn_data, set_client_option_2d),
+
+ MYSQLND_METHOD(mysqlnd_conn_data, negotiate_client_api_capabilities),
+ MYSQLND_METHOD(mysqlnd_conn_data, get_client_api_capabilities)
MYSQLND_CLASS_METHODS_END;
@@ -3046,11 +3094,14 @@ MYSQLND_CLASS_METHODS_END;
/* {{{ _mysqlnd_init */
PHPAPI MYSQLND *
-_mysqlnd_init(zend_bool persistent TSRMLS_DC)
+_mysqlnd_init(unsigned int flags, zend_bool persistent TSRMLS_DC)
{
MYSQLND * ret;
DBG_ENTER("mysqlnd_init");
ret = MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_object_factory).get_connection(persistent TSRMLS_CC);
+ if (ret && ret->data) {
+ ret->data->m->negotiate_client_api_capabilities(ret->data, flags TSRMLS_CC);
+ }
DBG_RETURN(ret);
}
/* }}} */
diff --git a/ext/mysqlnd/mysqlnd.h b/ext/mysqlnd/mysqlnd.h
index 551c5f34ac..f373ea5dd5 100644
--- a/ext/mysqlnd/mysqlnd.h
+++ b/ext/mysqlnd/mysqlnd.h
@@ -85,15 +85,16 @@ PHPAPI const MYSQLND_CHARSET * mysqlnd_find_charset_name(const char * const char
/* Connect */
-#define mysqlnd_init(persistent) _mysqlnd_init((persistent) TSRMLS_CC)
-PHPAPI MYSQLND * _mysqlnd_init(zend_bool persistent TSRMLS_DC);
+#define mysqlnd_init(client_flags, persistent) _mysqlnd_init((client_flags), (persistent) TSRMLS_CC)
+PHPAPI MYSQLND * _mysqlnd_init(unsigned int client_flags, zend_bool persistent TSRMLS_DC);
PHPAPI MYSQLND * mysqlnd_connect(MYSQLND * conn,
const char * host, const char * user,
const char * passwd, unsigned int passwd_len,
const char * db, unsigned int db_len,
unsigned int port,
const char * socket_or_pipe,
- unsigned int mysql_flags
+ unsigned int mysql_flags,
+ unsigned int client_api_flags
TSRMLS_DC);
#define mysqlnd_change_user(conn, user, passwd, db, silent) ((conn)->data)->m->change_user((conn)->data, (user), (passwd), (db), (silent), strlen((passwd)) TSRMLS_CC)
@@ -282,6 +283,7 @@ ZEND_BEGIN_MODULE_GLOBALS(mysqlnd)
long debug_calloc_fail_threshold;
long debug_realloc_fail_threshold;
char * sha256_server_public_key;
+ zend_bool fetch_data_copy;
ZEND_END_MODULE_GLOBALS(mysqlnd)
PHPAPI ZEND_EXTERN_MODULE_GLOBALS(mysqlnd)
diff --git a/ext/mysqlnd/mysqlnd_enum_n_def.h b/ext/mysqlnd/mysqlnd_enum_n_def.h
index d771998577..e1fc5f8f01 100644
--- a/ext/mysqlnd/mysqlnd_enum_n_def.h
+++ b/ext/mysqlnd/mysqlnd_enum_n_def.h
@@ -620,6 +620,16 @@ enum php_mysqlnd_server_command
#define MYSQLND_STORE_NO_COPY 2
#define MYSQLND_STORE_COPY 4
+enum mysqlnd_buffered_type
+{
+ MYSQLND_BUFFERED_TYPE_ZVAL = 1,
+ MYSQLND_BUFFERED_TYPE_C
+};
+
+
+#define MYSQLND_CLIENT_NO_FLAG 0
+#define MYSQLND_CLIENT_KNOWS_RSET_COPY_DATA 1
+
#endif /* MYSQLND_ENUM_N_DEF_H */
diff --git a/ext/mysqlnd/mysqlnd_ext_plugin.c b/ext/mysqlnd/mysqlnd_ext_plugin.c
index 706111346f..13f1e294dc 100644
--- a/ext/mysqlnd/mysqlnd_ext_plugin.c
+++ b/ext/mysqlnd/mysqlnd_ext_plugin.c
@@ -84,14 +84,26 @@ PHPAPI void ** _mysqlnd_plugin_get_plugin_result_unbuffered_data(const MYSQLND_R
/* {{{ _mysqlnd_plugin_get_plugin_result_buffered_data */
-PHPAPI void ** _mysqlnd_plugin_get_plugin_result_buffered_data(const MYSQLND_RES_BUFFERED * result, unsigned int plugin_id TSRMLS_DC)
+PHPAPI void ** _mysqlnd_plugin_get_plugin_result_buffered_data_zval(const MYSQLND_RES_BUFFERED_ZVAL * result, unsigned int plugin_id TSRMLS_DC)
{
DBG_ENTER("_mysqlnd_plugin_get_plugin_result_data");
DBG_INF_FMT("plugin_id=%u", plugin_id);
if (!result || plugin_id >= mysqlnd_plugin_count()) {
return NULL;
}
- DBG_RETURN((void *)((char *)result + sizeof(MYSQLND_RES_BUFFERED) + plugin_id * sizeof(void *)));
+ DBG_RETURN((void *)((char *)result + sizeof(MYSQLND_RES_BUFFERED_ZVAL) + plugin_id * sizeof(void *)));
+}
+/* }}} */
+
+/* {{{ _mysqlnd_plugin_get_plugin_result_buffered_data */
+PHPAPI void ** _mysqlnd_plugin_get_plugin_result_buffered_data_c(const MYSQLND_RES_BUFFERED_C * result, unsigned int plugin_id TSRMLS_DC)
+{
+ DBG_ENTER("_mysqlnd_plugin_get_plugin_result_data");
+ DBG_INF_FMT("plugin_id=%u", plugin_id);
+ if (!result || plugin_id >= mysqlnd_plugin_count()) {
+ return NULL;
+ }
+ DBG_RETURN((void *)((char *)result + sizeof(MYSQLND_RES_BUFFERED_C) + plugin_id * sizeof(void *)));
}
/* }}} */
diff --git a/ext/mysqlnd/mysqlnd_ext_plugin.h b/ext/mysqlnd/mysqlnd_ext_plugin.h
index 6f15eee8ce..d4a9d6cfc0 100644
--- a/ext/mysqlnd/mysqlnd_ext_plugin.h
+++ b/ext/mysqlnd/mysqlnd_ext_plugin.h
@@ -34,9 +34,11 @@ PHPAPI void ** _mysqlnd_plugin_get_plugin_result_data(const MYSQLND_RES * result
PHPAPI void ** _mysqlnd_plugin_get_plugin_result_unbuffered_data(const MYSQLND_RES_UNBUFFERED * result, unsigned int plugin_id TSRMLS_DC);
#define mysqlnd_plugin_get_plugin_result_unbuffered_data(r, p_id) _mysqlnd_plugin_get_plugin_result_unbuffered_data((r), (p_id) TSRMLS_CC)
-PHPAPI void ** _mysqlnd_plugin_get_plugin_result_buffered_data(const MYSQLND_RES_BUFFERED * result, unsigned int plugin_id TSRMLS_DC);
-#define mysqlnd_plugin_get_plugin_result_buffered_data(r, p_id) _mysqlnd_plugin_get_plugin_result_buffered_data((r), (p_id) TSRMLS_CC)
+PHPAPI void ** _mysqlnd_plugin_get_plugin_result_buffered_data_zval(const MYSQLND_RES_BUFFERED_ZVAL * result, unsigned int plugin_id TSRMLS_DC);
+#define mysqlnd_plugin_get_plugin_result_buffered_data_zval(r, p_id) _mysqlnd_plugin_get_plugin_result_buffered_data_zval((r), (p_id) TSRMLS_CC)
+PHPAPI void ** _mysqlnd_plugin_get_plugin_result_buffered_data_c(const MYSQLND_RES_BUFFERED_C * result, unsigned int plugin_id TSRMLS_DC);
+#define mysqlnd_plugin_get_plugin_result_buffered_data_c(r, p_id) _mysqlnd_plugin_get_plugin_result_buffered_data_c((r), (p_id) TSRMLS_CC)
PHPAPI void ** _mysqlnd_plugin_get_plugin_stmt_data(const MYSQLND_STMT * stmt, unsigned int plugin_id TSRMLS_DC);
#define mysqlnd_plugin_get_plugin_stmt_data(s, p_id) _mysqlnd_plugin_get_plugin_stmt_data((s), (p_id) TSRMLS_CC)
diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c
index fc30bddcb5..bee8e1d0ee 100644
--- a/ext/mysqlnd/mysqlnd_ps.c
+++ b/ext/mysqlnd/mysqlnd_ps.c
@@ -89,36 +89,39 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s TSRMLS_DC)
result->type = MYSQLND_RES_PS_BUF;
/* result->m.row_decoder = php_mysqlnd_rowp_read_binary_protocol; */
- result->stored_data = mysqlnd_result_buffered_init(result->field_count, TRUE, result->persistent TSRMLS_CC);
+ result->stored_data = (MYSQLND_RES_BUFFERED *) mysqlnd_result_buffered_zval_init(result->field_count, TRUE, result->persistent TSRMLS_CC);
if (!result->stored_data) {
SET_OOM_ERROR(*conn->error_info);
DBG_RETURN(NULL);
}
- ret = result->m.store_result_fetch_data(conn, result, result->meta, TRUE TSRMLS_CC);
+ ret = result->m.store_result_fetch_data(conn, result, result->meta, &result->stored_data->row_buffers, TRUE TSRMLS_CC);
result->stored_data->m.fetch_row = mysqlnd_stmt_fetch_row_buffered;
if (PASS == ret) {
/* Overflow ? */
- MYSQLND_RES_BUFFERED * set = result->stored_data;
- if (set->row_count) {
- /* don't try to allocate more than possible - mnd_XXalloc expects size_t, and it can have narrower range than uint64_t */
- if (set->row_count * result->meta->field_count * sizeof(zval *) > SIZE_MAX) {
- SET_OOM_ERROR(*conn->error_info);
- DBG_RETURN(NULL);
- }
- /* if pecalloc is used valgrind barks gcc version 4.3.1 20080507 (prerelease) [gcc-4_3-branch revision 135036] (SUSE Linux) */
- set->data = mnd_emalloc((size_t)(set->row_count * result->meta->field_count * sizeof(zval *)));
- if (!set->data) {
- SET_OOM_ERROR(*conn->error_info);
- DBG_RETURN(NULL);
+ if (result->stored_data->type == MYSQLND_BUFFERED_TYPE_ZVAL) {
+ MYSQLND_RES_BUFFERED_ZVAL * set = (MYSQLND_RES_BUFFERED_ZVAL *) result->stored_data;
+ if (result->stored_data->row_count) {
+ /* don't try to allocate more than possible - mnd_XXalloc expects size_t, and it can have narrower range than uint64_t */
+ if (result->stored_data->row_count * result->meta->field_count * sizeof(zval *) > SIZE_MAX) {
+ SET_OOM_ERROR(*conn->error_info);
+ DBG_RETURN(NULL);
+ }
+ /* if pecalloc is used valgrind barks gcc version 4.3.1 20080507 (prerelease) [gcc-4_3-branch revision 135036] (SUSE Linux) */
+ set->data = mnd_emalloc((size_t)(result->stored_data->row_count * result->meta->field_count * sizeof(zval *)));
+ if (!set->data) {
+ SET_OOM_ERROR(*conn->error_info);
+ DBG_RETURN(NULL);
+ }
+ memset(set->data, 0, (size_t)(result->stored_data->row_count * result->meta->field_count * sizeof(zval *)));
}
- memset(set->data, 0, (size_t)(set->row_count * result->meta->field_count * sizeof(zval *)));
+ /* Position at the first row */
+ set->data_cursor = set->data;
+ } else if (result->stored_data->type == MYSQLND_BUFFERED_TYPE_ZVAL) {
+ /*TODO*/
}
- /* Position at the first row */
- set->data_cursor = set->data;
-
/* libmysql API docs say it should be so for SELECT statements */
stmt->upsert_status->affected_rows = stmt->result->stored_data->row_count;
@@ -187,7 +190,7 @@ MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const s TSRMLS_DC)
break;
}
- if ((result = result->m.store_result(result, conn, TRUE TSRMLS_CC))) {
+ if ((result = result->m.store_result(result, conn, MYSQLND_STORE_PS | MYSQLND_STORE_NO_COPY TSRMLS_CC))) {
stmt->upsert_status->affected_rows = result->stored_data->row_count;
stmt->state = MYSQLND_STMT_PREPARED;
result->type = MYSQLND_RES_PS_BUF;
@@ -733,7 +736,6 @@ mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES * result, void * param, unsigned int
{
MYSQLND_STMT * s = (MYSQLND_STMT *) param;
MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
- MYSQLND_RES_BUFFERED *set = result->stored_data;
const MYSQLND_RES_METADATA * const meta = result->meta;
unsigned int field_count = meta->field_count;
@@ -742,81 +744,86 @@ mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES * result, void * param, unsigned int
DBG_INF_FMT("stmt=%lu", stmt != NULL ? stmt->stmt_id : 0L);
/* If we haven't read everything */
- if (set->data_cursor &&
- (set->data_cursor - set->data) < (set->row_count * field_count))
- {
- /* The user could have skipped binding - don't crash*/
- if (stmt->result_bind) {
- unsigned int i;
- zval **current_row = set->data_cursor;
-
- if (NULL == current_row[0]) {
- uint64_t row_num = (set->data_cursor - set->data) / field_count;
- enum_func_status rc = result->stored_data->m.row_decoder(set->row_buffers[row_num],
- current_row,
- meta->field_count,
- meta->fields,
- result->conn->options->int_and_float_native,
- result->conn->stats TSRMLS_CC);
- if (PASS != rc) {
- DBG_RETURN(FAIL);
- }
- set->initialized_rows++;
- if (stmt->update_max_length) {
- for (i = 0; i < result->field_count; i++) {
- /*
- NULL fields are 0 length, 0 is not more than 0
- String of zero size, definitely can't be the next max_length.
- Thus for NULL and zero-length we are quite efficient.
- */
- if (Z_TYPE_P(current_row[i]) >= IS_STRING) {
- unsigned long len = Z_STRLEN_P(current_row[i]);
- if (meta->fields[i].max_length < len) {
- meta->fields[i].max_length = len;
+ if (result->stored_data->type == MYSQLND_BUFFERED_TYPE_ZVAL) {
+ MYSQLND_RES_BUFFERED_ZVAL * set = (MYSQLND_RES_BUFFERED_ZVAL *) result->stored_data;
+ if (set->data_cursor &&
+ (set->data_cursor - set->data) < (result->stored_data->row_count * field_count))
+ {
+ /* The user could have skipped binding - don't crash*/
+ if (stmt->result_bind) {
+ unsigned int i;
+ zval **current_row = set->data_cursor;
+
+ if (NULL == current_row[0]) {
+ uint64_t row_num = (set->data_cursor - set->data) / field_count;
+ enum_func_status rc = result->stored_data->m.row_decoder(result->stored_data->row_buffers[row_num],
+ current_row,
+ meta->field_count,
+ meta->fields,
+ result->conn->options->int_and_float_native,
+ result->conn->stats TSRMLS_CC);
+ if (PASS != rc) {
+ DBG_RETURN(FAIL);
+ }
+ result->stored_data->initialized_rows++;
+ if (stmt->update_max_length) {
+ for (i = 0; i < result->field_count; i++) {
+ /*
+ NULL fields are 0 length, 0 is not more than 0
+ String of zero size, definitely can't be the next max_length.
+ Thus for NULL and zero-length we are quite efficient.
+ */
+ if (Z_TYPE_P(current_row[i]) >= IS_STRING) {
+ unsigned long len = Z_STRLEN_P(current_row[i]);
+ if (meta->fields[i].max_length < len) {
+ meta->fields[i].max_length = len;
+ }
}
}
}
}
- }
- for (i = 0; i < result->field_count; i++) {
- /* Clean what we copied last time */
+ for (i = 0; i < result->field_count; i++) {
+ /* Clean what we copied last time */
#ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
- if (stmt->result_bind[i].zv) {
- zval_dtor(stmt->result_bind[i].zv);
- }
+ if (stmt->result_bind[i].zv) {
+ zval_dtor(stmt->result_bind[i].zv);
+ }
#endif
- /* copy the type */
- if (stmt->result_bind[i].bound == TRUE) {
- DBG_INF_FMT("i=%u type=%u", i, Z_TYPE_P(current_row[i]));
- if (Z_TYPE_P(current_row[i]) != IS_NULL) {
- /*
- Copy the value.
- Pre-condition is that the zvals in the result_bind buffer
- have been ZVAL_NULL()-ed or to another simple type
- (int, double, bool but not string). Because of the reference
- counting the user can't delete the strings the variables point to.
- */
-
- Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(current_row[i]);
- stmt->result_bind[i].zv->value = current_row[i]->value;
+ /* copy the type */
+ if (stmt->result_bind[i].bound == TRUE) {
+ DBG_INF_FMT("i=%u type=%u", i, Z_TYPE_P(current_row[i]));
+ if (Z_TYPE_P(current_row[i]) != IS_NULL) {
+ /*
+ Copy the value.
+ Pre-condition is that the zvals in the result_bind buffer
+ have been ZVAL_NULL()-ed or to another simple type
+ (int, double, bool but not string). Because of the reference
+ counting the user can't delete the strings the variables point to.
+ */
+
+ Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(current_row[i]);
+ stmt->result_bind[i].zv->value = current_row[i]->value;
#ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
- zval_copy_ctor(stmt->result_bind[i].zv);
+ zval_copy_ctor(stmt->result_bind[i].zv);
#endif
- } else {
- ZVAL_NULL(stmt->result_bind[i].zv);
+ } else {
+ ZVAL_NULL(stmt->result_bind[i].zv);
+ }
}
}
}
+ set->data_cursor += field_count;
+ *fetched_anything = TRUE;
+ /* buffered result sets don't have a connection */
+ MYSQLND_INC_GLOBAL_STATISTIC(STAT_ROWS_FETCHED_FROM_CLIENT_PS_BUF);
+ DBG_INF("row fetched");
+ } else {
+ set->data_cursor = NULL;
+ DBG_INF("no more data");
}
- set->data_cursor += field_count;
- *fetched_anything = TRUE;
- /* buffered result sets don't have a connection */
- MYSQLND_INC_GLOBAL_STATISTIC(STAT_ROWS_FETCHED_FROM_CLIENT_PS_BUF);
- DBG_INF("row fetched");
- } else {
- set->data_cursor = NULL;
- DBG_INF("no more data");
+ } else if (result->stored_data->type == MYSQLND_BUFFERED_TYPE_C) {
+ /*TODO*/
}
DBG_INF("PASS");
DBG_RETURN(PASS);
diff --git a/ext/mysqlnd/mysqlnd_result.c b/ext/mysqlnd/mysqlnd_result.c
index fc6f48581c..0112a1394d 100644
--- a/ext/mysqlnd/mysqlnd_result.c
+++ b/ext/mysqlnd/mysqlnd_result.c
@@ -32,29 +32,30 @@
#define MYSQLND_SILENT
-
-/* {{{ mysqlnd_result_buffered::initialize_result_set_rest */
+/* {{{ mysqlnd_result_buffered_zval::initialize_result_set_rest */
static enum_func_status
-MYSQLND_METHOD(mysqlnd_result_buffered, initialize_result_set_rest)(MYSQLND_RES_BUFFERED * const result, MYSQLND_RES_METADATA * const meta,
- MYSQLND_STATS * stats, zend_bool int_and_float_native TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_result_buffered_zval, initialize_result_set_rest)(MYSQLND_RES_BUFFERED * const result, MYSQLND_RES_METADATA * const meta,
+ MYSQLND_STATS * stats, zend_bool int_and_float_native TSRMLS_DC)
{
unsigned int i;
- zval **data_cursor = result->data;
- zval **data_begin = result->data;
- unsigned int field_count = meta->field_count;
- uint64_t row_count = result->row_count;
enum_func_status ret = PASS;
- DBG_ENTER("mysqlnd_result_buffered::initialize_result_set_rest");
+ const unsigned int field_count = meta->field_count;
+ const uint64_t row_count = result->row_count;
+ enum_func_status rc;
+
+ zval **data_begin = ((MYSQLND_RES_BUFFERED_ZVAL *) result)->data;
+ zval **data_cursor = data_begin;
+
+ DBG_ENTER("mysqlnd_result_buffered_zval::initialize_result_set_rest");
if (!data_cursor || row_count == result->initialized_rows) {
DBG_RETURN(ret);
}
while ((data_cursor - data_begin) < (int)(row_count * field_count)) {
if (NULL == data_cursor[0]) {
- enum_func_status rc = result->m.row_decoder(
- result->row_buffers[(data_cursor - data_begin) / field_count],
+ rc = result->m.row_decoder(result->row_buffers[(data_cursor - data_begin) / field_count],
data_cursor,
- meta->field_count,
+ field_count,
meta->fields,
int_and_float_native,
stats TSRMLS_CC);
@@ -63,7 +64,7 @@ MYSQLND_METHOD(mysqlnd_result_buffered, initialize_result_set_rest)(MYSQLND_RES_
break;
}
result->initialized_rows++;
- for (i = 0; i < meta->field_count; i++) {
+ for (i = 0; i < field_count; i++) {
/*
NULL fields are 0 length, 0 is not more than 0
String of zero size, definitely can't be the next max_length.
@@ -84,6 +85,62 @@ MYSQLND_METHOD(mysqlnd_result_buffered, initialize_result_set_rest)(MYSQLND_RES_
/* }}} */
+/* {{{ mysqlnd_result_buffered_c::initialize_result_set_rest */
+static enum_func_status
+MYSQLND_METHOD(mysqlnd_result_buffered_c, initialize_result_set_rest)(MYSQLND_RES_BUFFERED * const result, MYSQLND_RES_METADATA * const meta,
+ MYSQLND_STATS * stats, zend_bool int_and_float_native TSRMLS_DC)
+{
+ unsigned int i;
+ enum_func_status ret = PASS;
+ const unsigned int field_count = meta->field_count;
+ const uint64_t row_count = result->row_count;
+ enum_func_status rc;
+ DBG_ENTER("mysqlnd_result_buffered_c::initialize_result_set_rest");
+
+ if (result->initialized_rows < row_count) {
+ zend_uchar * initialized = ((MYSQLND_RES_BUFFERED_C *) result)->initialized;
+ zval ** current_row = mnd_emalloc(field_count * sizeof(zval *));
+
+ if (!current_row) {
+ DBG_RETURN(FAIL);
+ }
+
+ for (i = 0; i < result->row_count; i++) {
+ /* (i / 8) & the_bit_for_i*/
+ if (initialized[i >> 3] & (1 << (i & 7))) {
+ continue;
+ }
+
+ rc = result->m.row_decoder(result->row_buffers[i], current_row, field_count, meta->fields, int_and_float_native, stats TSRMLS_CC);
+
+ if (rc != PASS) {
+ ret = FAIL;
+ break;
+ }
+ result->initialized_rows++;
+ initialized[i >> 3] |= (1 << (i & 7));
+ for (i = 0; i < field_count; i++) {
+ /*
+ NULL fields are 0 length, 0 is not more than 0
+ String of zero size, definitely can't be the next max_length.
+ Thus for NULL and zero-length we are quite efficient.
+ */
+ if (Z_TYPE_P(current_row[i]) >= IS_STRING) {
+ unsigned long len = Z_STRLEN_P(current_row[i]);
+ if (meta->fields[i].max_length < len) {
+ meta->fields[i].max_length = len;
+ }
+ }
+ zval_ptr_dtor(&current_row[i]);
+ }
+ }
+ mnd_efree(current_row);
+ }
+ DBG_RETURN(ret);
+}
+/* }}} */
+
+
/* {{{ mysqlnd_rset_zval_ptr_dtor */
static void
mysqlnd_rset_zval_ptr_dtor(zval **zv, enum_mysqlnd_res_type type, zend_bool * copy_ctor_called TSRMLS_DC)
@@ -205,25 +262,23 @@ MYSQLND_METHOD(mysqlnd_result_unbuffered, free_result)(MYSQLND_RES_UNBUFFERED *
/* }}} */
-/* {{{ mysqlnd_result_buffered::free_result */
+/* {{{ mysqlnd_result_buffered_zval::free_result */
static void
-MYSQLND_METHOD(mysqlnd_result_buffered, free_result)(MYSQLND_RES_BUFFERED * const set TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_result_buffered_zval, free_result)(MYSQLND_RES_BUFFERED_ZVAL * const set TSRMLS_DC)
{
- unsigned int field_count = set->field_count;
- int64_t row;
+ zval ** data = set->data;
- DBG_ENTER("mysqlnd_res::free_buffered_data");
- DBG_INF_FMT("Freeing "MYSQLND_LLU_SPEC" row(s)", set->row_count);
+ DBG_ENTER("mysqlnd_result_buffered_zval::free_result");
- if (set->data) {
+ set->data = NULL; /* prevent double free if following loop is interrupted */
+ if (data) {
unsigned int copy_on_write_performed = 0;
unsigned int copy_on_write_saved = 0;
- zval **data = set->data;
- set->data = NULL; /* prevent double free if following loop is interrupted */
-
+ unsigned int field_count = set->field_count;
+ int64_t row;
+
for (row = set->row_count - 1; row >= 0; row--) {
zval **current_row = data + row * field_count;
- MYSQLND_MEMORY_POOL_CHUNK *current_buffer = set->row_buffers[row];
int64_t col;
if (current_row != NULL) {
@@ -239,13 +294,48 @@ MYSQLND_METHOD(mysqlnd_result_buffered, free_result)(MYSQLND_RES_BUFFERED * cons
}
}
}
- current_buffer->free_chunk(current_buffer TSRMLS_CC);
}
-
MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_COPY_ON_WRITE_PERFORMED, copy_on_write_performed,
STAT_COPY_ON_WRITE_SAVED, copy_on_write_saved);
mnd_efree(data);
}
+ set->data_cursor = NULL;
+ DBG_VOID_RETURN;
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_result_buffered_c::free_result */
+static void
+MYSQLND_METHOD(mysqlnd_result_buffered_c, free_result)(MYSQLND_RES_BUFFERED_C * const set TSRMLS_DC)
+{
+ DBG_ENTER("mysqlnd_result_buffered_c::free_result");
+ mnd_pefree(set->initialized, set->persistent);
+ set->initialized = NULL;
+ DBG_VOID_RETURN;
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_result_buffered::free_result */
+static void
+MYSQLND_METHOD(mysqlnd_result_buffered, free_result)(MYSQLND_RES_BUFFERED * const set TSRMLS_DC)
+{
+ int64_t row;
+
+ DBG_ENTER("mysqlnd_result_buffered::free_result");
+ DBG_INF_FMT("Freeing "MYSQLND_LLU_SPEC" row(s)", set->row_count);
+
+ if (set->type == MYSQLND_BUFFERED_TYPE_ZVAL) {
+ MYSQLND_METHOD(mysqlnd_result_buffered_zval, free_result)((MYSQLND_RES_BUFFERED_ZVAL *) set TSRMLS_CC);
+ } if (set->type == MYSQLND_BUFFERED_TYPE_C) {
+ MYSQLND_METHOD(mysqlnd_result_buffered_c, free_result)((MYSQLND_RES_BUFFERED_C *) set TSRMLS_CC);
+ }
+
+ for (row = set->row_count - 1; row >= 0; row--) {
+ MYSQLND_MEMORY_POOL_CHUNK *current_buffer = set->row_buffers[row];
+ current_buffer->free_chunk(current_buffer TSRMLS_CC);
+ }
if (set->lengths) {
mnd_pefree(set->lengths, set->persistent);
@@ -253,8 +343,8 @@ MYSQLND_METHOD(mysqlnd_result_buffered, free_result)(MYSQLND_RES_BUFFERED * cons
}
if (set->row_buffers) {
- mnd_efree(set->row_buffers);
- set->row_buffers = NULL;
+ mnd_pefree(set->row_buffers, 0);
+ set->row_buffers = NULL;
}
if (set->result_set_memory_pool) {
@@ -263,7 +353,6 @@ MYSQLND_METHOD(mysqlnd_result_buffered, free_result)(MYSQLND_RES_BUFFERED * cons
}
- set->data_cursor = NULL;
set->row_count = 0;
mnd_pefree(set, set->persistent);
@@ -590,31 +679,49 @@ mysqlnd_query_read_result_set_header(MYSQLND_CONN_DATA * conn, MYSQLND_STMT * s
completeness.
*/
static unsigned long *
-MYSQLND_METHOD(mysqlnd_result_buffered, fetch_lengths)(MYSQLND_RES_BUFFERED * const result TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_result_buffered_zval, fetch_lengths)(MYSQLND_RES_BUFFERED * const result TSRMLS_DC)
{
- unsigned int i;
- zval **previous_row;
- MYSQLND_RES_BUFFERED *set = result;
-
+ const MYSQLND_RES_BUFFERED_ZVAL * set = (MYSQLND_RES_BUFFERED_ZVAL *) result;
/*
If:
- unbuffered result
- first row has not been read
- last_row has been read
*/
+ DBG_ENTER("mysqlnd_result_buffered_zval::fetch_lengths");
+
if (set->data_cursor == NULL ||
set->data_cursor == set->data ||
- ((set->data_cursor - set->data) > (set->row_count * result->field_count) ))
+ ((set->data_cursor - set->data) > (result->row_count * result->field_count) ))
{
- return NULL;/* No rows or no more rows */
+ DBG_INF("EOF");
+ DBG_RETURN(NULL);/* No rows or no more rows */
}
+ DBG_INF("non NULL");
+ DBG_RETURN(result->lengths);
+}
+/* }}} */
- previous_row = set->data_cursor - result->field_count;
- for (i = 0; i < result->field_count; i++) {
- result->lengths[i] = (Z_TYPE_P(previous_row[i]) == IS_NULL)? 0:Z_STRLEN_P(previous_row[i]);
- }
- return result->lengths;
+/* {{{ mysqlnd_result_buffered_c::fetch_lengths */
+/*
+ Do lazy initialization for buffered results. As PHP strings have
+ length inside, this function makes not much sense in the context
+ of PHP, to be called as separate function. But let's have it for
+ completeness.
+*/
+static unsigned long *
+MYSQLND_METHOD(mysqlnd_result_buffered_c, fetch_lengths)(MYSQLND_RES_BUFFERED * const result TSRMLS_DC)
+{
+ const MYSQLND_RES_BUFFERED_C * set = (MYSQLND_RES_BUFFERED_C *) result;
+ DBG_ENTER("mysqlnd_result_buffered_c::fetch_lengths");
+
+ if (set->current_row > set->row_count || set->current_row == 0) {
+ DBG_INF("EOF");
+ DBG_RETURN(NULL); /* No more rows, or no fetched row */
+ }
+ DBG_INF("non NULL");
+ DBG_RETURN(result->lengths);
}
/* }}} */
@@ -767,7 +874,7 @@ MYSQLND_METHOD(mysqlnd_result_unbuffered, fetch_row_c)(MYSQLND_RES * result, voi
/* {{{ mysqlnd_result_unbuffered::fetch_row */
static enum_func_status
-MYSQLND_METHOD(mysqlnd_result_unbuffered, fetch_row)(MYSQLND_RES * result, void * param, unsigned int flags, zend_bool * fetched_anything TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_result_unbuffered, fetch_row)(MYSQLND_RES * result, void * param, const unsigned int flags, zend_bool * fetched_anything TSRMLS_DC)
{
enum_func_status ret;
zval *row = (zval *) param;
@@ -944,20 +1051,111 @@ static enum_func_status
MYSQLND_METHOD(mysqlnd_result_buffered, fetch_row_c)(MYSQLND_RES * result, void * param, unsigned int flags, zend_bool * fetched_anything TSRMLS_DC)
{
MYSQLND_ROW_C * row = (MYSQLND_ROW_C *) param;
- MYSQLND_RES_BUFFERED * set = result->stored_data;
const MYSQLND_RES_METADATA * const meta = result->meta;
unsigned int field_count = meta->field_count;
enum_func_status ret = FAIL;
-
DBG_ENTER("mysqlnd_result_buffered::fetch_row_c");
+ if (result->stored_data->type == MYSQLND_BUFFERED_TYPE_ZVAL) {
+ MYSQLND_RES_BUFFERED_ZVAL * set = (MYSQLND_RES_BUFFERED_ZVAL *) result->stored_data;
+
+ /* If we haven't read everything */
+ if (set->data_cursor &&
+ (set->data_cursor - set->data) < (result->stored_data->row_count * field_count))
+ {
+ zval **current_row = set->data_cursor;
+ unsigned int i;
+
+ if (NULL == current_row[0]) {
+ uint64_t row_num = (set->data_cursor - set->data) / field_count;
+ enum_func_status rc = set->m.row_decoder(set->row_buffers[row_num],
+ current_row,
+ field_count,
+ meta->fields,
+ result->conn->options->int_and_float_native,
+ result->conn->stats TSRMLS_CC);
+ if (rc != PASS) {
+ DBG_RETURN(FAIL);
+ }
+ set->initialized_rows++;
+ for (i = 0; i < field_count; i++) {
+ /*
+ NULL fields are 0 length, 0 is not more than 0
+ String of zero size, definitely can't be the next max_length.
+ Thus for NULL and zero-length we are quite efficient.
+ */
+ if (Z_TYPE_P(current_row[i]) >= IS_STRING) {
+ unsigned long len = Z_STRLEN_P(current_row[i]);
+ if (meta->fields[i].max_length < len) {
+ meta->fields[i].max_length = len;
+ }
+ }
+ }
+ }
+
+/* BEGIN difference between normal normal fetch and _c */
+ /* there is no conn handle in this function thus we can't set OOM in error_info */
+ *row = mnd_malloc(field_count * sizeof(char *));
+ if (*row) {
+ for (i = 0; i < field_count; i++) {
+ zval * data = current_row[i];
+
+ set->lengths[i] = (Z_TYPE_P(data) == IS_NULL)? 0:Z_STRLEN_P(data);
+
+ if (Z_TYPE_P(data) != IS_NULL) {
+ convert_to_string(data);
+ (*row)[i] = Z_STRVAL_P(data);
+ } else {
+ (*row)[i] = NULL;
+ }
+ }
+ set->data_cursor += field_count;
+ MYSQLND_INC_GLOBAL_STATISTIC(STAT_ROWS_FETCHED_FROM_CLIENT_NORMAL_BUF);
+ } else {
+ SET_OOM_ERROR(*result->conn->error_info);
+ }
+/* END difference between normal normal fetch and _c */
+
+ *fetched_anything = *row? TRUE:FALSE;
+ ret = *row? PASS:FAIL;
+ } else {
+ set->data_cursor = NULL;
+ DBG_INF("EOF reached");
+ *fetched_anything = FALSE;
+ ret = PASS;
+ }
+ } else if (result->stored_data->type == MYSQLND_BUFFERED_TYPE_C) {
+ /*
+ We don't support _C with pdo because it uses the data in a different way - just references it.
+ We will either leak or give nirvana pointers
+ */
+ *fetched_anything = FALSE;
+ DBG_RETURN(FAIL);
+ }
+ DBG_INF_FMT("ret=PASS fetched=%u", *fetched_anything);
+ DBG_RETURN(ret);
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_result_buffered_zval::fetch_row */
+static enum_func_status
+MYSQLND_METHOD(mysqlnd_result_buffered_zval, fetch_row)(MYSQLND_RES * result, void * param, const unsigned int flags, zend_bool * fetched_anything TSRMLS_DC)
+{
+ zval * row = (zval *) param;
+ const MYSQLND_RES_METADATA * const meta = result->meta;
+ unsigned int field_count = meta->field_count;
+ enum_func_status ret = FAIL;
+ MYSQLND_RES_BUFFERED_ZVAL * set = (MYSQLND_RES_BUFFERED_ZVAL *) result->stored_data;
+
+ DBG_ENTER("mysqlnd_result_buffered_zval::fetch_row");
+
/* If we haven't read everything */
if (set->data_cursor &&
(set->data_cursor - set->data) < (set->row_count * field_count))
{
- zval **current_row = set->data_cursor;
- MYSQLND_FIELD * field = meta->fields;
unsigned int i;
+ zval **current_row = set->data_cursor;
if (NULL == current_row[0]) {
uint64_t row_num = (set->data_cursor - set->data) / field_count;
@@ -979,30 +1177,44 @@ MYSQLND_METHOD(mysqlnd_result_buffered, fetch_row_c)(MYSQLND_RES * result, void
*/
if (Z_TYPE_P(current_row[i]) >= IS_STRING) {
unsigned long len = Z_STRLEN_P(current_row[i]);
- if (field->max_length < len) {
- field->max_length = len;
+ if (meta->fields[i].max_length < len) {
+ meta->fields[i].max_length = len;
}
}
}
}
-/* BEGIN difference between normal normal fetch and _c */
- /* there is no conn handle in this function thus we can't set OOM in error_info */
- *row = mnd_malloc(field_count * sizeof(char *));
- if (ret) {
- for (i = 0; i < field_count; i++) {
- zval * data = current_row[i];
+ for (i = 0; i < field_count; i++) {
+ zval * data = current_row[i];
- if (Z_TYPE_P(data) != IS_NULL) {
- convert_to_string(data);
- (*row)[i] = Z_STRVAL_P(data);
+ set->lengths[i] = (Z_TYPE_P(data) == IS_NULL)? 0:Z_STRLEN_P(data);
+
+ if (flags & MYSQLND_FETCH_NUM) {
+ Z_ADDREF_P(data);
+ zend_hash_next_index_insert(Z_ARRVAL_P(row), &data, sizeof(zval *), NULL);
+ }
+ if (flags & MYSQLND_FETCH_ASSOC) {
+ /* zend_hash_quick_update needs length + trailing zero */
+ /* QQ: Error handling ? */
+ /*
+ zend_hash_quick_update does not check, as add_assoc_zval_ex do, whether
+ the index is a numeric and convert it to it. This however means constant
+ hashing of the column name, which is not needed as it can be precomputed.
+ */
+ Z_ADDREF_P(data);
+ if (meta->zend_hash_keys[i].is_numeric == FALSE) {
+ zend_hash_quick_update(Z_ARRVAL_P(row),
+ meta->fields[i].name,
+ meta->fields[i].name_length + 1,
+ meta->zend_hash_keys[i].key,
+ (void *) &data, sizeof(zval *), NULL);
} else {
- (*row)[i] = NULL;
+ zend_hash_index_update(Z_ARRVAL_P(row),
+ meta->zend_hash_keys[i].key,
+ (void *) &data, sizeof(zval *), NULL);
}
}
}
-/* END difference between normal normal fetch and _c */
-
set->data_cursor += field_count;
MYSQLND_INC_GLOBAL_STATISTIC(STAT_ROWS_FETCHED_FROM_CLIENT_NORMAL_BUF);
*fetched_anything = TRUE;
@@ -1019,38 +1231,45 @@ MYSQLND_METHOD(mysqlnd_result_buffered, fetch_row_c)(MYSQLND_RES * result, void
/* }}} */
-/* {{{ mysqlnd_result_buffered::fetch_row */
+/* {{{ mysqlnd_result_buffered_c::fetch_row */
static enum_func_status
-MYSQLND_METHOD(mysqlnd_result_buffered, fetch_row)(MYSQLND_RES * result, void * param, unsigned int flags, zend_bool * fetched_anything TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_result_buffered_c, fetch_row)(MYSQLND_RES * result, void * param, const unsigned int flags, zend_bool * fetched_anything TSRMLS_DC)
{
zval * row = (zval *) param;
- MYSQLND_RES_BUFFERED * set = result->stored_data;
const MYSQLND_RES_METADATA * const meta = result->meta;
unsigned int field_count = meta->field_count;
enum_func_status ret = FAIL;
- DBG_ENTER("mysqlnd_result_buffered::fetch_row");
+ MYSQLND_RES_BUFFERED_C * set = (MYSQLND_RES_BUFFERED_C *) result->stored_data;
+
+ DBG_ENTER("mysqlnd_result_buffered_c::fetch_row");
/* If we haven't read everything */
- if (set->data_cursor &&
- (set->data_cursor - set->data) < (set->row_count * field_count))
- {
- zval **current_row = set->data_cursor;
- MYSQLND_FIELD * field = meta->fields;
+ if (set->current_row < set->row_count) {
+ zval **current_row;
+ enum_func_status rc;
unsigned int i;
- if (NULL == current_row[0]) {
- uint64_t row_num = (set->data_cursor - set->data) / field_count;
- enum_func_status rc = set->m.row_decoder(set->row_buffers[row_num],
- current_row,
- field_count,
- meta->fields,
- result->conn->options->int_and_float_native,
- result->conn->stats TSRMLS_CC);
- if (rc != PASS) {
- DBG_RETURN(FAIL);
- }
+ current_row = mnd_emalloc(field_count * sizeof(zval *));
+ if (!current_row) {
+ SET_OOM_ERROR(*result->conn->error_info);
+ DBG_RETURN(FAIL);
+ }
+
+ rc = result->stored_data->m.row_decoder(result->stored_data->row_buffers[set->current_row],
+ current_row,
+ field_count,
+ meta->fields,
+ result->conn->options->int_and_float_native,
+ result->conn->stats TSRMLS_CC);
+ if (rc != PASS) {
+ DBG_RETURN(FAIL);
+ }
+ if (!(set->initialized[set->current_row >> 3] & (1 << (set->current_row & 7)))) {
+ set->initialized[set->current_row >> 3] |= (1 << (set->current_row & 7)); /* mark initialized */
+
set->initialized_rows++;
+
for (i = 0; i < field_count; i++) {
/*
NULL fields are 0 length, 0 is not more than 0
@@ -1059,16 +1278,18 @@ MYSQLND_METHOD(mysqlnd_result_buffered, fetch_row)(MYSQLND_RES * result, void *
*/
if (Z_TYPE_P(current_row[i]) >= IS_STRING) {
unsigned long len = Z_STRLEN_P(current_row[i]);
- if (field->max_length < len) {
- field->max_length = len;
+ if (meta->fields[i].max_length < len) {
+ meta->fields[i].max_length = len;
}
}
}
}
- for (i = 0; i < field_count; i++, field++) {
+ for (i = 0; i < field_count; i++) {
zval * data = current_row[i];
+ set->lengths[i] = (Z_TYPE_P(data) == IS_NULL)? 0:Z_STRLEN_P(data);
+
if (flags & MYSQLND_FETCH_NUM) {
Z_ADDREF_P(data);
zend_hash_next_index_insert(Z_ARRVAL_P(row), &data, sizeof(zval *), NULL);
@@ -1084,8 +1305,8 @@ MYSQLND_METHOD(mysqlnd_result_buffered, fetch_row)(MYSQLND_RES * result, void *
Z_ADDREF_P(data);
if (meta->zend_hash_keys[i].is_numeric == FALSE) {
zend_hash_quick_update(Z_ARRVAL_P(row),
- field->name,
- field->name_length + 1,
+ meta->fields[i].name,
+ meta->fields[i].name_length + 1,
meta->zend_hash_keys[i].key,
(void *) &data, sizeof(zval *), NULL);
} else {
@@ -1094,17 +1315,28 @@ MYSQLND_METHOD(mysqlnd_result_buffered, fetch_row)(MYSQLND_RES * result, void *
(void *) &data, sizeof(zval *), NULL);
}
}
+ /*
+ This will usually not destroy anything but decref.
+ However, if neither NUM nor ASSOC is set we will free memory cleanly and won't leak.
+ It also simplifies the handling of Z_ADDREF_P because we don't need to check if only
+ either NUM or ASSOC is set but not both.
+ */
+ zval_ptr_dtor(&data);
}
- set->data_cursor += field_count;
+ mnd_efree(current_row);
+ set->current_row++;
MYSQLND_INC_GLOBAL_STATISTIC(STAT_ROWS_FETCHED_FROM_CLIENT_NORMAL_BUF);
*fetched_anything = TRUE;
ret = PASS;
} else {
- set->data_cursor = NULL;
- DBG_INF("EOF reached");
+ if (set->current_row == set->row_count) {
+ set->current_row = set->row_count + 1;
+ }
+ DBG_INF_FMT("EOF reached. current_row=%llu", (unsigned long long) set->current_row);
*fetched_anything = FALSE;
ret = PASS;
}
+
DBG_INF_FMT("ret=PASS fetched=%u", *fetched_anything);
DBG_RETURN(ret);
}
@@ -1113,7 +1345,7 @@ MYSQLND_METHOD(mysqlnd_result_buffered, fetch_row)(MYSQLND_RES * result, void *
/* {{{ mysqlnd_res::fetch_row */
static enum_func_status
-MYSQLND_METHOD(mysqlnd_res, fetch_row)(MYSQLND_RES * result, void * param, unsigned int flags, zend_bool *fetched_anything TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_res, fetch_row)(MYSQLND_RES * result, void * param, const unsigned int flags, zend_bool *fetched_anything TSRMLS_DC)
{
const mysqlnd_fetch_row_func f = result->stored_data? result->stored_data->m.fetch_row:(result->unbuf? result->unbuf->m.fetch_row:NULL);
if (f) {
@@ -1131,6 +1363,7 @@ MYSQLND_METHOD(mysqlnd_res, fetch_row)(MYSQLND_RES * result, void * param, unsig
enum_func_status
MYSQLND_METHOD(mysqlnd_res, store_result_fetch_data)(MYSQLND_CONN_DATA * const conn, MYSQLND_RES * result,
MYSQLND_RES_METADATA * meta,
+ MYSQLND_MEMORY_POOL_CHUNK ***row_buffers,
zend_bool binary_protocol TSRMLS_DC)
{
enum_func_status ret;
@@ -1142,13 +1375,13 @@ MYSQLND_METHOD(mysqlnd_res, store_result_fetch_data)(MYSQLND_CONN_DATA * const c
set = result->stored_data;
- if (!set) {
+ if (!set || !row_buffers) {
ret = FAIL;
goto end;
}
if (free_rows) {
- set->row_buffers = mnd_emalloc((size_t)(free_rows * sizeof(MYSQLND_MEMORY_POOL_CHUNK *)));
- if (!set->row_buffers) {
+ *row_buffers = mnd_pemalloc((size_t)(free_rows * sizeof(MYSQLND_MEMORY_POOL_CHUNK *)), 0);
+ if (!*row_buffers) {
SET_OOM_ERROR(*conn->error_info);
ret = FAIL;
goto end;
@@ -1184,16 +1417,16 @@ MYSQLND_METHOD(mysqlnd_res, store_result_fetch_data)(MYSQLND_CONN_DATA * const c
ret = FAIL;
goto end;
}
- new_row_buffers = mnd_erealloc(set->row_buffers, (size_t)(total_allocated_rows * sizeof(MYSQLND_MEMORY_POOL_CHUNK *)));
+ new_row_buffers = mnd_perealloc(*row_buffers, (size_t)(total_allocated_rows * sizeof(MYSQLND_MEMORY_POOL_CHUNK *)), 0);
if (!new_row_buffers) {
SET_OOM_ERROR(*conn->error_info);
ret = FAIL;
goto end;
}
- set->row_buffers = new_row_buffers;
+ *row_buffers = new_row_buffers;
}
free_rows--;
- set->row_buffers[set->row_count] = row_packet->row_buffer;
+ (*row_buffers)[set->row_count] = row_packet->row_buffer;
set->row_count++;
@@ -1228,7 +1461,7 @@ MYSQLND_METHOD(mysqlnd_res, store_result_fetch_data)(MYSQLND_CONN_DATA * const c
ret = FAIL;
goto end;
}
- set->row_buffers = mnd_erealloc(set->row_buffers, (size_t) (set->row_count * sizeof(MYSQLND_MEMORY_POOL_CHUNK *)));
+ *row_buffers = mnd_perealloc(*row_buffers, (size_t) (set->row_count * sizeof(MYSQLND_MEMORY_POOL_CHUNK *)), 0);
}
if (conn->upsert_status->server_status & SERVER_MORE_RESULTS_EXISTS) {
@@ -1247,7 +1480,7 @@ MYSQLND_METHOD(mysqlnd_res, store_result_fetch_data)(MYSQLND_CONN_DATA * const c
ret == PASS? "PASS":"FAIL", (uint) set->row_count, conn->upsert_status->warning_count, conn->upsert_status->server_status);
end:
PACKET_FREE(row_packet);
-
+ DBG_INF_FMT("rows=%llu", (unsigned long long)result->stored_data->row_count);
DBG_RETURN(ret);
}
/* }}} */
@@ -1260,6 +1493,7 @@ MYSQLND_METHOD(mysqlnd_res, store_result)(MYSQLND_RES * result,
const unsigned int flags TSRMLS_DC)
{
enum_func_status ret;
+ MYSQLND_MEMORY_POOL_CHUNK ***row_buffers = NULL;
DBG_ENTER("mysqlnd_res::store_result");
@@ -1270,13 +1504,23 @@ MYSQLND_METHOD(mysqlnd_res, store_result)(MYSQLND_RES * result,
CONN_SET_STATE(conn, CONN_FETCHING_DATA);
- result->stored_data = mysqlnd_result_buffered_init(result->field_count, flags & MYSQLND_STORE_PS, result->persistent TSRMLS_CC);
- if (!result->stored_data) {
- SET_OOM_ERROR(*conn->error_info);
- DBG_RETURN(NULL);
+ if (flags & MYSQLND_STORE_NO_COPY) {
+ result->stored_data = (MYSQLND_RES_BUFFERED *) mysqlnd_result_buffered_zval_init(result->field_count, flags & MYSQLND_STORE_PS, result->persistent TSRMLS_CC);
+ if (!result->stored_data) {
+ SET_OOM_ERROR(*conn->error_info);
+ DBG_RETURN(NULL);
+ }
+ row_buffers = &result->stored_data->row_buffers;
+ } else if (flags & MYSQLND_STORE_COPY) {
+ result->stored_data = (MYSQLND_RES_BUFFERED *) mysqlnd_result_buffered_c_init(result->field_count, flags & MYSQLND_STORE_PS, result->persistent TSRMLS_CC);
+ if (!result->stored_data) {
+ SET_OOM_ERROR(*conn->error_info);
+ DBG_RETURN(NULL);
+ }
+ row_buffers = &result->stored_data->row_buffers;
}
+ ret = result->m.store_result_fetch_data(conn, result, result->meta, row_buffers, flags & MYSQLND_STORE_PS TSRMLS_CC);
- ret = result->m.store_result_fetch_data(conn, result, result->meta, flags & MYSQLND_STORE_PS TSRMLS_CC);
if (FAIL == ret) {
if (result->stored_data) {
COPY_CLIENT_ERROR(*conn->error_info, result->stored_data->error_info);
@@ -1286,24 +1530,30 @@ MYSQLND_METHOD(mysqlnd_res, store_result)(MYSQLND_RES * result,
DBG_RETURN(NULL);
} else {
/* Overflow ? */
- MYSQLND_RES_METADATA * meta = result->meta;
- MYSQLND_RES_BUFFERED * set = result->stored_data;
- if (set->row_count) {
- /* don't try to allocate more than possible - mnd_XXalloc expects size_t, and it can have narrower range than uint64_t */
- if (set->row_count * meta->field_count * sizeof(zval *) > SIZE_MAX) {
- SET_OOM_ERROR(*conn->error_info);
- DBG_RETURN(NULL);
- }
- /* if pecalloc is used valgrind barks gcc version 4.3.1 20080507 (prerelease) [gcc-4_3-branch revision 135036] (SUSE Linux) */
- set->data = mnd_emalloc((size_t)(set->row_count * meta->field_count * sizeof(zval *)));
- if (!set->data) {
- SET_OOM_ERROR(*conn->error_info);
- DBG_RETURN(NULL);
+ if (flags & MYSQLND_STORE_NO_COPY) {
+ MYSQLND_RES_METADATA * meta = result->meta;
+ MYSQLND_RES_BUFFERED_ZVAL * set = (MYSQLND_RES_BUFFERED_ZVAL *) result->stored_data;
+ if (set->row_count) {
+ /* don't try to allocate more than possible - mnd_XXalloc expects size_t, and it can have narrower range than uint64_t */
+ if (set->row_count * meta->field_count * sizeof(zval *) > SIZE_MAX) {
+ SET_OOM_ERROR(*conn->error_info);
+ DBG_RETURN(NULL);
+ }
+ /* if pecalloc is used valgrind barks gcc version 4.3.1 20080507 (prerelease) [gcc-4_3-branch revision 135036] (SUSE Linux) */
+ set->data = mnd_emalloc((size_t)(set->row_count * meta->field_count * sizeof(zval *)));
+ if (!set->data) {
+ SET_OOM_ERROR(*conn->error_info);
+ DBG_RETURN(NULL);
+ }
+ memset(set->data, 0, (size_t)(set->row_count * meta->field_count * sizeof(zval *)));
}
- memset(set->data, 0, (size_t)(set->row_count * meta->field_count * sizeof(zval *)));
+ /* Position at the first row */
+ set->data_cursor = set->data;
+ } else if (flags & MYSQLND_STORE_COPY) {
+ MYSQLND_RES_BUFFERED_C * set = (MYSQLND_RES_BUFFERED_C *) result->stored_data;
+ set->current_row = 0;
+ set->initialized = mnd_pecalloc((set->row_count / 8) + 1, sizeof(zend_uchar), set->persistent); /* +1 for safety */
}
- /* Position at the first row */
- set->data_cursor = set->data;
}
/* libmysql's documentation says it should be so for SELECT statements */
@@ -1370,19 +1620,37 @@ MYSQLND_METHOD(mysqlnd_res, data_seek)(MYSQLND_RES * const result, const uint64_
/* }}} */
-/* {{{ mysqlnd_result_buffered::data_seek */
+/* {{{ mysqlnd_result_buffered_zval::data_seek */
static enum_func_status
-MYSQLND_METHOD(mysqlnd_result_buffered, data_seek)(MYSQLND_RES_BUFFERED * const result, const uint64_t row TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_result_buffered_zval, data_seek)(MYSQLND_RES_BUFFERED * const result, const uint64_t row TSRMLS_DC)
{
- DBG_ENTER("mysqlnd_result_buffered::data_seek");
+ MYSQLND_RES_BUFFERED_ZVAL * set = (MYSQLND_RES_BUFFERED_ZVAL *) result;
+ DBG_ENTER("mysqlnd_result_buffered_zval::data_seek");
/* libmysql just moves to the end, it does traversing of a linked list */
- if (row >= result->row_count) {
- result->data_cursor = NULL;
+ if (row >= set->row_count) {
+ set->data_cursor = NULL;
} else {
- result->data_cursor = result->data + row * result->field_count;
+ set->data_cursor = set->data + row * result->field_count;
}
+ DBG_RETURN(PASS);
+}
+/* }}} */
+
+/* {{{ mysqlnd_result_buffered_c::data_seek */
+static enum_func_status
+MYSQLND_METHOD(mysqlnd_result_buffered_c, data_seek)(MYSQLND_RES_BUFFERED * const result, const uint64_t row TSRMLS_DC)
+{
+ MYSQLND_RES_BUFFERED_C * set = (MYSQLND_RES_BUFFERED_C *) result;
+ DBG_ENTER("mysqlnd_result_buffered_c::data_seek");
+
+ /* libmysql just moves to the end, it does traversing of a linked list */
+ if (row >= set->row_count) {
+ set->current_row = set->row_count;
+ } else {
+ set->current_row = row;
+ }
DBG_RETURN(PASS);
}
/* }}} */
@@ -1539,7 +1807,7 @@ MYSQLND_METHOD(mysqlnd_res, field_tell)(const MYSQLND_RES * const result TSRMLS_
/* {{{ mysqlnd_res::fetch_into */
static void
-MYSQLND_METHOD(mysqlnd_res, fetch_into)(MYSQLND_RES * result, unsigned int flags,
+MYSQLND_METHOD(mysqlnd_res, fetch_into)(MYSQLND_RES * result, const unsigned int flags,
zval *return_value,
enum_mysqlnd_extension extension TSRMLS_DC ZEND_FILE_LINE_DC)
{
@@ -1585,7 +1853,7 @@ MYSQLND_METHOD(mysqlnd_res, fetch_row_c)(MYSQLND_RES * result TSRMLS_DC)
MYSQLND_ROW_C ret = NULL;
DBG_ENTER("mysqlnd_res::fetch_row_c");
- if (result->stored_data && result->stored_data->m.fetch_row == MYSQLND_METHOD(mysqlnd_result_buffered, fetch_row)) {
+ if (result->stored_data && result->stored_data->m.fetch_row == MYSQLND_METHOD(mysqlnd_result_buffered_zval, fetch_row)) {
MYSQLND_METHOD(mysqlnd_result_buffered, fetch_row_c)(result, (void *) &ret, 0, &fetched_anything TSRMLS_CC);
} else if (result->unbuf && result->unbuf->m.fetch_row == MYSQLND_METHOD(mysqlnd_result_unbuffered, fetch_row)) {
MYSQLND_METHOD(mysqlnd_result_unbuffered, fetch_row_c)(result, (void *) &ret, 0, &fetched_anything TSRMLS_CC);
@@ -1600,7 +1868,7 @@ MYSQLND_METHOD(mysqlnd_res, fetch_row_c)(MYSQLND_RES * result TSRMLS_DC)
/* {{{ mysqlnd_res::fetch_all */
static void
-MYSQLND_METHOD(mysqlnd_res, fetch_all)(MYSQLND_RES * result, unsigned int flags, zval *return_value TSRMLS_DC ZEND_FILE_LINE_DC)
+MYSQLND_METHOD(mysqlnd_res, fetch_all)(MYSQLND_RES * result, const unsigned int flags, zval *return_value TSRMLS_DC ZEND_FILE_LINE_DC)
{
zval *row;
ulong i = 0;
@@ -1713,12 +1981,12 @@ MYSQLND_CLASS_METHODS_END;
MYSQLND_CLASS_METHODS_START(mysqlnd_result_buffered)
- MYSQLND_METHOD(mysqlnd_result_buffered, fetch_row),
+ NULL, /* fetch_row */
NULL, /* row_decoder */
MYSQLND_METHOD(mysqlnd_result_buffered, num_rows),
- MYSQLND_METHOD(mysqlnd_result_buffered, fetch_lengths),
- MYSQLND_METHOD(mysqlnd_result_buffered, data_seek),
- MYSQLND_METHOD(mysqlnd_result_buffered, initialize_result_set_rest),
+ NULL, /* fetch_lengths */
+ NULL, /* data_seek */
+ NULL, /* initialize_result_set_rest */
MYSQLND_METHOD(mysqlnd_result_buffered, free_result)
MYSQLND_CLASS_METHODS_END;
@@ -1778,7 +2046,7 @@ mysqlnd_result_unbuffered_init(unsigned int field_count, zend_bool ps, zend_bool
ret->m.fetch_lengths = NULL; /* makes no sense */
ret->m.row_decoder = php_mysqlnd_rowp_read_binary_protocol;
} else {
- ret->m.row_decoder = php_mysqlnd_rowp_read_text_protocol;
+ ret->m.row_decoder = php_mysqlnd_rowp_read_text_protocol_zval;
}
DBG_RETURN(ret);
@@ -1786,14 +2054,57 @@ mysqlnd_result_unbuffered_init(unsigned int field_count, zend_bool ps, zend_bool
/* }}} */
-/* {{{ mysqlnd_result_buffered_init */
-PHPAPI MYSQLND_RES_BUFFERED *
-mysqlnd_result_buffered_init(unsigned int field_count, zend_bool ps, zend_bool persistent TSRMLS_DC)
+/* {{{ mysqlnd_result_buffered_zval_init */
+PHPAPI MYSQLND_RES_BUFFERED_ZVAL *
+mysqlnd_result_buffered_zval_init(unsigned int field_count, zend_bool ps, zend_bool persistent TSRMLS_DC)
+{
+ size_t alloc_size = sizeof(MYSQLND_RES_BUFFERED_ZVAL) + mysqlnd_plugin_count() * sizeof(void *);
+ MYSQLND_RES_BUFFERED_ZVAL * ret = mnd_pecalloc(1, alloc_size, persistent);
+
+ DBG_ENTER("mysqlnd_result_buffered_zval_init");
+
+ if (!ret) {
+ DBG_RETURN(NULL);
+ }
+ if (!(ret->lengths = mnd_pecalloc(field_count, sizeof(unsigned long), persistent))) {
+ mnd_pefree(ret, persistent);
+ DBG_RETURN(NULL);
+ }
+ if (!(ret->result_set_memory_pool = mysqlnd_mempool_create(MYSQLND_G(mempool_default_size) TSRMLS_CC))) {
+ mnd_efree(ret->lengths);
+ mnd_pefree(ret, persistent);
+ DBG_RETURN(NULL);
+ }
+
+ ret->persistent = persistent;
+ ret->field_count= field_count;
+ ret->ps = ps;
+ ret->m = *mysqlnd_result_buffered_get_methods();
+ ret->type = MYSQLND_BUFFERED_TYPE_ZVAL;
+
+ if (ps) {
+ ret->m.fetch_lengths = NULL; /* makes no sense */
+ ret->m.row_decoder = php_mysqlnd_rowp_read_binary_protocol;
+ } else {
+ ret->m.row_decoder = php_mysqlnd_rowp_read_text_protocol_zval;
+ }
+ ret->m.fetch_row = MYSQLND_METHOD(mysqlnd_result_buffered_zval, fetch_row);
+ ret->m.fetch_lengths = MYSQLND_METHOD(mysqlnd_result_buffered_zval, fetch_lengths);
+ ret->m.data_seek = MYSQLND_METHOD(mysqlnd_result_buffered_zval, data_seek);
+ ret->m.initialize_result_set_rest = MYSQLND_METHOD(mysqlnd_result_buffered_zval, initialize_result_set_rest);
+ DBG_RETURN(ret);
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_result_buffered_c_init */
+PHPAPI MYSQLND_RES_BUFFERED_C *
+mysqlnd_result_buffered_c_init(unsigned int field_count, zend_bool ps, zend_bool persistent TSRMLS_DC)
{
- size_t alloc_size = sizeof(MYSQLND_RES_BUFFERED) + mysqlnd_plugin_count() * sizeof(void *);
- MYSQLND_RES_BUFFERED * ret = mnd_pecalloc(1, alloc_size, persistent);
+ size_t alloc_size = sizeof(MYSQLND_RES_BUFFERED_C) + mysqlnd_plugin_count() * sizeof(void *);
+ MYSQLND_RES_BUFFERED_C * ret = mnd_pecalloc(1, alloc_size, persistent);
- DBG_ENTER("mysqlnd_result_buffered_init");
+ DBG_ENTER("mysqlnd_result_buffered_c_init");
if (!ret) {
DBG_RETURN(NULL);
@@ -1812,13 +2123,18 @@ mysqlnd_result_buffered_init(unsigned int field_count, zend_bool ps, zend_bool p
ret->field_count= field_count;
ret->ps = ps;
ret->m = *mysqlnd_result_buffered_get_methods();
+ ret->type = MYSQLND_BUFFERED_TYPE_C;
if (ps) {
ret->m.fetch_lengths = NULL; /* makes no sense */
ret->m.row_decoder = php_mysqlnd_rowp_read_binary_protocol;
} else {
- ret->m.row_decoder = php_mysqlnd_rowp_read_text_protocol;
+ ret->m.row_decoder = php_mysqlnd_rowp_read_text_protocol_c;
}
+ ret->m.fetch_row = MYSQLND_METHOD(mysqlnd_result_buffered_c, fetch_row);
+ ret->m.fetch_lengths = MYSQLND_METHOD(mysqlnd_result_buffered_c, fetch_lengths);
+ ret->m.data_seek = MYSQLND_METHOD(mysqlnd_result_buffered_c, data_seek);
+ ret->m.initialize_result_set_rest = MYSQLND_METHOD(mysqlnd_result_buffered_c, initialize_result_set_rest);
DBG_RETURN(ret);
}
diff --git a/ext/mysqlnd/mysqlnd_result.h b/ext/mysqlnd/mysqlnd_result.h
index 0a54ea0454..f7e22a1d87 100644
--- a/ext/mysqlnd/mysqlnd_result.h
+++ b/ext/mysqlnd/mysqlnd_result.h
@@ -25,7 +25,8 @@
PHPAPI MYSQLND_RES * mysqlnd_result_init(unsigned int field_count, zend_bool persistent TSRMLS_DC);
PHPAPI MYSQLND_RES_UNBUFFERED * mysqlnd_result_unbuffered_init(unsigned int field_count, zend_bool ps, zend_bool persistent TSRMLS_DC);
-PHPAPI MYSQLND_RES_BUFFERED * mysqlnd_result_buffered_init(unsigned int field_count, zend_bool ps, zend_bool persistent TSRMLS_DC);
+PHPAPI MYSQLND_RES_BUFFERED_ZVAL * mysqlnd_result_buffered_zval_init(unsigned int field_count, zend_bool ps, zend_bool persistent TSRMLS_DC);
+PHPAPI MYSQLND_RES_BUFFERED_C * mysqlnd_result_buffered_c_init(unsigned int field_count, zend_bool ps, zend_bool persistent TSRMLS_DC);
enum_func_status mysqlnd_query_read_result_set_header(MYSQLND_CONN_DATA * conn, MYSQLND_STMT * stmt TSRMLS_DC);
diff --git a/ext/mysqlnd/mysqlnd_reverse_api.c b/ext/mysqlnd/mysqlnd_reverse_api.c
index cd490fa62c..669b99bf0e 100644
--- a/ext/mysqlnd/mysqlnd_reverse_api.c
+++ b/ext/mysqlnd/mysqlnd_reverse_api.c
@@ -68,7 +68,7 @@ mysqlnd_reverse_api_register_api(MYSQLND_REVERSE_API * apiext TSRMLS_DC)
/* {{{ zval_to_mysqlnd */
PHPAPI MYSQLND *
-zval_to_mysqlnd(zval * zv TSRMLS_DC)
+zval_to_mysqlnd(zval * zv, const unsigned int client_api_capabilities, unsigned int * save_client_api_capabilities TSRMLS_DC)
{
MYSQLND * retval;
MYSQLND_REVERSE_API ** elem;
@@ -80,6 +80,9 @@ zval_to_mysqlnd(zval * zv TSRMLS_DC)
if ((*elem)->conversion_cb) {
retval = (*elem)->conversion_cb(zv TSRMLS_CC);
if (retval) {
+ if (retval->data) {
+ *save_client_api_capabilities = retval->data->m->negotiate_client_api_capabilities(retval->data, client_api_capabilities TSRMLS_CC);
+ }
return retval;
}
}
diff --git a/ext/mysqlnd/mysqlnd_reverse_api.h b/ext/mysqlnd/mysqlnd_reverse_api.h
index 028a1f6b13..79c0feb60a 100644
--- a/ext/mysqlnd/mysqlnd_reverse_api.h
+++ b/ext/mysqlnd/mysqlnd_reverse_api.h
@@ -34,8 +34,7 @@ PHPAPI void mysqlnd_reverse_api_end(TSRMLS_D);
PHPAPI HashTable * mysqlnd_reverse_api_get_api_list(TSRMLS_D);
PHPAPI void mysqlnd_reverse_api_register_api(MYSQLND_REVERSE_API * apiext TSRMLS_DC);
-
-PHPAPI MYSQLND * zval_to_mysqlnd(zval * zv TSRMLS_DC);
+PHPAPI MYSQLND * zval_to_mysqlnd(zval * zv, const unsigned int client_api_capabilities, unsigned int * save_client_api_capabilities TSRMLS_DC);
#endif /* MYSQLND_REVERSE_API_H */
diff --git a/ext/mysqlnd/mysqlnd_structs.h b/ext/mysqlnd/mysqlnd_structs.h
index 65f1c57a00..4d4538da35 100644
--- a/ext/mysqlnd/mysqlnd_structs.h
+++ b/ext/mysqlnd/mysqlnd_structs.h
@@ -235,7 +235,9 @@ typedef struct st_mysqlnd_param_bind MYSQLND_PARAM_BIND;
typedef struct st_mysqlnd_result_bind MYSQLND_RESULT_BIND;
typedef struct st_mysqlnd_result_metadata MYSQLND_RES_METADATA;
-typedef struct st_mysqlnd_buffered_result MYSQLND_RES_BUFFERED;
+typedef struct st_mysqlnd_buffered_result_parent MYSQLND_RES_BUFFERED;
+typedef struct st_mysqlnd_buffered_result_zval MYSQLND_RES_BUFFERED_ZVAL;
+typedef struct st_mysqlnd_buffered_result_c MYSQLND_RES_BUFFERED_C;
typedef struct st_mysqlnd_unbuffered_result MYSQLND_RES_UNBUFFERED;
typedef struct st_mysqlnd_debug MYSQLND_DEBUG;
@@ -244,7 +246,7 @@ typedef struct st_mysqlnd_debug MYSQLND_DEBUG;
typedef MYSQLND_RES* (*mysqlnd_stmt_use_or_store_func)(MYSQLND_STMT * const TSRMLS_DC);
typedef enum_func_status (*mysqlnd_fetch_row_func)(MYSQLND_RES *result,
void * param,
- unsigned int flags,
+ const unsigned int flags,
zend_bool * fetched_anything
TSRMLS_DC);
@@ -500,6 +502,11 @@ typedef struct st_mysqlnd_authentication_plugin * (*func_mysqlnd_conn_data__fetc
typedef enum_func_status (*func_mysqlnd_conn_data__set_client_option_2d)(MYSQLND_CONN_DATA * const conn, enum mysqlnd_option option, const char * const key, const char * const value TSRMLS_DC);
+
+typedef unsigned int (*func_mysqlnd_conn_data__negotiate_client_api_capabilities)(MYSQLND_CONN_DATA * const conn, const unsigned int flags TSRMLS_DC);
+typedef unsigned int (*func_mysqlnd_conn_data__get_client_api_capabilities)(const MYSQLND_CONN_DATA * const conn TSRMLS_DC);
+
+
struct st_mysqlnd_conn_data_methods
{
func_mysqlnd_conn_data__init init;
@@ -591,6 +598,9 @@ struct st_mysqlnd_conn_data_methods
func_mysqlnd_conn_data__fetch_auth_plugin_by_name fetch_auth_plugin_by_name;
func_mysqlnd_conn_data__set_client_option_2d set_client_option_2d;
+
+ func_mysqlnd_conn_data__negotiate_client_api_capabilities negotiate_client_api_capabilities;
+ func_mysqlnd_conn_data__get_client_api_capabilities get_client_api_capabilities;
};
@@ -615,9 +625,9 @@ typedef enum_func_status (*func_mysqlnd_res__row_decoder)(MYSQLND_MEMORY_POOL_CH
typedef MYSQLND_RES * (*func_mysqlnd_res__use_result)(MYSQLND_RES * const result, zend_bool ps_protocol TSRMLS_DC);
typedef MYSQLND_RES * (*func_mysqlnd_res__store_result)(MYSQLND_RES * result, MYSQLND_CONN_DATA * const conn, const unsigned int flags TSRMLS_DC);
-typedef void (*func_mysqlnd_res__fetch_into)(MYSQLND_RES *result, unsigned int flags, zval *return_value, enum_mysqlnd_extension ext TSRMLS_DC ZEND_FILE_LINE_DC);
+typedef void (*func_mysqlnd_res__fetch_into)(MYSQLND_RES *result, const unsigned int flags, zval *return_value, enum_mysqlnd_extension ext TSRMLS_DC ZEND_FILE_LINE_DC);
typedef MYSQLND_ROW_C (*func_mysqlnd_res__fetch_row_c)(MYSQLND_RES *result TSRMLS_DC);
-typedef void (*func_mysqlnd_res__fetch_all)(MYSQLND_RES *result, unsigned int flags, zval *return_value TSRMLS_DC ZEND_FILE_LINE_DC);
+typedef void (*func_mysqlnd_res__fetch_all)(MYSQLND_RES *result, const unsigned int flags, zval *return_value TSRMLS_DC ZEND_FILE_LINE_DC);
typedef void (*func_mysqlnd_res__fetch_field_data)(MYSQLND_RES *result, unsigned int offset, zval *return_value TSRMLS_DC);
typedef uint64_t (*func_mysqlnd_res__num_rows)(const MYSQLND_RES * const result TSRMLS_DC);
typedef unsigned int (*func_mysqlnd_res__num_fields)(const MYSQLND_RES * const result TSRMLS_DC);
@@ -631,7 +641,7 @@ typedef const MYSQLND_FIELD *(*func_mysqlnd_res__fetch_fields)(MYSQLND_RES * con
typedef enum_func_status (*func_mysqlnd_res__read_result_metadata)(MYSQLND_RES * result, MYSQLND_CONN_DATA * conn TSRMLS_DC);
typedef unsigned long * (*func_mysqlnd_res__fetch_lengths)(MYSQLND_RES * const result TSRMLS_DC);
-typedef enum_func_status (*func_mysqlnd_res__store_result_fetch_data)(MYSQLND_CONN_DATA * const conn, MYSQLND_RES * result, MYSQLND_RES_METADATA *meta, zend_bool binary_protocol TSRMLS_DC);
+typedef enum_func_status (*func_mysqlnd_res__store_result_fetch_data)(MYSQLND_CONN_DATA * const conn, MYSQLND_RES * result, MYSQLND_RES_METADATA * meta, MYSQLND_MEMORY_POOL_CHUNK *** row_buffers, zend_bool binary_protocol TSRMLS_DC);
typedef void (*func_mysqlnd_res__free_result_buffers)(MYSQLND_RES * result TSRMLS_DC); /* private */
typedef enum_func_status (*func_mysqlnd_res__free_result)(MYSQLND_RES * result, zend_bool implicit TSRMLS_DC);
@@ -947,9 +957,6 @@ struct st_mysqlnd_connection_data
/* Temporal storage for mysql_query */
unsigned int field_count;
- /* persistent connection */
- zend_bool persistent;
-
/* options */
MYSQLND_OPTIONS * options;
MYSQLND_OPTIONS options_impl;
@@ -957,7 +964,12 @@ struct st_mysqlnd_connection_data
/* stats */
MYSQLND_STATS * stats;
+ unsigned int client_api_capabilities;
+
struct st_mysqlnd_conn_data_methods * m;
+
+ /* persistent connection */
+ zend_bool persistent;
};
@@ -991,31 +1003,51 @@ struct st_mysqlnd_result_metadata
};
-struct st_mysqlnd_buffered_result
+#define def_mysqlnd_buffered_result_parent \
+ MYSQLND_MEMORY_POOL_CHUNK **row_buffers; \
+ uint64_t row_count; \
+ uint64_t initialized_rows; \
+ \
+ /* Column lengths of current row - both buffered and unbuffered. For buffered results it duplicates the data found in **data */ \
+ unsigned long *lengths; \
+ \
+ MYSQLND_MEMORY_POOL *result_set_memory_pool; \
+ \
+ unsigned int references; \
+ \
+ MYSQLND_ERROR_INFO error_info; \
+ \
+ unsigned int field_count; \
+ zend_bool ps; \
+ zend_bool persistent; \
+ struct st_mysqlnd_result_buffered_methods m; \
+ enum mysqlnd_buffered_type type; \
+ void * unused1; \
+ void * unused2; \
+ void * unused3; \
+
+
+struct st_mysqlnd_buffered_result_parent
{
- zval **data;
- zval **data_cursor;
- MYSQLND_MEMORY_POOL_CHUNK **row_buffers;
- uint64_t row_count;
- uint64_t initialized_rows;
+ def_mysqlnd_buffered_result_parent;
+};
- /*
- Column lengths of current row - both buffered and unbuffered.
- For buffered results it duplicates the data found in **data
- */
- unsigned long *lengths;
- MYSQLND_MEMORY_POOL *result_set_memory_pool;
+struct st_mysqlnd_buffered_result_zval
+{
+ def_mysqlnd_buffered_result_parent;
- unsigned int references;
+ zval **data;
+ zval **data_cursor;
+};
- MYSQLND_ERROR_INFO error_info;
- unsigned int field_count;
- zend_bool ps;
- zend_bool persistent;
+struct st_mysqlnd_buffered_result_c
+{
+ def_mysqlnd_buffered_result_parent;
- struct st_mysqlnd_result_buffered_methods m;
+ zend_uchar *initialized; /* every row is a single bit */
+ uint64_t current_row;
};
diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.c b/ext/mysqlnd/mysqlnd_wireprotocol.c
index dfdba4084e..ecce71d9c2 100644
--- a/ext/mysqlnd/mysqlnd_wireprotocol.c
+++ b/ext/mysqlnd/mysqlnd_wireprotocol.c
@@ -1572,13 +1572,13 @@ php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zv
}
/* }}} */
-
/* {{{ php_mysqlnd_rowp_read_text_protocol */
enum_func_status
-php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
+php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
unsigned int field_count, const MYSQLND_FIELD * fields_metadata,
- zend_bool as_int_or_float, MYSQLND_STATS * stats TSRMLS_DC)
+ zend_bool as_int_or_float, zend_bool copy_data, MYSQLND_STATS * stats TSRMLS_DC)
{
+
unsigned int i;
zend_bool last_field_was_string = FALSE;
zval **current_field, **end_field, **start_field;
@@ -1586,7 +1586,7 @@ php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval
size_t data_size = row_buffer->app;
zend_uchar * bit_area = (zend_uchar*) row_buffer->ptr + data_size + 1; /* we allocate from here */
- DBG_ENTER("php_mysqlnd_rowp_read_text_protocol");
+ DBG_ENTER("php_mysqlnd_rowp_read_text_protocol_aux");
if (!fields) {
DBG_RETURN(FAIL);
@@ -1608,7 +1608,7 @@ php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval
/* php_mysqlnd_net_field_length() call should be after *this_field_len_pos = p; */
unsigned long len = php_mysqlnd_net_field_length(&p);
- if (current_field > start_field && last_field_was_string) {
+ if (copy_data == FALSE && current_field > start_field && last_field_was_string) {
/*
Normal queries:
We have to put \0 now to the end of the previous field, if it was
@@ -1733,22 +1733,22 @@ php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval
p -= len;
if (Z_TYPE_PP(current_field) == IS_LONG) {
bit_area += 1 + sprintf((char *)start, "%ld", Z_LVAL_PP(current_field));
- ZVAL_STRINGL(*current_field, (char *) start, bit_area - start - 1, 0);
+ ZVAL_STRINGL(*current_field, (char *) start, bit_area - start - 1, copy_data);
} else if (Z_TYPE_PP(current_field) == IS_STRING){
memcpy(bit_area, Z_STRVAL_PP(current_field), Z_STRLEN_PP(current_field));
bit_area += Z_STRLEN_PP(current_field);
*bit_area++ = '\0';
zval_dtor(*current_field);
- ZVAL_STRINGL(*current_field, (char *) start, bit_area - start - 1, 0);
+ ZVAL_STRINGL(*current_field, (char *) start, bit_area - start - 1, copy_data);
}
} else {
- ZVAL_STRINGL(*current_field, (char *)p, len, 0);
+ ZVAL_STRINGL(*current_field, (char *)p, len, copy_data);
}
p += len;
last_field_was_string = TRUE;
}
}
- if (last_field_was_string) {
+ if (copy_data == FALSE && last_field_was_string) {
/* Normal queries: The buffer has one more byte at the end, because we need it */
row_buffer->ptr[data_size] = '\0';
}
@@ -1758,6 +1758,36 @@ php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval
/* }}} */
+/* {{{ php_mysqlnd_rowp_read_text_protocol_zval */
+enum_func_status
+php_mysqlnd_rowp_read_text_protocol_zval(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
+ unsigned int field_count, const MYSQLND_FIELD * fields_metadata,
+ zend_bool as_int_or_float, MYSQLND_STATS * stats TSRMLS_DC)
+{
+ enum_func_status ret;
+ DBG_ENTER("php_mysqlnd_rowp_read_text_protocol_zval");
+ ret = php_mysqlnd_rowp_read_text_protocol_aux(row_buffer, fields, field_count, fields_metadata, as_int_or_float, FALSE, stats TSRMLS_CC);
+ DBG_RETURN(ret);
+}
+/* }}} */
+
+
+/* {{{ php_mysqlnd_rowp_read_text_protocol_c */
+enum_func_status
+php_mysqlnd_rowp_read_text_protocol_c(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
+ unsigned int field_count, const MYSQLND_FIELD * fields_metadata,
+ zend_bool as_int_or_float, MYSQLND_STATS * stats TSRMLS_DC)
+{
+ enum_func_status ret;
+ DBG_ENTER("php_mysqlnd_rowp_read_text_protocol_c");
+ ret = php_mysqlnd_rowp_read_text_protocol_aux(row_buffer, fields, field_count, fields_metadata, as_int_or_float, TRUE, stats TSRMLS_CC);
+ DBG_RETURN(ret);
+}
+/* }}} */
+
+
+
+
/* {{{ php_mysqlnd_rowp_read */
/*
if normal statements => packet->fields is created by this function,
diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.h b/ext/mysqlnd/mysqlnd_wireprotocol.h
index be71d06508..7e8b9624ac 100644
--- a/ext/mysqlnd/mysqlnd_wireprotocol.h
+++ b/ext/mysqlnd/mysqlnd_wireprotocol.h
@@ -312,7 +312,11 @@ enum_func_status php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK
zend_bool as_int_or_float, MYSQLND_STATS * stats TSRMLS_DC);
-enum_func_status php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
+enum_func_status php_mysqlnd_rowp_read_text_protocol_zval(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
+ unsigned int field_count, const MYSQLND_FIELD * fields_metadata,
+ zend_bool as_int_or_float, MYSQLND_STATS * stats TSRMLS_DC);
+
+enum_func_status php_mysqlnd_rowp_read_text_protocol_c(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
unsigned int field_count, const MYSQLND_FIELD * fields_metadata,
zend_bool as_int_or_float, MYSQLND_STATS * stats TSRMLS_DC);
diff --git a/ext/mysqlnd/php_mysqlnd.c b/ext/mysqlnd/php_mysqlnd.c
index 7712f1ecb8..913574e2e9 100644
--- a/ext/mysqlnd/php_mysqlnd.c
+++ b/ext/mysqlnd/php_mysqlnd.c
@@ -209,6 +209,7 @@ static PHP_GINIT_FUNCTION(mysqlnd)
mysqlnd_globals->debug_calloc_fail_threshold = -1;
mysqlnd_globals->debug_realloc_fail_threshold = -1;
mysqlnd_globals->sha256_server_public_key = NULL;
+ mysqlnd_globals->fetch_data_copy = FALSE;
}
/* }}} */
@@ -227,8 +228,8 @@ static PHP_INI_MH(OnUpdateNetCmdBufferSize)
/* {{{ PHP_INI_BEGIN
*/
PHP_INI_BEGIN()
- STD_PHP_INI_BOOLEAN("mysqlnd.collect_statistics", "1", PHP_INI_ALL, OnUpdateBool, collect_statistics, zend_mysqlnd_globals, mysqlnd_globals)
- STD_PHP_INI_BOOLEAN("mysqlnd.collect_memory_statistics", "0", PHP_INI_SYSTEM, OnUpdateBool, collect_memory_statistics, zend_mysqlnd_globals, mysqlnd_globals)
+ STD_PHP_INI_BOOLEAN("mysqlnd.collect_statistics", "1", PHP_INI_ALL, OnUpdateBool, collect_statistics, zend_mysqlnd_globals, mysqlnd_globals)
+ STD_PHP_INI_BOOLEAN("mysqlnd.collect_memory_statistics","0",PHP_INI_SYSTEM, OnUpdateBool, collect_memory_statistics, zend_mysqlnd_globals, mysqlnd_globals)
STD_PHP_INI_ENTRY("mysqlnd.debug", NULL, PHP_INI_SYSTEM, OnUpdateString, debug, zend_mysqlnd_globals, mysqlnd_globals)
STD_PHP_INI_ENTRY("mysqlnd.trace_alloc", NULL, PHP_INI_SYSTEM, OnUpdateString, trace_alloc_settings, zend_mysqlnd_globals, mysqlnd_globals)
STD_PHP_INI_ENTRY("mysqlnd.net_cmd_buffer_size", MYSQLND_NET_CMD_BUFFER_MIN_SIZE_STR, PHP_INI_ALL, OnUpdateNetCmdBufferSize, net_cmd_buffer_size, zend_mysqlnd_globals, mysqlnd_globals)
@@ -237,7 +238,7 @@ PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("mysqlnd.log_mask", "0", PHP_INI_ALL, OnUpdateLong, log_mask, zend_mysqlnd_globals, mysqlnd_globals)
STD_PHP_INI_ENTRY("mysqlnd.mempool_default_size","16000", PHP_INI_ALL, OnUpdateLong, mempool_default_size, zend_mysqlnd_globals, mysqlnd_globals)
STD_PHP_INI_ENTRY("mysqlnd.sha256_server_public_key",NULL, PHP_INI_PERDIR, OnUpdateString, sha256_server_public_key, zend_mysqlnd_globals, mysqlnd_globals)
-
+ STD_PHP_INI_BOOLEAN("mysqlnd.fetch_data_copy", "0", PHP_INI_ALL, OnUpdateBool, fetch_data_copy, zend_mysqlnd_globals, mysqlnd_globals)
#if PHP_DEBUG
STD_PHP_INI_ENTRY("mysqlnd.debug_emalloc_fail_threshold","-1", PHP_INI_SYSTEM, OnUpdateLong, debug_emalloc_fail_threshold, zend_mysqlnd_globals, mysqlnd_globals)
STD_PHP_INI_ENTRY("mysqlnd.debug_ecalloc_fail_threshold","-1", PHP_INI_SYSTEM, OnUpdateLong, debug_ecalloc_fail_threshold, zend_mysqlnd_globals, mysqlnd_globals)
diff --git a/ext/pdo_mysql/mysql_driver.c b/ext/pdo_mysql/mysql_driver.c
index 825fe2647f..581766b38a 100644
--- a/ext/pdo_mysql/mysql_driver.c
+++ b/ext/pdo_mysql/mysql_driver.c
@@ -37,7 +37,7 @@
#include "zend_exceptions.h"
#if defined(PDO_USE_MYSQLND)
-# define pdo_mysql_init(persistent) mysqlnd_init(persistent)
+# define pdo_mysql_init(persistent) mysqlnd_init(MYSQLND_CLIENT_NO_FLAG, persistent)
#else
# define pdo_mysql_init(persistent) mysql_init(NULL)
#endif
@@ -752,7 +752,7 @@ static int pdo_mysql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_
}
if (mysqlnd_connect(H->server, host, dbh->username, dbh->password, password_len, dbname, dbname_len,
- port, unix_socket, connect_opts TSRMLS_CC) == NULL) {
+ port, unix_socket, connect_opts, MYSQLND_CLIENT_NO_FLAG TSRMLS_CC) == NULL) {
#else
if (mysql_real_connect(H->server, host, dbh->username, dbh->password, dbname, port, unix_socket, connect_opts) == NULL) {
#endif