From 832c30f38df10fdab235894fa395004dd983d660 Mon Sep 17 00:00:00 2001 From: SakiTakamachi Date: Wed, 1 Nov 2023 01:30:44 +0900 Subject: [PATCH] Added transaction check process fix macro fix report flags fix tests fix tests --- ext/mysqli/mysqli_api.c | 13 +++++++++-- ext/mysqli/mysqli_nonapi.c | 5 ++++ ext/mysqli/php_mysqli_structs.h | 2 ++ .../tests/mysqli_begin_transaction.phpt | 23 ++++++++++++++++--- ext/mysqli/tests/mysqli_commit.phpt | 9 ++++++++ ext/mysqli/tests/mysqli_commit_oo.phpt | 6 +++++ ext/mysqli/tests/mysqli_report.phpt | 8 +++++-- ext/mysqli/tests/mysqli_rollback.phpt | 9 ++++++++ 8 files changed, 68 insertions(+), 7 deletions(-) diff --git a/ext/mysqli/mysqli_api.c b/ext/mysqli/mysqli_api.c index 68b55e1d78d35..b933f3caae788 100644 --- a/ext/mysqli/mysqli_api.c +++ b/ext/mysqli/mysqli_api.c @@ -313,6 +313,11 @@ PHP_FUNCTION(mysqli_commit) } MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID); + if (!MYSQLI_IS_IN_TRANSACTION(mysql)) { + php_mysqli_report_error(NULL, 0, "There is no active transaction"); + RETURN_FALSE; + } + if (FAIL == mysqlnd_commit(mysql->mysql, flags, name)) { MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql); RETURN_FALSE; @@ -523,12 +528,12 @@ PHP_FUNCTION(mysqli_execute_query) if (FAIL == mysql_stmt_prepare(stmt->stmt, query, query_len)) { MYSQLI_REPORT_STMT_ERROR(stmt->stmt); - + close_stmt_and_copy_errors(stmt, mysql); RETURN_FALSE; } - /* The bit below, which is copied from mysqli_prepare, is needed for bad index exceptions */ + /* The bit below, which is copied from mysqli_prepare, is needed for bad index exceptions */ /* don't initialize stmt->query with NULL, we ecalloc()-ed the memory */ /* Get performance boost if reporting is switched off */ if (query_len && (MyG(report_mode) & MYSQLI_REPORT_INDEX)) { @@ -1420,6 +1425,10 @@ PHP_FUNCTION(mysqli_rollback) } MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID); + if (!MYSQLI_IS_IN_TRANSACTION(mysql)) { + php_mysqli_report_error(NULL, 0, "There is no active transaction"); + RETURN_FALSE; + } if (FAIL == mysqlnd_rollback(mysql->mysql, flags, name)) { MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql); diff --git a/ext/mysqli/mysqli_nonapi.c b/ext/mysqli/mysqli_nonapi.c index 406d928699784..e15cd3fb16837 100644 --- a/ext/mysqli/mysqli_nonapi.c +++ b/ext/mysqli/mysqli_nonapi.c @@ -1021,6 +1021,11 @@ PHP_FUNCTION(mysqli_begin_transaction) RETURN_THROWS(); } + if (MYSQLI_IS_IN_TRANSACTION(mysql)) { + php_mysqli_report_error(NULL, 0, "There is already an active transaction"); + RETURN_FALSE; + } + if (FAIL == mysqlnd_begin_transaction(mysql->mysql, flags, name)) { RETURN_FALSE; } diff --git a/ext/mysqli/php_mysqli_structs.h b/ext/mysqli/php_mysqli_structs.h index 7495cc8bda733..171af8c0832ed 100644 --- a/ext/mysqli/php_mysqli_structs.h +++ b/ext/mysqli/php_mysqli_structs.h @@ -234,6 +234,8 @@ extern void php_mysqli_fetch_into_hash_aux(zval *return_value, MYSQL_RES * resul intern->ptr = NULL; \ } +#define MYSQLI_IS_IN_TRANSACTION(__mysql) \ + ((mysqli_server_status(__mysql->mysql) & SERVER_STATUS_IN_TRANS) != 0) ZEND_BEGIN_MODULE_GLOBALS(mysqli) zend_long num_links; diff --git a/ext/mysqli/tests/mysqli_begin_transaction.phpt b/ext/mysqli/tests/mysqli_begin_transaction.phpt index 7a7d7e36fba4e..b568ee2fbccd2 100644 --- a/ext/mysqli/tests/mysqli_begin_transaction.phpt +++ b/ext/mysqli/tests/mysqli_begin_transaction.phpt @@ -85,14 +85,30 @@ if (!have_innodb($link)) if (mysqli_get_server_version($link) >= 50605) { /* 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)); + if (@!$link->begin_transaction(MYSQLI_TRANS_START_READ_WRITE, "*/trick me?\n\0")) { + printf("[020] [%d] %s\n", mysqli_errno($link), mysqli_error($link)); + } else { + mysqli_rollback($link); + } /* does it like stupid names? */ - if (@!$link->begin_transaction(MYSQLI_TRANS_START_READ_WRITE, "az09")) + if (@!$link->begin_transaction(MYSQLI_TRANS_START_READ_WRITE, "az09")) { printf("[021] [%d] %s\n", mysqli_errno($link), mysqli_error($link)); + } else { + mysqli_rollback($link); + } } + mysqli_report(MYSQLI_REPORT_ERROR|MYSQLI_REPORT_STRICT); + try { + mysqli_begin_transaction($link); + mysqli_begin_transaction($link); + } catch (\mysqli_sql_exception $e) { + echo $e->getMessage() . \PHP_EOL; + } + + mysqli_rollback($link); + print "done!"; ?> --CLEAN-- @@ -102,4 +118,5 @@ if (!have_innodb($link)) --EXPECT-- NULL mysqli_begin_transaction(): Argument #2 ($flags) must be one of the MYSQLI_TRANS_* constants +There is already an active transaction done! diff --git a/ext/mysqli/tests/mysqli_commit.phpt b/ext/mysqli/tests/mysqli_commit.phpt index f5b64e1251179..6480a4498ad99 100644 --- a/ext/mysqli/tests/mysqli_commit.phpt +++ b/ext/mysqli/tests/mysqli_commit.phpt @@ -56,6 +56,14 @@ if (!have_innodb($link)) echo $exception->getMessage() . "\n"; } + $link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket); + mysqli_report(MYSQLI_REPORT_ERROR|MYSQLI_REPORT_STRICT); + try { + mysqli_commit($link); + } catch (\mysqli_sql_exception $e) { + echo $e->getMessage() . \PHP_EOL; + } + print "done!"; ?> --CLEAN-- @@ -64,4 +72,5 @@ require_once 'clean_table.inc'; ?> --EXPECT-- mysqli object is already closed +There is no active transaction done! diff --git a/ext/mysqli/tests/mysqli_commit_oo.phpt b/ext/mysqli/tests/mysqli_commit_oo.phpt index d0ff739b8af3a..6072bc5472e37 100644 --- a/ext/mysqli/tests/mysqli_commit_oo.phpt +++ b/ext/mysqli/tests/mysqli_commit_oo.phpt @@ -24,6 +24,7 @@ if (!have_innodb($link)) $mysqli = new my_mysqli($host, $user, $passwd, $db, $port, $socket); + $mysqli->begin_transaction(); if (true !== ($tmp = $mysqli->commit())) { printf("[002] Expecting boolean/true got %s/%s\n", gettype($tmp), $tmp); } @@ -66,16 +67,21 @@ if (!have_innodb($link)) printf("[011] [%d] %s\n", $mysqli->errno, $mysqli->error); } + $mysqli->begin_transaction(); if (!$mysqli->commit(0 , "tx_name0123")) { printf("[012] [%d] %s\n", $mysqli->errno, $mysqli->error); } + $mysqli->begin_transaction(); var_dump($mysqli->commit(0 , "*/ nonsense")); + $mysqli->begin_transaction(); var_dump($mysqli->commit(0 , "tx_name ulf вендел")); + $mysqli->begin_transaction(); var_dump($mysqli->commit(0 , "tx_name \t\n\r\b")); + $mysqli->begin_transaction(); if (!$mysqli->commit(MYSQLI_TRANS_COR_AND_CHAIN | MYSQLI_TRANS_COR_NO_RELEASE , "tx_name")) { printf("[016] [%d] %s\n", $mysqli->errno, $mysqli->error); } diff --git a/ext/mysqli/tests/mysqli_report.phpt b/ext/mysqli/tests/mysqli_report.phpt index b4998546d1373..23141b7e9b2e4 100644 --- a/ext/mysqli/tests/mysqli_report.phpt +++ b/ext/mysqli/tests/mysqli_report.phpt @@ -323,9 +323,9 @@ Warning: mysqli_real_query(): (%d/%d): You have an error in your SQL syntax; che 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_commit(): (%s/%d): There is no active transaction 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_rollback(): (%s/%d): There is no active transaction 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 @@ -336,6 +336,10 @@ Warning: mysqli_store_result(): (%s/%d): You have an error in your SQL syntax; c 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_commit(): (%s/%d): There is no active transaction in %s on line %d + +Warning: mysqli_rollback(): (%s/%d): There is no active transaction in %s on line %d + 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 [013] Access denied for user '%s'@'%s'%r( \(using password: \w+\)){0,1}%r [016] Access denied for user '%s'@'%s'%r( \(using password: \w+\)){0,1}%r diff --git a/ext/mysqli/tests/mysqli_rollback.phpt b/ext/mysqli/tests/mysqli_rollback.phpt index 70a142dd6aeda..cff671c23e08f 100644 --- a/ext/mysqli/tests/mysqli_rollback.phpt +++ b/ext/mysqli/tests/mysqli_rollback.phpt @@ -53,6 +53,14 @@ if (!have_innodb($link)) echo $exception->getMessage() . "\n"; } + $link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket); + mysqli_report(MYSQLI_REPORT_ERROR|MYSQLI_REPORT_STRICT); + try { + mysqli_rollback($link); + } catch (\mysqli_sql_exception $e) { + echo $e->getMessage() . \PHP_EOL; + } + print "done!\n"; ?> --CLEAN-- @@ -61,4 +69,5 @@ require_once 'clean_table.inc'; ?> --EXPECT-- mysqli object is already closed +There is no active transaction done!