php7.2: add u9 patchset

master
parent b77f88e3a9
commit c3ba9ac893
  1. 6
      testing/php7.2/APKBUILD
  2. 156
      testing/php7.2/u9-001-lp-1939853-1-Fix-Segfault-with-get_result-and-PS-cursors.patch
  3. 472
      testing/php7.2/u9-002-lp-1939853-2-MySQLnd-Support-cursors-in-store-get-result.patch

@ -26,7 +26,7 @@
pkgname=php7.2
_pkgreal=php
pkgver=7.2.34
pkgrel=7
pkgrel=8
_apiver=20170718
_suffix=${pkgname#php}
_suffixA=7
@ -114,6 +114,8 @@ source="https://php.net/distributions/$_pkgreal-$pkgver.tar.xz
u8-009-CVE-2021-21704-4.patch
u8-010-CVE-2021-21705.patch
u8-011-CVE-2021-21705-2.patch
u9-001-lp-1939853-1-Fix-Segfault-with-get_result-and-PS-cursors.patch
u9-002-lp-1939853-2-MySQLnd-Support-cursors-in-store-get-result.patch
"
builddir="$srcdir/$_pkgreal-$pkgver"
@ -704,4 +706,6 @@ a3b631bb2d8fa016c29a70ca0f2be4e9bf61137ed221710b5ab23b1d187086f81a8d0e1dbb2c7c2e
5612baf6614e8c18411efb7fd7a027bf03ca06d9f9f41d33b1733b333316e1a975a34eae785238368e479e98be1bba5a6cc64901d911976b5ccb9e4083fdfa8b u8-009-CVE-2021-21704-4.patch
43e7eb90d0ba9bf6eca92b594d991bd3990817801a1addbaa69b2632a904c67b2831b233e12f494757e4bdf673c255b109a41f4581ea5272f6dec95d39e40ef7 u8-010-CVE-2021-21705.patch
6eeaac947df36a16a703d60bd4c31ce3bb17c1c6ab9fdf76bb78ac278c0f88b197dd6ddc226c9f5d0428b9170ffdd186c30f368077626aabe2a9f05c3e9d735f u8-011-CVE-2021-21705-2.patch
c837e778c17780093a47255d48cc7f47b5ca3fdd9569174145eeae73614bce8565cbbb54cae488b1510e32614edd28a716f5acf5f932cc61a422a33b5606ea4c u9-001-lp-1939853-1-Fix-Segfault-with-get_result-and-PS-cursors.patch
844b7736b3a5ecc5ad247d41419e97e466fae382b82cc1cdf6d56e9a8fa9280bc0f624a3f07fd9d52205372c5d82201d7b3b97dde46577b1d79a62dbb545b07d u9-002-lp-1939853-2-MySQLnd-Support-cursors-in-store-get-result.patch
"

@ -0,0 +1,156 @@
commit b5481defe64c991d0e4307372d69c0ea3cd83378
Author: Dharman <tekiela246@gmail.com>
Date: Thu 17 Sep 2020 12:35:26 +0100
Description:
Fix bug #72413: Segfault with get_result and PS cursors
We cannot simply switch to use_result here, because the fetch_row
methods in get_result mode and in use_result/store_result mode
are different: In one case it accepts a statement, in the other
a return value zval. Thus, doing a switch to use_result results
in a segfault when trying to fetch a row.
Actually supporting get_result with cursors would require adding
cursor support in mysqlnd_result, not just mysqlnd_ps. That would
be a significant amount of effort and, given the age of the issue,
does not appear to be particularly likely to happen soon.
As such, we simply generate an error when using get_result()
with cursors, which is much better than causing a segfault.
Instead, parameter binding needs to be used.
Bug: https://bugs.php.net/bug.php?id=72413
Bug-Ubuntu: https://bugs.launchpad.net/bugs/1939853
Origin: backport, https://github.com/php/php-src/commit/b5481defe64c991d0e4307372d69c0ea3cd83378
Last-Update: 2021-08-13
Index: php7.2-7.2.24/ext/mysqli/tests/mysqli_stmt_get_result.phpt
===================================================================
--- php7.2-7.2.24.orig/ext/mysqli/tests/mysqli_stmt_get_result.phpt 2021-08-16 17:46:04.259501381 +1200
+++ php7.2-7.2.24/ext/mysqli/tests/mysqli_stmt_get_result.phpt 2021-08-16 17:46:04.255501246 +1200
@@ -124,32 +124,77 @@
if (true !== ($tmp = mysqli_stmt_bind_result($stmt, $id, $label)))
printf("[035] Expecting boolean/true, got %s/%s\n", gettype($tmp), var_export($tmp, 1));
+ // get_result cannot be used in PS cursor mode
+ if (!$stmt = mysqli_stmt_init($link))
+ printf("[030] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+ if (!mysqli_stmt_prepare($stmt, "SELECT id, label FROM test ORDER BY id LIMIT 2"))
+ printf("[031] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
+
+ if (!mysqli_stmt_attr_set($stmt, MYSQLI_STMT_ATTR_CURSOR_TYPE, MYSQLI_CURSOR_TYPE_READ_ONLY))
+ printf("[032] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
+
+ if (!mysqli_stmt_execute($stmt))
+ printf("[033] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
+
+ mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
+ try {
+ $res = mysqli_stmt_get_result($stmt);
+ // we expect no segfault if we try to fetch a row because get_result should throw an error or return false
+ mysqli_fetch_assoc($res);
+ } catch (\mysqli_sql_exception $e) {
+ echo $e->getMessage() . "\n";
+ }
+
+ try {
+ $res = $stmt->get_result();
+ // we expect no segfault if we try to fetch a row because get_result should throw an error or return false
+ $res->fetch_assoc();
+ } catch (\mysqli_sql_exception $e) {
+ echo $e->getMessage() . "\n";
+ }
+ mysqli_report(MYSQLI_REPORT_OFF);
+
+ if (!$stmt = mysqli_stmt_init($link))
+ printf("[034] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+ if (!mysqli_stmt_prepare($stmt, "SELECT id, label FROM test ORDER BY id LIMIT 2"))
+ printf("[035] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
+
+ if (!mysqli_stmt_execute($stmt))
+ printf("[036] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
+
+ $id = NULL;
+ $label = NULL;
+ if (true !== ($tmp = mysqli_stmt_bind_result($stmt, $id, $label)))
+ printf("[037] Expecting boolean/true, got %s/%s\n", gettype($tmp), var_export($tmp, 1));
+
if (!is_object($tmp = $result = mysqli_stmt_get_result($stmt)))
- printf("[036] Expecting array, got %s/%s, [%d] %s\n",
+ printf("[038] Expecting array, got %s/%s, [%d] %s\n",
gettype($tmp), var_export($tmp, 1),
mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
if (false !== ($tmp = mysqli_stmt_fetch($stmt)))
- printf("[037] Expecting boolean/false, got %s/%s, [%d] %s\n",
+ printf("[039] Expecting boolean/false, got %s/%s, [%d] %s\n",
gettype($tmp), $tmp, mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
- printf("[038] [%d] [%s]\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
- printf("[039] [%d] [%s]\n", mysqli_errno($link), mysqli_error($link));
+ printf("[040] [%d] [%s]\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
+ printf("[041] [%d] [%s]\n", mysqli_errno($link), mysqli_error($link));
while ($row = mysqli_fetch_assoc($result)) {
var_dump($row);
}
mysqli_free_result($result);
if (!mysqli_kill($link, mysqli_thread_id($link)))
- printf("[040] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+ printf("[042] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
if (false !== ($tmp = mysqli_stmt_get_result($stmt)))
- printf("[041] Expecting false, got %s/%s\n", gettype($tmp), var_export($tmp, 1));
+ printf("[043] Expecting false, got %s/%s\n", gettype($tmp), var_export($tmp, 1));
mysqli_stmt_close($stmt);
if (NULL !== ($tmp = mysqli_stmt_fetch($stmt)))
- printf("[042] Expecting NULL, got %s/%s\n", gettype($tmp), var_export($tmp, 1));
+ printf("[044] Expecting NULL, got %s/%s\n", gettype($tmp), var_export($tmp, 1));
mysqli_close($link);
@@ -168,8 +213,10 @@
Warning: mysqli_stmt_get_result(): invalid object or resource mysqli_stmt
in %s on line %d
-[038] [2014] [Commands out of sync; you can't run this command now]
-[039] [0] []
+mysqli_stmt_get_result() cannot be used with cursors
+get_result() cannot be used with cursors
+[040] [2014] [Commands out of sync; you can't run this command now]
+[041] [0] []
array(2) {
["id"]=>
int(1)
Index: php7.2-7.2.24/ext/mysqlnd/mysqlnd_ps.c
===================================================================
--- php7.2-7.2.24.orig/ext/mysqlnd/mysqlnd_ps.c 2021-08-16 17:46:04.259501381 +1200
+++ php7.2-7.2.24/ext/mysqlnd/mysqlnd_ps.c 2021-08-16 17:46:04.255501246 +1200
@@ -152,13 +152,19 @@
}
if (stmt->cursor_exists) {
- /* Silently convert buffered to unbuffered, for now */
- DBG_RETURN(s->m->use_result(s));
+ /* Prepared statement cursors are not supported as of yet */
+ char * msg;
+ mnd_sprintf(&msg, 0, "%s() cannot be used with cursors", get_active_function_name());
+ SET_CLIENT_ERROR(stmt->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, msg);
+ if (msg) {
+ mnd_sprintf_free(msg);
+ }
+ DBG_RETURN(NULL);
}
/* Nothing to store for UPSERT/LOAD DATA*/
if (GET_CONNECTION_STATE(&conn->state) != CONN_FETCHING_DATA || stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE) {
- SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
+ SET_CLIENT_ERROR(stmt->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
DBG_RETURN(NULL);
}

@ -0,0 +1,472 @@
commit bc166844e37a6e1531a18dc0916fbe508152fc6c
Author: Nikita Popov <nikita.ppv@gmail.com>
Date: Wed, 16 Dec 2020 12:12:06 +0100
Description:
MySQLnd: Support cursors in store/get result
This fixes two related issues:
1. When a PS with cursor is used in store_result/get_result,
perform a COM_FETCH with maximum number of rows rather than
silently switching to an unbuffered result set (in the case of
store_result) or erroring (in the case of get_result).
In the future, we might want to make get_result unbuffered for
PS with cursors, as using cursors with buffered result sets
doesn't really make sense. Unlike store_result, get_result
isn't very explicit about what kind of result set is desired.
2. If the client did not request a cursor, but the server reports
that a cursor exists, ignore this and treat the PS as if it
has no cursor (i.e. to not use COM_FETCH). It appears to be a
server side bug that a cursor used inside an SP will be reported
to the client, even though the client cannot use the cursor.
Fixes bug #64638, bug #72862, bug #77935.
Closes GH-6518.
Bug: https://bugs.php.net/bug.php?id=64638
Bug: https://bugs.php.net/bug.php?id=72862
Bug: https://bugs.php.net/bug.php?id=77935
Bug-Ubuntu: https://bugs.launchpad.net/bugs/1939853
Origin: backport, https://github.com/php/php-src/commit/bc166844e37a6e1531a18dc0916fbe508152fc6c
Last-Update: 2021-08-13
Index: php7.2-7.2.24/ext/mysqli/tests/bug77935.phpt
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ php7.2-7.2.24/ext/mysqli/tests/bug77935.phpt 2021-08-17 16:54:06.156580253 +1200
@@ -0,0 +1,39 @@
+--TEST--
+Bug #77935: Crash in mysqlnd_fetch_stmt_row_cursor when calling an SP with a cursor
+--SKIPIF--
+<?php
+require_once('skipif.inc');
+require_once('skipifconnectfailure.inc');
+?>
+--FILE--
+<?php
+require_once(__DIR__ . '/connect.inc');
+
+mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
+$db = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket);
+$db->query('DROP PROCEDURE IF EXISTS testSp');
+$db->query(<<<'SQL'
+CREATE
+ PROCEDURE `testSp`()
+ BEGIN
+ DECLARE `cur` CURSOR FOR SELECT 1;
+ OPEN `cur`;
+ CLOSE `cur`;
+ SELECT 1;
+ END;
+SQL
+);
+
+$stmt = $db->prepare("CALL testSp()");
+$stmt->execute();
+$result = $stmt->get_result();
+while ($row = $result->fetch_assoc()) {
+ var_dump($row);
+}
+
+?>
+--EXPECT--
+array(1) {
+ [1]=>
+ int(1)
+}
Index: php7.2-7.2.24/ext/mysqli/tests/mysqli_stmt_get_result.phpt
===================================================================
--- php7.2-7.2.24.orig/ext/mysqli/tests/mysqli_stmt_get_result.phpt 2021-08-17 16:54:06.176580524 +1200
+++ php7.2-7.2.24/ext/mysqli/tests/mysqli_stmt_get_result.phpt 2021-08-17 16:54:06.156580253 +1200
@@ -110,21 +110,7 @@
mysqli_stmt_close($stmt);
- if (!$stmt = mysqli_stmt_init($link))
- printf("[032] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
-
- if (!mysqli_stmt_prepare($stmt, "SELECT id, label FROM test ORDER BY id LIMIT 2"))
- printf("[033] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
-
- if (!mysqli_stmt_execute($stmt))
- printf("[034] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
-
- $id = NULL;
- $label = NULL;
- if (true !== ($tmp = mysqli_stmt_bind_result($stmt, $id, $label)))
- printf("[035] Expecting boolean/true, got %s/%s\n", gettype($tmp), var_export($tmp, 1));
-
- // get_result cannot be used in PS cursor mode
+ // get_result can be used in PS cursor mode
if (!$stmt = mysqli_stmt_init($link))
printf("[030] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
@@ -137,23 +123,10 @@
if (!mysqli_stmt_execute($stmt))
printf("[033] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
- mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
- try {
- $res = mysqli_stmt_get_result($stmt);
- // we expect no segfault if we try to fetch a row because get_result should throw an error or return false
- mysqli_fetch_assoc($res);
- } catch (\mysqli_sql_exception $e) {
- echo $e->getMessage() . "\n";
- }
-
- try {
- $res = $stmt->get_result();
- // we expect no segfault if we try to fetch a row because get_result should throw an error or return false
- $res->fetch_assoc();
- } catch (\mysqli_sql_exception $e) {
- echo $e->getMessage() . "\n";
+ $result = mysqli_stmt_get_result($stmt);
+ while ($row = mysqli_fetch_assoc($result)) {
+ var_dump($row);
}
- mysqli_report(MYSQLI_REPORT_OFF);
if (!$stmt = mysqli_stmt_init($link))
printf("[034] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
@@ -213,8 +186,18 @@
Warning: mysqli_stmt_get_result(): invalid object or resource mysqli_stmt
in %s on line %d
-mysqli_stmt_get_result() cannot be used with cursors
-get_result() cannot be used with cursors
+array(2) {
+ ["id"]=>
+ int(1)
+ ["label"]=>
+ string(1) "a"
+}
+array(2) {
+ ["id"]=>
+ int(2)
+ ["label"]=>
+ string(1) "b"
+}
[040] [2014] [Commands out of sync; you can't run this command now]
[041] [0] []
array(2) {
Index: php7.2-7.2.24/ext/mysqli/tests/ps_cursor_multiple_result_sets.phpt
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ php7.2-7.2.24/ext/mysqli/tests/ps_cursor_multiple_result_sets.phpt 2021-08-17 16:54:06.176580524 +1200
@@ -0,0 +1,99 @@
+--TEST--
+PS using cursor and returning multiple result sets
+--SKIPIF--
+<?php
+require_once('skipif.inc');
+require_once('skipifconnectfailure.inc');
+?>
+--FILE--
+<?php
+require_once(__DIR__ . '/connect.inc');
+
+mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
+$db = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket);
+$db->query('DROP PROCEDURE IF EXISTS testPs');
+$db->query(<<<'SQL'
+CREATE PROCEDURE testPs() BEGIN
+ DECLARE testCursor CURSOR FOR SELECT 'stuff';
+ OPEN testCursor;
+ CLOSE testCursor;
+ SELECT 1 as a, 2 as b;
+ SELECT 3 as a, 4 as b;
+END
+SQL
+);
+
+echo "use_result:\n";
+$stmt = $db->prepare("call testPs()");
+$stmt->execute();
+$stmt->bind_result($v1, $v2);
+while ($stmt->fetch()) {
+ var_dump($v1, $v2);
+}
+
+$stmt->next_result();
+$stmt->bind_result($v1, $v2);
+while ($stmt->fetch()) {
+ var_dump($v1, $v2);
+}
+$stmt->next_result();
+
+echo "\nstore_result:\n";
+$stmt = $db->prepare("call testPs()");
+$stmt->execute();
+$stmt->store_result();
+$stmt->bind_result($v1, $v2);
+while ($stmt->fetch()) {
+ var_dump($v1, $v2);
+}
+
+$stmt->next_result();
+$stmt->store_result();
+$stmt->bind_result($v1, $v2);
+while ($stmt->fetch()) {
+ var_dump($v1, $v2);
+}
+$stmt->next_result();
+
+echo "\nget_result:\n";
+$stmt = $db->prepare("call testPs()");
+$stmt->execute();
+$result = $stmt->get_result();
+while ($row = $result->fetch_assoc()) {
+ var_dump($row);
+}
+
+$stmt->next_result();
+$result = $stmt->get_result();
+while ($row = $result->fetch_assoc()) {
+ var_dump($row);
+}
+$stmt->next_result();
+
+?>
+--EXPECT--
+use_result:
+int(1)
+int(2)
+int(3)
+int(4)
+
+store_result:
+int(1)
+int(2)
+int(3)
+int(4)
+
+get_result:
+array(2) {
+ ["a"]=>
+ int(1)
+ ["b"]=>
+ int(2)
+}
+array(2) {
+ ["a"]=>
+ int(3)
+ ["b"]=>
+ int(4)
+}
Index: php7.2-7.2.24/ext/mysqlnd/mysqlnd_ps.c
===================================================================
--- php7.2-7.2.24.orig/ext/mysqlnd/mysqlnd_ps.c 2021-08-17 16:54:06.176580524 +1200
+++ php7.2-7.2.24/ext/mysqlnd/mysqlnd_ps.c 2021-08-17 16:54:06.176580524 +1200
@@ -40,6 +40,45 @@
static void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt);
static void mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const stmt, const unsigned int param_no);
+static enum_func_status mysqlnd_stmt_send_cursor_fetch_command(
+ const MYSQLND_STMT_DATA *stmt, unsigned max_rows)
+{
+ enum_func_status ret;
+ MYSQLND_CONN_DATA *conn = stmt->conn;
+ zend_uchar buf[MYSQLND_STMT_ID_LENGTH /* statement id */ + 4 /* number of rows to fetch */];
+ const MYSQLND_CSTRING payload = {(const char*) buf, sizeof(buf)};
+
+ int4store(buf, stmt->stmt_id);
+ int4store(buf + MYSQLND_STMT_ID_LENGTH, max_rows);
+
+ struct st_mysqlnd_protocol_command * command = conn->command_factory(COM_STMT_FETCH, conn, payload);
+ ret = FAIL;
+ if (command) {
+ ret = command->run(command);
+ command->free_command(command);
+ if (ret == FAIL) {
+ COPY_CLIENT_ERROR(stmt->error_info, *conn->error_info);
+ }
+ }
+ if (FAIL == ret) {
+ return FAIL;
+ }
+ return PASS;
+}
+
+static zend_bool mysqlnd_stmt_check_state(const MYSQLND_STMT_DATA *stmt)
+{
+ const MYSQLND_CONN_DATA *conn = stmt->conn;
+ if (stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE) {
+ return 0;
+ }
+ if (stmt->cursor_exists) {
+ return GET_CONNECTION_STATE(&conn->state) == CONN_READY;
+ } else {
+ return GET_CONNECTION_STATE(&conn->state) == CONN_FETCHING_DATA;
+ }
+}
+
/* {{{ mysqlnd_stmt::store_result */
static MYSQLND_RES *
MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s)
@@ -60,14 +99,8 @@
DBG_RETURN(NULL);
}
- if (stmt->cursor_exists) {
- /* Silently convert buffered to unbuffered, for now */
- DBG_RETURN(s->m->use_result(s));
- }
-
/* Nothing to store for UPSERT/LOAD DATA*/
- if (GET_CONNECTION_STATE(&conn->state) != CONN_FETCHING_DATA || stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE)
- {
+ if (!mysqlnd_stmt_check_state(stmt)) {
SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
DBG_RETURN(NULL);
}
@@ -78,6 +111,12 @@
SET_EMPTY_ERROR(conn->error_info);
MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_PS_BUFFERED_SETS);
+ if (stmt->cursor_exists) {
+ if (mysqlnd_stmt_send_cursor_fetch_command(stmt, -1) == FAIL) {
+ DBG_RETURN(NULL);
+ }
+ }
+
result = stmt->result;
result->type = MYSQLND_RES_PS_BUF;
/* result->m.row_decoder = php_mysqlnd_rowp_read_binary_protocol; */
@@ -151,19 +190,8 @@
DBG_RETURN(NULL);
}
- if (stmt->cursor_exists) {
- /* Prepared statement cursors are not supported as of yet */
- char * msg;
- mnd_sprintf(&msg, 0, "%s() cannot be used with cursors", get_active_function_name());
- SET_CLIENT_ERROR(stmt->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, msg);
- if (msg) {
- mnd_sprintf_free(msg);
- }
- DBG_RETURN(NULL);
- }
-
/* Nothing to store for UPSERT/LOAD DATA*/
- if (GET_CONNECTION_STATE(&conn->state) != CONN_FETCHING_DATA || stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE) {
+ if (!mysqlnd_stmt_check_state(stmt)) {
SET_CLIENT_ERROR(stmt->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
DBG_RETURN(NULL);
}
@@ -172,6 +200,12 @@
SET_EMPTY_ERROR(conn->error_info);
MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_BUFFERED_SETS);
+ if (stmt->cursor_exists) {
+ if (mysqlnd_stmt_send_cursor_fetch_command(stmt, -1) == FAIL) {
+ DBG_RETURN(NULL);
+ }
+ }
+
do {
result = conn->m->result_init(stmt->result->field_count, stmt->persistent);
if (!result) {
@@ -571,28 +605,30 @@
DBG_INF_FMT("server_status=%u cursor=%u", UPSERT_STATUS_GET_SERVER_STATUS(stmt->upsert_status),
UPSERT_STATUS_GET_SERVER_STATUS(stmt->upsert_status) & SERVER_STATUS_CURSOR_EXISTS);
- if (UPSERT_STATUS_GET_SERVER_STATUS(stmt->upsert_status) & SERVER_STATUS_CURSOR_EXISTS) {
- DBG_INF("cursor exists");
- stmt->cursor_exists = TRUE;
- SET_CONNECTION_STATE(&conn->state, CONN_READY);
- /* Only cursor read */
- stmt->default_rset_handler = s->m->use_result;
- DBG_INF("use_result");
- } else if (stmt->flags & CURSOR_TYPE_READ_ONLY) {
- DBG_INF("asked for cursor but got none");
- /*
- We have asked for CURSOR but got no cursor, because the condition
- above is not fulfilled. Then...
-
- This is a single-row result set, a result set with no rows, EXPLAIN,
- SHOW VARIABLES, or some other command which either a) bypasses the
- cursors framework in the server and writes rows directly to the
- network or b) is more efficient if all (few) result set rows are
- precached on client and server's resources are freed.
- */
- /* preferred is buffered read */
- stmt->default_rset_handler = s->m->store_result;
- DBG_INF("store_result");
+ if (stmt->flags & CURSOR_TYPE_READ_ONLY) {
+ if (UPSERT_STATUS_GET_SERVER_STATUS(stmt->upsert_status) & SERVER_STATUS_CURSOR_EXISTS) {
+ DBG_INF("cursor exists");
+ stmt->cursor_exists = TRUE;
+ SET_CONNECTION_STATE(&conn->state, CONN_READY);
+ /* Only cursor read */
+ stmt->default_rset_handler = s->m->use_result;
+ DBG_INF("use_result");
+ } else {
+ DBG_INF("asked for cursor but got none");
+ /*
+ We have asked for CURSOR but got no cursor, because the condition
+ above is not fulfilled. Then...
+
+ This is a single-row result set, a result set with no rows, EXPLAIN,
+ SHOW VARIABLES, or some other command which either a) bypasses the
+ cursors framework in the server and writes rows directly to the
+ network or b) is more efficient if all (few) result set rows are
+ precached on client and server's resources are freed.
+ */
+ /* preferred is buffered read */
+ stmt->default_rset_handler = s->m->store_result;
+ DBG_INF("store_result");
+ }
} else {
DBG_INF("no cursor");
/* preferred is unbuffered read */
@@ -1006,11 +1042,7 @@
}
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
- if (!stmt->field_count ||
- (!stmt->cursor_exists && GET_CONNECTION_STATE(&conn->state) != CONN_FETCHING_DATA) ||
- (stmt->cursor_exists && GET_CONNECTION_STATE(&conn->state) != CONN_READY) ||
- (stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE))
- {
+ if (!stmt->field_count || !mysqlnd_stmt_check_state(stmt)) {
SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
DBG_ERR("command out of sync");
DBG_RETURN(NULL);
@@ -1040,7 +1072,6 @@
MYSQLND_STMT * s = (MYSQLND_STMT *) param;
MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
MYSQLND_CONN_DATA * conn = stmt? stmt->conn : NULL;
- zend_uchar buf[MYSQLND_STMT_ID_LENGTH /* statement id */ + 4 /* number of rows to fetch */];
MYSQLND_PACKET_ROW * row_packet;
DBG_ENTER("mysqlnd_fetch_stmt_row_cursor");
@@ -1064,24 +1095,9 @@
SET_EMPTY_ERROR(stmt->error_info);
SET_EMPTY_ERROR(conn->error_info);
- int4store(buf, stmt->stmt_id);
- int4store(buf + MYSQLND_STMT_ID_LENGTH, 1); /* for now fetch only one row */
-
- {
- const MYSQLND_CSTRING payload = {(const char*) buf, sizeof(buf)};
- struct st_mysqlnd_protocol_command * command = conn->command_factory(COM_STMT_FETCH, conn, payload);
- ret = FAIL;
- if (command) {
- ret = command->run(command);
- command->free_command(command);
- if (ret == FAIL) {
- COPY_CLIENT_ERROR(stmt->error_info, *conn->error_info);
- }
- }
- if (FAIL == ret) {
- DBG_RETURN(FAIL);
- }
-
+ /* for now fetch only one row */
+ if (mysqlnd_stmt_send_cursor_fetch_command(stmt, 1) == FAIL) {
+ DBG_RETURN(FAIL);
}
row_packet->skip_extraction = stmt->result_bind? FALSE:TRUE;
Loading…
Cancel
Save