]> granicus.if.org Git - php/commitdiff
Add support for begin_transaction in libmysql mode.
authorAndrey Hristov <andrey@php.net>
Thu, 7 Feb 2013 17:45:49 +0000 (18:45 +0100)
committerAndrey Hristov <andrey@php.net>
Thu, 7 Feb 2013 17:45:49 +0000 (18:45 +0100)
Add support for flags and name for commit/rollback in libmysql mode

ext/mysqli/mysqli_api.c
ext/mysqli/mysqli_fe.c
ext/mysqli/mysqli_fe.h
ext/mysqli/mysqli_libmysql.h
ext/mysqli/mysqli_nonapi.c
ext/mysqli/tests/mysqli_class_mysqli_interface.phpt
ext/mysqli/tests/mysqli_class_mysqli_reflection.phpt
ext/mysqli/tests/mysqli_commit_oo.phpt

index 70a8cc63039d8b99f815e447cc54be304779d561..760ee3c424c102767c08f8f82efbe69a90650be1 100644 (file)
@@ -30,6 +30,7 @@
 #include "php_ini.h"
 #include "php_globals.h"
 #include "ext/standard/info.h"
+#include "ext/standard/php_smart_str.h"
 #include "php_mysqli_structs.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)
    Commit outstanding actions and close transaction */
 PHP_FUNCTION(mysqli_commit)
 {
        MY_MYSQL        *mysql;
        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;
        }
        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_TRUE;
@@ -1872,19 +1941,27 @@ PHP_FUNCTION(mysqli_real_escape_string) {
 }
 /* }}} */
 
+
 /* {{{ proto bool mysqli_rollback(object link)
    Undo actions from current transaction */
 PHP_FUNCTION(mysqli_rollback)
 {
        MY_MYSQL        *mysql;
        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;
        }
        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_TRUE;
index 4ac67269ce44f6a7899ad7d285db5b5f1d797a27..411ab11979e99ae836786679e911cfd51226ae6e 100644 (file)
@@ -86,6 +86,38 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_mysqli_autocommit, 0, 0, 1)
        ZEND_ARG_INFO(0, mode)
 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)
        MYSQLI_ZEND_ARG_OBJ_INFO_LINK()
