From a3a0f37a8241e937688c66f9d8187a239f210033 Mon Sep 17 00:00:00 2001 From: Dharman Date: Thu, 17 Sep 2020 23:45:17 +0100 Subject: [PATCH 1/2] Trigger exceptions for autocommit, commit, rollback and mysqli_stmt_attr_set mysqli_report test cases for autocommit, commit, rollback and mysqli_stmt_attr_set Updated test case with no warning control case --- ext/mysqli/mysqli_api.c | 4 ++++ ext/mysqli/tests/mysqli_report.phpt | 35 +++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/ext/mysqli/mysqli_api.c b/ext/mysqli/mysqli_api.c index 91915809428a0..34126f0ebb1bf 100644 --- a/ext/mysqli/mysqli_api.c +++ b/ext/mysqli/mysqli_api.c @@ -169,6 +169,7 @@ PHP_FUNCTION(mysqli_autocommit) MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID); if (mysql_autocommit(mysql->mysql, (my_bool)automode)) { + MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql); RETURN_FALSE; } RETURN_TRUE; @@ -708,6 +709,7 @@ PHP_FUNCTION(mysqli_commit) #else if (FAIL == mysqlnd_commit(mysql->mysql, flags, name)) { #endif + MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql); RETURN_FALSE; } RETURN_TRUE; @@ -1927,6 +1929,7 @@ PHP_FUNCTION(mysqli_rollback) #else if (FAIL == mysqlnd_rollback(mysql->mysql, flags, name)) { #endif + MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql); RETURN_FALSE; } RETURN_TRUE; @@ -2297,6 +2300,7 @@ PHP_FUNCTION(mysqli_stmt_attr_set) #else if (FAIL == mysql_stmt_attr_set(stmt->stmt, attr, mode_p)) { #endif + MYSQLI_REPORT_STMT_ERROR(stmt->stmt); RETURN_FALSE; } RETURN_TRUE; diff --git a/ext/mysqli/tests/mysqli_report.phpt b/ext/mysqli/tests/mysqli_report.phpt index dda3c3ec734b2..38f56b439eb19 100644 --- a/ext/mysqli/tests/mysqli_report.phpt +++ b/ext/mysqli/tests/mysqli_report.phpt @@ -49,6 +49,18 @@ require_once('skipifconnectfailure.inc'); printf("[009] select_db should have failed\n"); // mysqli_store_result() and mysqli_use_result() cannot be tested, because one would need to cause an error inside the C function to test it + mysqli_multi_query($link, "SELECT 1; FOO;"); + mysqli_autocommit($link, true); + mysqli_commit($link); + mysqli_rollback($link); + while(mysqli_more_results($link)) { + mysqli_next_result($link); + $res = mysqli_store_result($link); + } + mysqli_next_result($link); + + $stmt = mysqli_prepare($link, "SELECT 1"); + mysqli_stmt_attr_set($stmt, MYSQLI_STMT_ATTR_CURSOR_TYPE, MYSQLI_CURSOR_TYPE_FOR_UPDATE); // Check that none of the above would have caused any error messages if MYSQL_REPORT_ERROR would // not have been set. If that would be the case, the test would be broken. @@ -65,6 +77,19 @@ require_once('skipifconnectfailure.inc'); mysqli_real_query($link, "FOO"); mysqli_select_db($link, "Oh lord, let this be an unknown database name"); + mysqli_multi_query($link, "SELECT 1; FOO;"); + mysqli_autocommit($link, true); + mysqli_commit($link); + mysqli_rollback($link); + while(mysqli_more_results($link)) { + mysqli_next_result($link); + $res = mysqli_store_result($link); + } + mysqli_next_result($link); + + $stmt = mysqli_prepare($link, "SELECT 1"); + mysqli_stmt_attr_set($stmt, MYSQLI_STMT_ATTR_CURSOR_TYPE, MYSQLI_CURSOR_TYPE_FOR_UPDATE); + /* Internal macro MYSQL_REPORT_STMT_ERROR */ @@ -292,6 +317,16 @@ mysqli_kill(): Argument #2 ($process_id) must be greater than 0 Warning: mysqli_prepare(): (%d/%d): You have an error in your SQL syntax; check the manual that corresponds to your %s server version for the right syntax to use near 'FOO' at line 1 in %s on line %d Warning: mysqli_real_query(): (%d/%d): You have an error in your SQL syntax; check the manual that corresponds to your %s server version for the right syntax to use near 'FOO' at line 1 in %s on line %d + +Warning: mysqli_autocommit(): (%s/%d): Commands out of sync; you can't run this command now in %s on line %d + +Warning: mysqli_commit(): (%s/%d): Commands out of sync; you can't run this command now in %s on line %d + +Warning: mysqli_rollback(): (%s/%d): Commands out of sync; you can't run this command now in %s on line %d + +Warning: mysqli_store_result(): (%s/%d): You have an error in your SQL syntax; check the manual that corresponds to your %s server version for the right syntax to use near 'FOO' at line 1 in %s on line %d + +Warning: mysqli_stmt_attr_set(): (%s/%d): Not implemented in %s on line %d mysqli_kill(): Argument #2 ($process_id) must be greater than 0 Warning: mysqli_stmt_prepare(): (%d/%d): You have an error in your SQL syntax; check the manual that corresponds to your %s server version for the right syntax to use near 'FOO' at line 1 in %s on line %d From f14ed7b7f45d58d0227494cd5be39fcdc8f868c7 Mon Sep 17 00:00:00 2001 From: Dharman Date: Fri, 18 Sep 2020 21:49:09 +0100 Subject: [PATCH 2/2] If mysqli_stmt_prepare fails then the error is populated in conn not in stmt However, mysqli_stmt_prepare only checks for errors in statement. If exception mode is enabled the exception is not triggered because of this flawed logic. Fix: copy the error from conn to stmt. If mysqli_stmt_prepare is called from mysqli_prepare then it doesn't matter because we unset stmt immediately and check for errors in conn. --- ext/mysqli/tests/mysqli_report.phpt | 6 ++++++ ext/mysqlnd/mysqlnd_ps.c | 1 + 2 files changed, 7 insertions(+) diff --git a/ext/mysqli/tests/mysqli_report.phpt b/ext/mysqli/tests/mysqli_report.phpt index 38f56b439eb19..1dbf1e4dc19ce 100644 --- a/ext/mysqli/tests/mysqli_report.phpt +++ b/ext/mysqli/tests/mysqli_report.phpt @@ -53,6 +53,8 @@ require_once('skipifconnectfailure.inc'); mysqli_autocommit($link, true); mysqli_commit($link); mysqli_rollback($link); + $stmt = mysqli_stmt_init($link); + mysqli_stmt_prepare($stmt, "SELECT id FROM test WHERE id > ?"); while(mysqli_more_results($link)) { mysqli_next_result($link); $res = mysqli_store_result($link); @@ -81,6 +83,8 @@ require_once('skipifconnectfailure.inc'); mysqli_autocommit($link, true); mysqli_commit($link); mysqli_rollback($link); + $stmt = mysqli_stmt_init($link); + mysqli_stmt_prepare($stmt, "SELECT id FROM test WHERE id > ?"); while(mysqli_more_results($link)) { mysqli_next_result($link); $res = mysqli_store_result($link); @@ -324,6 +328,8 @@ Warning: mysqli_commit(): (%s/%d): Commands out of sync; you can't run this comm Warning: mysqli_rollback(): (%s/%d): Commands out of sync; you can't run this command now in %s on line %d +Warning: mysqli_stmt_prepare(): (%s/%d): Commands out of sync; you can't run this command now in %s on line %d + Warning: mysqli_store_result(): (%s/%d): You have an error in your SQL syntax; check the manual that corresponds to your %s server version for the right syntax to use near 'FOO' at line 1 in %s on line %d Warning: mysqli_stmt_attr_set(): (%s/%d): Not implemented in %s on line %d diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index 2415b91a3b837..296304da121c7 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -407,6 +407,7 @@ MYSQLND_METHOD(mysqlnd_stmt, prepare)(MYSQLND_STMT * const s, const char * const ret = conn->command->stmt_prepare(conn, query_string); if (FAIL == ret) { + COPY_CLIENT_ERROR(stmt->error_info, *conn->error_info); goto fail; } }