diff options
Diffstat (limited to 'ext/mysqli/mysqli_api.c')
-rw-r--r-- | ext/mysqli/mysqli_api.c | 253 |
1 files changed, 175 insertions, 78 deletions
diff --git a/ext/mysqli/mysqli_api.c b/ext/mysqli/mysqli_api.c index 0b28a43ba7..e3042b18f8 100644 --- a/ext/mysqli/mysqli_api.c +++ b/ext/mysqli/mysqli_api.c @@ -30,9 +30,115 @@ #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" + +#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); +} +/* }}} */ + + +/* {{{ mysqlnd_escape_string_for_tx_name_in_comment */ +char * +mysqli_escape_string_for_tx_name_in_comment(const char * const name TSRMLS_DC) +{ + char * ret = NULL; + if (name) { + zend_bool warned = FALSE; + const char * p_orig = name; + char * p_copy; + p_copy = ret = emalloc(strlen(name) + 1 + 2 + 2 + 1); /* space, open, close, NullS */ + *p_copy++ = ' '; + *p_copy++ = '/'; + *p_copy++ = '*'; + while (1) { + register char v = *p_orig; + if (v == 0) { + break; + } + if ((v >= '0' && v <= '9') || + (v >= 'a' && v <= 'z') || + (v >= 'A' && v <= 'Z') || + v == '-' || + v == '_' || + v == ' ' || + v == '=') + { + *p_copy++ = v; + } else if (warned == FALSE) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Transaction name truncated. Must be only [0-9A-Za-z\\-_=]+"); + warned = TRUE; + } + ++p_orig; + } + *p_copy++ = '*'; + *p_copy++ = '/'; + *p_copy++ = 0; + } + return ret; +} +/* }}} */ + + +/* {{{ 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 TSRMLS_DC) +{ + 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 * query; + char * name_esc = mysqli_escape_string_for_tx_name_in_comment(name TSRMLS_CC); + size_t query_len; + + query_len = spprintf(&query, 0, (commit? "COMMIT%s %s":"ROLLBACK%s %s"), + name_esc? name_esc:"", tmp_str.c? tmp_str.c:""); + smart_str_free(&tmp_str); + if (name_esc) { + efree(name_esc); + name_esc = NULL; + } + + ret = mysql_real_query(conn, query, query_len); + efree(query); + } + return ret; +} +/* }}} */ +#endif + + /* {{{ proto mixed mysqli_affected_rows(object link) Get number of affected rows in previous MySQL operation */ PHP_FUNCTION(mysqli_affected_rows) @@ -566,14 +672,17 @@ PHP_FUNCTION(mysqli_character_set_name) { MY_MYSQL *mysql; zval *mysql_link; + const char *cs_name; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) { return; } MYSQLI_FETCH_RESOURCE_CONN(mysql, &mysql_link, MYSQLI_STATUS_VALID); - - RETURN_STRING((char *)mysql_character_set_name(mysql->mysql), 1); + cs_name = mysql_character_set_name(mysql->mysql); + if (cs_name) { + RETURN_STRING(cs_name, 1); + } } /* }}} */ @@ -632,18 +741,29 @@ PHP_FUNCTION(mysqli_close) } /* }}} */ -/* {{{ proto bool mysqli_commit(object link) + + + +/* {{{ proto bool mysqli_commit(object link[, int flags [, string name ]]) 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 TSRMLS_CC)) { +#else + if (FAIL == mysqlnd_commit(mysql->mysql, flags, name)) { +#endif RETURN_FALSE; } RETURN_TRUE; @@ -732,12 +852,16 @@ PHP_FUNCTION(mysqli_error) { MY_MYSQL *mysql; zval *mysql_link; + const char *err; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) { return; } MYSQLI_FETCH_RESOURCE_CONN(mysql, &mysql_link, MYSQLI_STATUS_VALID); - RETURN_STRING((char *)mysql_error(mysql->mysql),1); + err = mysql_error(mysql->mysql); + if (err) { + RETURN_STRING(err, 1); + } } /* }}} */ @@ -1268,7 +1392,10 @@ PHP_FUNCTION(mysqli_free_result) Get MySQL client info */ PHP_FUNCTION(mysqli_get_client_info) { - RETURN_STRING((char *)mysql_get_client_info(), 1); + const char * info = mysql_get_client_info(); + if (info) { + RETURN_STRING(info, 1); + } } /* }}} */ @@ -1320,15 +1447,18 @@ PHP_FUNCTION(mysqli_get_server_info) { MY_MYSQL *mysql; zval *mysql_link = NULL; + const char *info; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) { return; } MYSQLI_FETCH_RESOURCE_CONN(mysql, &mysql_link, MYSQLI_STATUS_VALID); - RETURN_STRING((char *)mysql_get_server_info(mysql->mysql), 1); + info = mysql_get_server_info(mysql->mysql); + if (info) { + RETURN_STRING(info, 1); + } } - /* }}} */ /* {{{ proto int mysqli_get_server_version(object link) @@ -1361,7 +1491,9 @@ PHP_FUNCTION(mysqli_info) MYSQLI_FETCH_RESOURCE_CONN(mysql, &mysql_link, MYSQLI_STATUS_VALID); info = mysql_info(mysql->mysql); - RETURN_STRING((info) ? (char *)info : "", 1); + if (info) { + RETURN_STRING(info, 1); + } } /* }}} */ @@ -1456,64 +1588,6 @@ PHP_FUNCTION(mysqli_kill) } /* }}} */ -/* {{{ proto void mysqli_set_local_infile_default(object link) - unsets user defined handler for load local infile command */ -#if !defined(MYSQLI_USE_MYSQLND) -PHP_FUNCTION(mysqli_set_local_infile_default) -{ - MY_MYSQL *mysql; - zval *mysql_link; - - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) { - return; - } - - MYSQLI_FETCH_RESOURCE_CONN(mysql, &mysql_link, MYSQLI_STATUS_VALID); - - if (mysql->li_read) { - zval_ptr_dtor(&(mysql->li_read)); - mysql->li_read = NULL; - } -} -/* }}} */ - -/* {{{ proto bool mysqli_set_local_infile_handler(object link, callback read_func) - Set callback functions for LOAD DATA LOCAL INFILE */ -PHP_FUNCTION(mysqli_set_local_infile_handler) -{ - MY_MYSQL *mysql; - zval *mysql_link; - char *callback_name; - zval *callback_func; - - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oz", &mysql_link, mysqli_link_class_entry, - &callback_func) == FAILURE) { - return; - } - - MYSQLI_FETCH_RESOURCE_CONN(mysql, &mysql_link, MYSQLI_STATUS_VALID); - - /* check callback function */ - if (!zend_is_callable(callback_func, 0, &callback_name TSRMLS_CC)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not a valid callback function %s", callback_name); - efree(callback_name); - RETURN_FALSE; - } - efree(callback_name); - - /* save callback function */ - if (!mysql->li_read) { - MAKE_STD_ZVAL(mysql->li_read); - } else { - zval_dtor(mysql->li_read); - } - ZVAL_ZVAL(mysql->li_read, callback_func, 1, 0); - - RETURN_TRUE; -} -#endif -/* }}} */ - /* {{{ proto bool mysqli_more_results(object link) check if there any more query results from a multi query */ PHP_FUNCTION(mysqli_more_results) @@ -1645,10 +1719,10 @@ static int mysqli_options_get_option_zval_type(int option) #endif /* MYSQLI_USE_MYSQLND */ case MYSQL_OPT_CONNECT_TIMEOUT: #ifdef MYSQL_REPORT_DATA_TRUNCATION - case MYSQL_REPORT_DATA_TRUNCATION: + case MYSQL_REPORT_DATA_TRUNCATION: #endif - case MYSQL_OPT_LOCAL_INFILE: - case MYSQL_OPT_NAMED_PIPE: + case MYSQL_OPT_LOCAL_INFILE: + case MYSQL_OPT_NAMED_PIPE: #ifdef MYSQL_OPT_PROTOCOL case MYSQL_OPT_PROTOCOL: #endif /* MySQL 4.1.0 */ @@ -1664,7 +1738,7 @@ static int mysqli_options_get_option_zval_type(int option) case MYSQL_OPT_RECONNECT: #endif /* MySQL 5.0.13 */ #ifdef MYSQL_OPT_SSL_VERIFY_SERVER_CERT - case MYSQL_OPT_SSL_VERIFY_SERVER_CERT: + case MYSQL_OPT_SSL_VERIFY_SERVER_CERT: #endif /* MySQL 5.0.23 */ #ifdef MYSQL_OPT_COMPRESS case MYSQL_OPT_COMPRESS: @@ -1672,7 +1746,7 @@ static int mysqli_options_get_option_zval_type(int option) #ifdef MYSQL_OPT_SSL_VERIFY_SERVER_CERT REGISTER_LONG_CONSTANT("MYSQLI_OPT_SSL_VERIFY_SERVER_CERT", MYSQL_OPT_SSL_VERIFY_SERVER_CERT, CONST_CS | CONST_PERSISTENT); #endif /* MySQL 5.1.1., mysqlnd @ PHP 5.3.3 */ -#if MYSQL_VERSION_ID >= 50611 || defined(MYSQLI_USE_MYSQLND) +#if (MYSQL_VERSION_ID >= 50611 && defined(CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS)) || defined(MYSQLI_USE_MYSQLND) case MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS: #endif return IS_LONG; @@ -1688,6 +1762,9 @@ static int mysqli_options_get_option_zval_type(int option) case MYSQL_INIT_COMMAND: case MYSQL_SET_CHARSET_NAME: case MYSQL_SET_CHARSET_DIR: +#if MYSQL_VERSION_ID > 50605 || defined(MYSQLI_USE_MYSQLND) + case MYSQL_SERVER_PUBLIC_KEY: +#endif return IS_STRING; default: @@ -1916,19 +1993,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 TSRMLS_CC)) { +#else + if (FAIL == mysqlnd_rollback(mysql->mysql, flags, name)) { +#endif RETURN_FALSE; } RETURN_TRUE; @@ -2158,12 +2243,16 @@ PHP_FUNCTION(mysqli_sqlstate) { MY_MYSQL *mysql; zval *mysql_link; + const char *state; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) { return; } MYSQLI_FETCH_RESOURCE_CONN(mysql, &mysql_link, MYSQLI_STATUS_VALID); - RETURN_STRING((char *)mysql_sqlstate(mysql->mysql),1); + state = mysql_sqlstate(mysql->mysql); + if (state) { + RETURN_STRING(state, 1); + } } /* }}} */ @@ -2341,13 +2430,17 @@ PHP_FUNCTION(mysqli_stmt_error) { MY_STMT *stmt; zval *mysql_stmt; + const char * err; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) { return; } MYSQLI_FETCH_RESOURCE_STMT(stmt, &mysql_stmt, MYSQLI_STATUS_INITIALIZED); - RETURN_STRING((char *)mysql_stmt_error(stmt->stmt),1); + err = mysql_stmt_error(stmt->stmt); + if (err) { + RETURN_STRING(err, 1); + } } /* }}} */ @@ -2490,13 +2583,17 @@ PHP_FUNCTION(mysqli_stmt_sqlstate) { MY_STMT *stmt; zval *mysql_stmt; + const char * state; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) { return; } MYSQLI_FETCH_RESOURCE_STMT(stmt, &mysql_stmt, MYSQLI_STATUS_VALID); - RETURN_STRING((char *)mysql_stmt_sqlstate(stmt->stmt),1); + state = mysql_stmt_sqlstate(stmt->stmt); + if (state) { + RETURN_STRING(state, 1); + } } /* }}} */ |