From 9fb0dba4be197b677b6ff7df23a110698d12530b Mon Sep 17 00:00:00 2001 From: Andrey Hristov Date: Thu, 7 Feb 2013 16:05:27 +0100 Subject: [PATCH] Add support for commit and rollback options. Add support for explicitly starting a transaction - modes also available. Using the API makes the life of load balancer mysqlnd plugins easier/possible. --- ext/mysqlnd/mysqlnd.c | 129 +++++++++++++++++++++++++++++-- ext/mysqlnd/mysqlnd_enum_n_def.h | 12 +++ ext/mysqlnd/mysqlnd_structs.h | 9 +++ 3 files changed, 142 insertions(+), 8 deletions(-) diff --git a/ext/mysqlnd/mysqlnd.c b/ext/mysqlnd/mysqlnd.c index 1bab6f5b7a..d7ddcb594b 100644 --- a/ext/mysqlnd/mysqlnd.c +++ b/ext/mysqlnd/mysqlnd.c @@ -2617,12 +2617,79 @@ MYSQLND_METHOD(mysqlnd_conn_data, set_autocommit)(MYSQLND_CONN_DATA * conn, unsi static enum_func_status MYSQLND_METHOD(mysqlnd_conn_data, tx_commit)(MYSQLND_CONN_DATA * conn TSRMLS_DC) { - size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, tx_commit); + return conn->m->tx_commit_or_rollback(conn, TRUE, TRANS_COR_NO_OPT, NULL TSRMLS_CC); +} +/* }}} */ + + +/* {{{ mysqlnd_conn_data::tx_rollback */ +static enum_func_status +MYSQLND_METHOD(mysqlnd_conn_data, tx_rollback)(MYSQLND_CONN_DATA * conn TSRMLS_DC) +{ + return conn->m->tx_commit_or_rollback(conn, FALSE, TRANS_COR_NO_OPT, NULL TSRMLS_CC); +} +/* }}} */ + + +/* {{{ mysqlnd_tx_cor_options_to_string */ +static void +MYSQLND_METHOD(mysqlnd_conn_data, tx_cor_options_to_string)(const MYSQLND_CONN_DATA * const conn, smart_str * str, const unsigned int mode TSRMLS_DC) +{ + 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); +} +/* }}} */ + + +/* {{{ mysqlnd_conn_data::tx_commit_ex */ +static enum_func_status +MYSQLND_METHOD(mysqlnd_conn_data, tx_commit_or_rollback)(MYSQLND_CONN_DATA * conn, const zend_bool commit, const unsigned int flags, const char * const name TSRMLS_DC) +{ + size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, tx_commit_or_rollback); enum_func_status ret = FAIL; - DBG_ENTER("mysqlnd_conn_data::tx_commit"); + DBG_ENTER("mysqlnd_conn_data::tx_commit_or_rollback"); if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) { - ret = conn->m->query(conn, "COMMIT", sizeof("COMMIT") - 1 TSRMLS_CC); + do { + smart_str tmp_str = {0, 0, 0}; + conn->m->tx_cor_options_to_string(conn, &tmp_str, flags TSRMLS_CC); + smart_str_0(&tmp_str); + + { + char * query; + unsigned int query_len = mnd_sprintf(&query, 0, (commit? "COMMIT %s":"ROLLBACK %s"), tmp_str.c? tmp_str.c:""); + smart_str_free(&tmp_str); + + if (!query) { + SET_OOM_ERROR(*conn->error_info); + break; + } + ret = conn->m->query(conn, query, query_len TSRMLS_CC); + mnd_sprintf_free(query); + } + } while (0); conn->m->local_tx_end(conn, this_func, ret TSRMLS_CC); } @@ -2631,16 +2698,55 @@ MYSQLND_METHOD(mysqlnd_conn_data, tx_commit)(MYSQLND_CONN_DATA * conn TSRMLS_DC) /* }}} */ -/* {{{ mysqlnd_conn_data::tx_rollback */ +/* {{{ mysqlnd_conn_data::tx_begin */ static enum_func_status -MYSQLND_METHOD(mysqlnd_conn_data, tx_rollback)(MYSQLND_CONN_DATA * conn TSRMLS_DC) +MYSQLND_METHOD(mysqlnd_conn_data, tx_begin)(MYSQLND_CONN_DATA * conn, const unsigned int mode, const char * const name TSRMLS_DC) { - size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, tx_rollback); + size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, tx_begin); enum_func_status ret = FAIL; - DBG_ENTER("mysqlnd_conn_data::tx_rollback"); + DBG_ENTER("mysqlnd_conn_data::tx_begin"); if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) { - ret = conn->m->query(conn, "ROLLBACK", sizeof("ROLLBACK") - 1 TSRMLS_CC); + do { + 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? mnd_sprintf(&commented_name, 0, " /*%s*/", name):0; + char * query; + unsigned int query_len = mnd_sprintf(&query, 0, "START TRANSACTION%s %s", commented_name? commented_name:"", tmp_str.c? tmp_str.c:""); + smart_str_free(&tmp_str); + + if (!query) { + SET_OOM_ERROR(*conn->error_info); + break; + } + ret = conn->m->query(conn, query, query_len TSRMLS_CC); + mnd_sprintf_free(query); + if (commented_name) { + mnd_sprintf_free(commented_name); + } + } + } while (0); conn->m->local_tx_end(conn, this_func, ret TSRMLS_CC); } @@ -2649,6 +2755,9 @@ MYSQLND_METHOD(mysqlnd_conn_data, tx_rollback)(MYSQLND_CONN_DATA * conn TSRMLS_D /* }}} */ +typedef enum_func_status (*func_mysqlnd_conn_data__)(MYSQLND_CONN_DATA * conn, const unsigned int flags, const char * const name TSRMLS_DC); + + /* {{{ mysqlnd_conn_data::local_tx_start */ static enum_func_status MYSQLND_METHOD(mysqlnd_conn_data, local_tx_start)(MYSQLND_CONN_DATA * conn, size_t this_func TSRMLS_DC) @@ -2763,6 +2872,10 @@ MYSQLND_CLASS_METHODS_START(mysqlnd_conn_data) MYSQLND_METHOD(mysqlnd_conn_data, set_autocommit), MYSQLND_METHOD(mysqlnd_conn_data, tx_commit), MYSQLND_METHOD(mysqlnd_conn_data, tx_rollback), + MYSQLND_METHOD(mysqlnd_conn_data, tx_begin), + MYSQLND_METHOD(mysqlnd_conn_data, tx_commit_or_rollback), + MYSQLND_METHOD(mysqlnd_conn_data, tx_cor_options_to_string), + MYSQLND_METHOD(mysqlnd_conn_data, local_tx_start), MYSQLND_METHOD(mysqlnd_conn_data, local_tx_end), MYSQLND_METHOD(mysqlnd_conn_data, execute_init_commands), diff --git a/ext/mysqlnd/mysqlnd_enum_n_def.h b/ext/mysqlnd/mysqlnd_enum_n_def.h index cf5b02728b..1d645a8d75 100644 --- a/ext/mysqlnd/mysqlnd_enum_n_def.h +++ b/ext/mysqlnd/mysqlnd_enum_n_def.h @@ -108,6 +108,18 @@ #define MYSQLND_NET_FLAG_USE_COMPRESSION 1 + +#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 + typedef enum mysqlnd_extension { MYSQLND_MYSQL = 0, diff --git a/ext/mysqlnd/mysqlnd_structs.h b/ext/mysqlnd/mysqlnd_structs.h index b88004a9f1..7d22dafb8f 100644 --- a/ext/mysqlnd/mysqlnd_structs.h +++ b/ext/mysqlnd/mysqlnd_structs.h @@ -23,6 +23,8 @@ #ifndef MYSQLND_STRUCTS_H #define MYSQLND_STRUCTS_H +#include "ext/standard/php_smart_str.h" + #define MYSQLND_TYPEDEFED_METHODS #define MYSQLND_CLASS_METHOD_TABLE_NAME(class) mysqlnd_##class##_methods @@ -31,6 +33,7 @@ #define MYSQLND_CLASS_METHODS_START(class) MYSQLND_CLASS_METHOD_TABLE_NAME_FORWARD(class) = { #define MYSQLND_CLASS_METHODS_END } + typedef struct st_mysqlnd_memory_pool MYSQLND_MEMORY_POOL; typedef struct st_mysqlnd_memory_pool_chunk MYSQLND_MEMORY_POOL_CHUNK; typedef struct st_mysqlnd_memory_pool_chunk_llist MYSQLND_MEMORY_POOL_CHUNK_LLIST; @@ -480,6 +483,9 @@ typedef MYSQLND_RES * (*func_mysqlnd_conn_data__result_init)(unsigned int fiel typedef enum_func_status (*func_mysqlnd_conn_data__set_autocommit)(MYSQLND_CONN_DATA * conn, unsigned int mode TSRMLS_DC); typedef enum_func_status (*func_mysqlnd_conn_data__tx_commit)(MYSQLND_CONN_DATA * conn TSRMLS_DC); typedef enum_func_status (*func_mysqlnd_conn_data__tx_rollback)(MYSQLND_CONN_DATA * conn TSRMLS_DC); +typedef enum_func_status (*func_mysqlnd_conn_data__tx_begin)(MYSQLND_CONN_DATA * conn, const unsigned int mode, const char * const name TSRMLS_DC); +typedef enum_func_status (*func_mysqlnd_conn_data__tx_commit_or_rollback)(MYSQLND_CONN_DATA * conn, const zend_bool commit, const unsigned int flags, const char * const name TSRMLS_DC); +typedef void (*func_mysqlnd_conn_data__tx_cor_options_to_string)(const MYSQLND_CONN_DATA * const conn, smart_str * tmp_str, const unsigned int mode TSRMLS_DC); typedef enum_func_status (*func_mysqlnd_conn_data__local_tx_start)(MYSQLND_CONN_DATA * conn, size_t this_func TSRMLS_DC); typedef enum_func_status (*func_mysqlnd_conn_data__local_tx_end)(MYSQLND_CONN_DATA * conn, size_t this_func, enum_func_status status TSRMLS_DC); @@ -566,6 +572,9 @@ struct st_mysqlnd_conn_data_methods func_mysqlnd_conn_data__set_autocommit set_autocommit; func_mysqlnd_conn_data__tx_commit tx_commit; func_mysqlnd_conn_data__tx_rollback tx_rollback; + func_mysqlnd_conn_data__tx_begin tx_begin; + func_mysqlnd_conn_data__tx_commit_or_rollback tx_commit_or_rollback; + func_mysqlnd_conn_data__tx_cor_options_to_string tx_cor_options_to_string; func_mysqlnd_conn_data__local_tx_start local_tx_start; func_mysqlnd_conn_data__local_tx_end local_tx_end; -- 2.40.0