@@ -326,10 +358,11 @@ ZEND_END_ARG_INFO()
 const zend_function_entry mysqli_functions[] = {
        PHP_FE(mysqli_affected_rows,                                            arginfo_mysqli_only_link)
        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_character_set_name,                                       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_errno,                                            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)
        PHP_FE(mysqli_reap_async_query,                                         arginfo_mysqli_only_link)
 #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)
 #ifdef HAVE_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[] = {
        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(character_set_name, mysqli_character_set_name, 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(dump_debug_info, mysqli_dump_debug_info, arginfo_mysqli_no_params)
        PHP_FALIAS(debug, mysqli_debug, arginfo_mysqli_debug)
@@ -494,7 +528,7 @@ const zend_function_entry mysqli_link_methods[] = {
 #endif
        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(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)
 #ifdef HAVE_MYSQLI_SET_CHARSET
        PHP_FALIAS(set_charset, mysqli_set_charset, arginfo_class_mysqli_set_charset)
index 2edb32cb31c5b1fd52b553f075ad849939c891c1..e6cd3a6678c251852a7617a040ce875b05f51354 100644 (file)
@@ -25,6 +25,7 @@
 PHP_FUNCTION(mysqli);
 PHP_FUNCTION(mysqli_affected_rows);
 PHP_FUNCTION(mysqli_autocommit);
+PHP_FUNCTION(mysqli_begin_transaction);
 PHP_FUNCTION(mysqli_change_user);
 PHP_FUNCTION(mysqli_character_set_name);
 PHP_FUNCTION(mysqli_set_charset);
index 3a7b91b9956fd84c1ae81a4eb411e0fa5841c76b..e10e3702ea762df0a171189181e13ad52e05fc21 100644 (file)
 #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
   available if one wants to build mysqli against mysqlnd and they are useful for libmysql as
index b730d24cd69d88dd59f03f9405207c8345fcd501..c08fbaef28d397b026b8e87f6de25b50ea47e362 100644 (file)
@@ -29,6 +29,7 @@
 #include "php.h"
 #include "php_ini.h"
 #include "ext/standard/info.h"
+#include "ext/standard/php_smart_str.h"
 #include "php_mysqli_structs.h"
 #include "mysqli_priv.h"
 
@@ -1045,6 +1046,81 @@ PHP_FUNCTION(mysqli_get_charset)
 /* }}} */
 #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:
  * tab-width: 4
index 19ba0086fb2596c3a3c751f93ab3ea8260ecb0e0..44e9865e17aac3a5dc1c83f91e45b394263870f5 100644 (file)
@@ -20,38 +20,39 @@ require_once('skipifconnectfailure.inc');
        $methods = get_class_methods($mysqli);
        $expected_methods = array(
                'autocommit'                    => true,
+               'begin_transaction'             => true,
                'change_user'                   => true,
-               'character_set_name'            => true,
-               'close'                         => true,
-               'commit'        => true,
-               'connect'                       => true,
+               'character_set_name'    => true,
+               'close'                                 => true,
+               'commit'                                => true,
+               'connect'                               => true,
                'dump_debug_info'               => true,
                'escape_string'                 => true,
                'get_charset'                   => true,
                'get_client_info'               => true,
                'get_server_info'               => true,
                'get_warnings'                  => true,
-               'init'                          => true,
-               'kill'                          => true,
+               'init'                                  => true,
+               'kill'                                  => true,
                'more_results'                  => true,
                'multi_query'                   => true,
-               'mysqli'                        => true,
+               'mysqli'                                => true,
                'next_result'                   => true,
-               'options'                       => true,
-               'ping'                          => true,
-               'prepare'                       => true,
-               'query'                         => true,
+               'options'                               => true,
+               'ping'                                  => true,
+               'prepare'                               => true,
+               'query'                                 => true,
                'real_connect'                  => true,
-               'real_escape_string'            => true,
+               'real_escape_string'    => true,
                'real_query'                    => true,
-               'refresh'                       => true,
-               'rollback'                      => true,
-               'select_db'                     => true,
+               'refresh'                               => true,
+               'rollback'                              => true,
+               'select_db'                             => true,
                'set_charset'                   => true,
-               'set_opt'                       => true,
-               'ssl_set'                       => true,
-               'stat'                          => true,
-               'stmt_init'                     => true,
+               'set_opt'                               => true,
+               'ssl_set'                               => true,
+               'stat'                                  => true,
+               'stmt_init'                             => true,
                'store_result'                  => true,
                'thread_safe'                   => true,
                'use_result'                    => true,
index 5fd4b6f45cd06124a9799e47b6a558c37eb3fea0..c62cb52fc79509f642e21727dd26904d7f2b7511 100644 (file)
@@ -6,8 +6,6 @@ require_once('skipif.inc');
 require_once('skipifemb.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.
 Most of the things which we test are covered by mysqli_class_*_interface.phpt.
@@ -120,6 +118,36 @@ isPassedByReference: no
 isOptional: 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'
 isFinal: no
 isAbstract: no
@@ -202,9 +230,23 @@ isInternal: yes
 isUserDefined: no
 returnsReference: no
 Modifiers: 256
-Number of Parameters: 0
+Number of Parameters: 2
 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'
 isFinal: no
 isAbstract: no
@@ -863,9 +905,23 @@ isInternal: yes
 isUserDefined: no
 returnsReference: no
 Modifiers: 256
-Number of Parameters: 0
+Number of Parameters: 2
 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'
 isFinal: no
 isAbstract: no
index 34ec4bfcdca6e4f2e974ef25fdb14b9bbbffda2e..e19f698e8193d402b2ba3e6a6b50c06e9427888f 100644 (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",
                        $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()))
-               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)))
                printf("[003] Cannot turn off autocommit, expecting true, got %s/%s\n", gettype($tmp), $tmp);