Add support for begin_transaction in libmysql mode.

Add support for flags and name for commit/rollback in libmysql mode
This commit is contained in:
Andrey Hristov 2013-02-07 18:45:49 +01:00
parent 403d4fbbff
commit afacdecd1f
8 changed files with 289 additions and 36 deletions

View file

@ -30,6 +30,7 @@
#include "php_ini.h" #include "php_ini.h"
#include "php_globals.h" #include "php_globals.h"
#include "ext/standard/info.h" #include "ext/standard/info.h"
#include "ext/standard/php_smart_str.h"
#include "php_mysqli_structs.h" #include "php_mysqli_structs.h"
#include "mysqli_priv.h" #include "mysqli_priv.h"
@ -635,18 +636,86 @@ PHP_FUNCTION(mysqli_close)
} }
/* }}} */ /* }}} */
#if !defined(MYSQLI_USE_MYSQLND)
/* {{{ mysqli_tx_cor_options_to_string */
static void mysqli_tx_cor_options_to_string(const MYSQL * const conn, smart_str * str, const unsigned int mode)
{
if (mode & TRANS_COR_AND_CHAIN && !(mode & TRANS_COR_AND_NO_CHAIN)) {
if (str->len) {
smart_str_appendl(str, ", ", sizeof(", ") - 1);
}
smart_str_appendl(str, "AND CHAIN", sizeof("AND CHAIN") - 1);
} else if (mode & TRANS_COR_AND_NO_CHAIN && !(mode & TRANS_COR_AND_CHAIN)) {
if (str->len) {
smart_str_appendl(str, ", ", sizeof(", ") - 1);
}
smart_str_appendl(str, "AND NO CHAIN", sizeof("AND NO CHAIN") - 1);
}
if (mode & TRANS_COR_RELEASE && !(mode & TRANS_COR_NO_RELEASE)) {
if (str->len) {
smart_str_appendl(str, ", ", sizeof(", ") - 1);
}
smart_str_appendl(str, "RELEASE", sizeof("RELEASE") - 1);
} else if (mode & TRANS_COR_NO_RELEASE && !(mode & TRANS_COR_RELEASE)) {
if (str->len) {
smart_str_appendl(str, ", ", sizeof(", ") - 1);
}
smart_str_appendl(str, "NO RELEASE", sizeof("NO RELEASE") - 1);
}
smart_str_0(str);
}
/* }}} */
/* {{{ proto bool mysqli_commit_or_rollback_libmysql */
static int mysqli_commit_or_rollback_libmysql(MYSQL * conn, zend_bool commit, const unsigned int mode, const char * const name)
{
int ret;
smart_str tmp_str = {0, 0, 0};
mysqli_tx_cor_options_to_string(conn, &tmp_str, mode);
smart_str_0(&tmp_str);
{
char * commented_name = NULL;
unsigned int commented_name_len = name? spprintf(&commented_name, 0, " /*%s*/", name):0;
char * query;
unsigned int query_len = spprintf(&query, 0, (commit? "COMMIT%s %s":"ROLLBACK%s %s"),
commented_name? commented_name:"", tmp_str.c? tmp_str.c:"");
smart_str_free(&tmp_str);
ret = mysql_real_query(conn, query, query_len);
efree(query);
if (commented_name) {
efree(commented_name);
}
}
}
/* }}} */
#endif
/* {{{ proto bool mysqli_commit(object link) /* {{{ proto bool mysqli_commit(object link)
Commit outstanding actions and close transaction */ Commit outstanding actions and close transaction */
PHP_FUNCTION(mysqli_commit) PHP_FUNCTION(mysqli_commit)
{ {
MY_MYSQL *mysql; MY_MYSQL *mysql;
zval *mysql_link; zval *mysql_link;
long flags = TRANS_COR_NO_OPT;
char * name = NULL;
int name_len = 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|ls", &mysql_link, mysqli_link_class_entry, &flags, &name, &name_len) == FAILURE) {
return; return;
} }
MYSQLI_FETCH_RESOURCE_CONN(mysql, &mysql_link, MYSQLI_STATUS_VALID); MYSQLI_FETCH_RESOURCE_CONN(mysql, &mysql_link, MYSQLI_STATUS_VALID);
if (mysql_commit(mysql->mysql)) {
#if !defined(MYSQLI_USE_MYSQLND)
if (mysqli_commit_or_rollback_libmysql(mysql->mysql, TRUE, flags, name)) {
#else
if (mysqlnd_commit(mysql->mysql, flags, name)) {
#endif
RETURN_FALSE; RETURN_FALSE;
} }
RETURN_TRUE; RETURN_TRUE;
@ -1872,19 +1941,27 @@ PHP_FUNCTION(mysqli_real_escape_string) {
} }
/* }}} */ /* }}} */
/* {{{ proto bool mysqli_rollback(object link) /* {{{ proto bool mysqli_rollback(object link)
Undo actions from current transaction */ Undo actions from current transaction */
PHP_FUNCTION(mysqli_rollback) PHP_FUNCTION(mysqli_rollback)
{ {
MY_MYSQL *mysql; MY_MYSQL *mysql;
zval *mysql_link; zval *mysql_link;
long flags = TRANS_COR_NO_OPT;
char * name = NULL;
int name_len = 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|ls", &mysql_link, mysqli_link_class_entry, &flags, &name, &name_len) == FAILURE) {
return; return;
} }
MYSQLI_FETCH_RESOURCE_CONN(mysql, &mysql_link, MYSQLI_STATUS_VALID); MYSQLI_FETCH_RESOURCE_CONN(mysql, &mysql_link, MYSQLI_STATUS_VALID);
if (mysql_rollback(mysql->mysql)) { #if !defined(MYSQLI_USE_MYSQLND)
if (mysqli_commit_or_rollback_libmysql(mysql->mysql, FALSE, flags, name)) {
#else
if (mysqlnd_rollback(mysql->mysql, flags, name)) {
#endif
RETURN_FALSE; RETURN_FALSE;
} }
RETURN_TRUE; RETURN_TRUE;

View file

@ -86,6 +86,38 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_mysqli_autocommit, 0, 0, 1)
ZEND_ARG_INFO(0, mode) ZEND_ARG_INFO(0, mode)
ZEND_END_ARG_INFO() ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqli_begin_transaction, 0, 0, 1)
MYSQLI_ZEND_ARG_OBJ_INFO_LINK()
ZEND_ARG_INFO(0, flags)
ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_mysqli_begin_transaction, 0, 0, 0)
ZEND_ARG_INFO(0, flags)
ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqli_commit, 0, 0, 1)
MYSQLI_ZEND_ARG_OBJ_INFO_LINK()
ZEND_ARG_INFO(0, flags)
ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_mysqli_commit, 0, 0, 0)
ZEND_ARG_INFO(0, flags)
ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqli_rollback, 0, 0, 1)
MYSQLI_ZEND_ARG_OBJ_INFO_LINK()
ZEND_ARG_INFO(0, flags)
ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_mysqli_rollback, 0, 0, 0)
ZEND_ARG_INFO(0, flags)
ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqli_change_user, 0, 0, 4) ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqli_change_user, 0, 0, 4)
MYSQLI_ZEND_ARG_OBJ_INFO_LINK() MYSQLI_ZEND_ARG_OBJ_INFO_LINK()
@ -326,10 +358,11 @@ ZEND_END_ARG_INFO()
const zend_function_entry mysqli_functions[] = { const zend_function_entry mysqli_functions[] = {
PHP_FE(mysqli_affected_rows, arginfo_mysqli_only_link) PHP_FE(mysqli_affected_rows, arginfo_mysqli_only_link)
PHP_FE(mysqli_autocommit, arginfo_mysqli_autocommit) PHP_FE(mysqli_autocommit, arginfo_mysqli_autocommit)
PHP_FE(mysqli_begin_transaction, arginfo_mysqli_begin_transaction)
PHP_FE(mysqli_change_user, arginfo_mysqli_change_user) PHP_FE(mysqli_change_user, arginfo_mysqli_change_user)
PHP_FE(mysqli_character_set_name, arginfo_mysqli_only_link) PHP_FE(mysqli_character_set_name, arginfo_mysqli_only_link)
PHP_FE(mysqli_close, arginfo_mysqli_only_link) PHP_FE(mysqli_close, arginfo_mysqli_only_link)
PHP_FE(mysqli_commit, arginfo_mysqli_only_link) PHP_FE(mysqli_commit, arginfo_mysqli_commit)
PHP_FE(mysqli_connect, arginfo_mysqli_connect) PHP_FE(mysqli_connect, arginfo_mysqli_connect)
PHP_FE(mysqli_connect_errno, arginfo_mysqli_no_params) PHP_FE(mysqli_connect_errno, arginfo_mysqli_no_params)
PHP_FE(mysqli_connect_error, arginfo_mysqli_no_params) PHP_FE(mysqli_connect_error, arginfo_mysqli_no_params)
@ -397,7 +430,7 @@ const zend_function_entry mysqli_functions[] = {
#if defined(MYSQLI_USE_MYSQLND) #if defined(MYSQLI_USE_MYSQLND)
PHP_FE(mysqli_reap_async_query, arginfo_mysqli_only_link) PHP_FE(mysqli_reap_async_query, arginfo_mysqli_only_link)
#endif #endif
PHP_FE(mysqli_rollback, arginfo_mysqli_only_link) PHP_FE(mysqli_rollback, arginfo_mysqli_rollback)
PHP_FE(mysqli_select_db, arginfo_mysqli_select_db) PHP_FE(mysqli_select_db, arginfo_mysqli_select_db)
#ifdef HAVE_MYSQLI_SET_CHARSET #ifdef HAVE_MYSQLI_SET_CHARSET
PHP_FE(mysqli_set_charset, arginfo_mysqli_set_charset) PHP_FE(mysqli_set_charset, arginfo_mysqli_set_charset)
@ -458,10 +491,11 @@ const zend_function_entry mysqli_functions[] = {
*/ */
const zend_function_entry mysqli_link_methods[] = { const zend_function_entry mysqli_link_methods[] = {
PHP_FALIAS(autocommit, mysqli_autocommit, arginfo_class_mysqli_autocommit) PHP_FALIAS(autocommit, mysqli_autocommit, arginfo_class_mysqli_autocommit)
PHP_FALIAS(begin_transaction, mysqli_begin_transaction, arginfo_class_mysqli_begin_transaction)
PHP_FALIAS(change_user,mysqli_change_user, arginfo_class_mysqli_change_user) PHP_FALIAS(change_user,mysqli_change_user, arginfo_class_mysqli_change_user)
PHP_FALIAS(character_set_name, mysqli_character_set_name, arginfo_mysqli_no_params) PHP_FALIAS(character_set_name, mysqli_character_set_name, arginfo_mysqli_no_params)
PHP_FALIAS(close, mysqli_close, arginfo_mysqli_no_params) PHP_FALIAS(close, mysqli_close, arginfo_mysqli_no_params)
PHP_FALIAS(commit, mysqli_commit, arginfo_mysqli_no_params) PHP_FALIAS(commit, mysqli_commit, arginfo_class_mysqli_commit)
PHP_FALIAS(connect, mysqli_connect, arginfo_mysqli_connect) PHP_FALIAS(connect, mysqli_connect, arginfo_mysqli_connect)
PHP_FALIAS(dump_debug_info, mysqli_dump_debug_info, arginfo_mysqli_no_params) PHP_FALIAS(dump_debug_info, mysqli_dump_debug_info, arginfo_mysqli_no_params)
PHP_FALIAS(debug, mysqli_debug, arginfo_mysqli_debug) PHP_FALIAS(debug, mysqli_debug, arginfo_mysqli_debug)
@ -494,7 +528,7 @@ const zend_function_entry mysqli_link_methods[] = {
#endif #endif
PHP_FALIAS(escape_string, mysqli_real_escape_string, arginfo_class_mysqli_real_escape_string) PHP_FALIAS(escape_string, mysqli_real_escape_string, arginfo_class_mysqli_real_escape_string)
PHP_FALIAS(real_query, mysqli_real_query, arginfo_class_mysqli_query) PHP_FALIAS(real_query, mysqli_real_query, arginfo_class_mysqli_query)
PHP_FALIAS(rollback,mysqli_rollback, arginfo_mysqli_no_params) PHP_FALIAS(rollback, mysqli_rollback, arginfo_class_mysqli_rollback)
PHP_FALIAS(select_db,mysqli_select_db, arginfo_class_mysqli_select_db) PHP_FALIAS(select_db,mysqli_select_db, arginfo_class_mysqli_select_db)
#ifdef HAVE_MYSQLI_SET_CHARSET #ifdef HAVE_MYSQLI_SET_CHARSET
PHP_FALIAS(set_charset, mysqli_set_charset, arginfo_class_mysqli_set_charset) PHP_FALIAS(set_charset, mysqli_set_charset, arginfo_class_mysqli_set_charset)

View file

@ -25,6 +25,7 @@
PHP_FUNCTION(mysqli); PHP_FUNCTION(mysqli);
PHP_FUNCTION(mysqli_affected_rows); PHP_FUNCTION(mysqli_affected_rows);
PHP_FUNCTION(mysqli_autocommit); PHP_FUNCTION(mysqli_autocommit);
PHP_FUNCTION(mysqli_begin_transaction);
PHP_FUNCTION(mysqli_change_user); PHP_FUNCTION(mysqli_change_user);
PHP_FUNCTION(mysqli_character_set_name); PHP_FUNCTION(mysqli_character_set_name);
PHP_FUNCTION(mysqli_set_charset); PHP_FUNCTION(mysqli_set_charset);

View file

@ -42,6 +42,18 @@
#define mysqli_change_user_silent(c, u, p, d, p_len) mysql_change_user((c), (u), (p), (d)) #define mysqli_change_user_silent(c, u, p, d, p_len) mysql_change_user((c), (u), (p), (d))
#define TRANS_START_NO_OPT 0
#define TRANS_START_WITH_CONSISTENT_SNAPSHOT 1
#define TRANS_START_READ_WRITE 2
#define TRANS_START_READ_ONLY 4
#define TRANS_COR_NO_OPT 0
#define TRANS_COR_AND_CHAIN 1
#define TRANS_COR_AND_NO_CHAIN 2
#define TRANS_COR_RELEASE 4
#define TRANS_COR_NO_RELEASE 8
/* /*
These functions also reside in ext/mysqlnd/mysqlnd_portability.h but since it is only made These functions also reside in ext/mysqlnd/mysqlnd_portability.h but since it is only made
available if one wants to build mysqli against mysqlnd and they are useful for libmysql as available if one wants to build mysqli against mysqlnd and they are useful for libmysql as

View file

@ -29,6 +29,7 @@
#include "php.h" #include "php.h"
#include "php_ini.h" #include "php_ini.h"
#include "ext/standard/info.h" #include "ext/standard/info.h"
#include "ext/standard/php_smart_str.h"
#include "php_mysqli_structs.h" #include "php_mysqli_structs.h"
#include "mysqli_priv.h" #include "mysqli_priv.h"
@ -1045,6 +1046,81 @@ PHP_FUNCTION(mysqli_get_charset)
/* }}} */ /* }}} */
#endif #endif
#if !defined(MYSQLI_USE_MYSQLND)
/* {{{ proto bool mysqli_begin_transaction_libmysql */
static int mysqli_begin_transaction_libmysql(MYSQL * conn, const unsigned int mode, const char * const name)
{
int ret;
smart_str tmp_str = {0, 0, 0};
if (mode & TRANS_START_WITH_CONSISTENT_SNAPSHOT) {
if (tmp_str.len) {
smart_str_appendl(&tmp_str, ", ", sizeof(", ") - 1);
}
smart_str_appendl(&tmp_str, "WITH CONSISTENT SNAPSHOT", sizeof("WITH CONSISTENT SNAPSHOT") - 1);
}
if (mode & TRANS_START_READ_WRITE) {
if (tmp_str.len) {
smart_str_appendl(&tmp_str, ", ", sizeof(", ") - 1);
}
smart_str_appendl(&tmp_str, "READ WRITE", sizeof("READ WRITE") - 1);
}
if (mode & TRANS_START_READ_ONLY) {
if (tmp_str.len) {
smart_str_appendl(&tmp_str, ", ", sizeof(", ") - 1);
}
smart_str_appendl(&tmp_str, "READ ONLY", sizeof("READ ONLY") - 1);
}
smart_str_0(&tmp_str);
{
char * commented_name = NULL;
unsigned int commented_name_len = name? spprintf(&commented_name, 0, " /*%s*/", name):0;
char * query;
unsigned int query_len = spprintf(&query, 0, "START TRANSACTION%s %s",
commented_name? commented_name:"", tmp_str.c? tmp_str.c:"");
smart_str_free(&tmp_str);
ret = mysql_real_query(conn, query, query_len);
efree(query);
if (commented_name) {
efree(commented_name);
}
}
return ret;
}
/* }}} */
#endif
/* {{{ proto bool mysqli_begin_transaction(object link, [int flags [, string name]])
Starts a transaction */
PHP_FUNCTION(mysqli_begin_transaction)
{
MY_MYSQL *mysql;
zval *mysql_link;
long flags = TRANS_START_NO_OPT;
char * name = NULL;
int name_len = 0;
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O|ls", &mysql_link, mysqli_link_class_entry, &flags, &name, &name_len) == FAILURE) {
return;
}
MYSQLI_FETCH_RESOURCE_CONN(mysql, &mysql_link, MYSQLI_STATUS_VALID);
#if !defined(MYSQLI_USE_MYSQLND)
if (mysqli_begin_transaction_libmysql(mysql->mysql, flags, name)) {
RETURN_FALSE;
}
#else
if (mysqlnd_begin_transaction(mysql->mysql, flags, name)) {
RETURN_FALSE;
}
#endif
RETURN_TRUE;
}
/* }}} */
/* /*
* Local variables: * Local variables:
* tab-width: 4 * tab-width: 4

View file

@ -20,6 +20,7 @@ require_once('skipifconnectfailure.inc');
$methods = get_class_methods($mysqli); $methods = get_class_methods($mysqli);
$expected_methods = array( $expected_methods = array(
'autocommit' => true, 'autocommit' => true,
'begin_transaction' => true,
'change_user' => true, 'change_user' => true,
'character_set_name' => true, 'character_set_name' => true,
'close' => true, 'close' => true,

View file

@ -6,8 +6,6 @@ require_once('skipif.inc');
require_once('skipifemb.inc'); require_once('skipifemb.inc');
require_once('connect.inc'); require_once('connect.inc');
if (($tmp = substr(PHP_VERSION, 0, strpos(PHP_VERSION, '.'))) && ($tmp < 5))
die("skip Reflection not available before PHP 5 (found PHP $tmp)");
/* /*
Let's not deal with cross-version issues in the EXPECTF/UEXPECTF. Let's not deal with cross-version issues in the EXPECTF/UEXPECTF.
Most of the things which we test are covered by mysqli_class_*_interface.phpt. Most of the things which we test are covered by mysqli_class_*_interface.phpt.
@ -120,6 +118,36 @@ isPassedByReference: no
isOptional: no isOptional: no
isDefaultValueAvailable: no isDefaultValueAvailable: no
Inspecting method 'begin_transaction'
isFinal: no
isAbstract: no
isPublic: yes
isPrivate: no
isProtected: no
isStatic: no
isConstructor: no
isDestructor: no
isInternal: yes
isUserDefined: no
returnsReference: no
Modifiers: 256
Number of Parameters: 2
Number of Required Parameters: 0
Inspecting parameter 'flags' of method 'begin_transaction'
isArray: no
allowsNull: no
isPassedByReference: no
isOptional: yes
isDefaultValueAvailable: no
Inspecting parameter 'name' of method 'begin_transaction'
isArray: no
allowsNull: no
isPassedByReference: no
isOptional: yes
isDefaultValueAvailable: no
Inspecting method 'change_user' Inspecting method 'change_user'
isFinal: no isFinal: no
isAbstract: no isAbstract: no
@ -202,9 +230,23 @@ isInternal: yes
isUserDefined: no isUserDefined: no
returnsReference: no returnsReference: no
Modifiers: 256 Modifiers: 256
Number of Parameters: 0 Number of Parameters: 2
Number of Required Parameters: 0 Number of Required Parameters: 0
Inspecting parameter 'flags' of method 'commit'
isArray: no
allowsNull: no
isPassedByReference: no
isOptional: yes
isDefaultValueAvailable: no
Inspecting parameter 'name' of method 'commit'
isArray: no
allowsNull: no
isPassedByReference: no
isOptional: yes
isDefaultValueAvailable: no
Inspecting method 'connect' Inspecting method 'connect'
isFinal: no isFinal: no
isAbstract: no isAbstract: no
@ -863,9 +905,23 @@ isInternal: yes
isUserDefined: no isUserDefined: no
returnsReference: no returnsReference: no
Modifiers: 256 Modifiers: 256
Number of Parameters: 0 Number of Parameters: 2
Number of Required Parameters: 0 Number of Required Parameters: 0
Inspecting parameter 'flags' of method 'rollback'
isArray: no
allowsNull: no
isPassedByReference: no
isOptional: yes
isDefaultValueAvailable: no
Inspecting parameter 'name' of method 'rollback'
isArray: no
allowsNull: no
isPassedByReference: no
isOptional: yes
isDefaultValueAvailable: no
Inspecting method 'select_db' Inspecting method 'select_db'
isFinal: no isFinal: no
isAbstract: no isAbstract: no

View file

@ -28,12 +28,8 @@ if (!have_innodb($link))
printf("[001] Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n", 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); $host, $user, $db, $port, $socket);
if (!is_null($tmp = @$mysqli->commit($link)))
printf("[002] Expecting NULL/NULL, got %s/%s, [%d] %s\n",
gettype($tmp), $tmp, $mysqli->errno, $mysqli->error);
if (true !== ($tmp = $mysqli->commit())) if (true !== ($tmp = $mysqli->commit()))
printf("[014] Expecting boolean/true got %s/%s\n", gettype($tmp), $tmp); printf("[002] Expecting boolean/true got %s/%s\n", gettype($tmp), $tmp);
if (true !== ($tmp = $mysqli->autocommit(false))) if (true !== ($tmp = $mysqli->autocommit(false)))
printf("[003] Cannot turn off autocommit, expecting true, got %s/%s\n", gettype($tmp), $tmp); printf("[003] Cannot turn off autocommit, expecting true, got %s/%s\n", gettype($tmp), $tmp);