diff options
| author | Andrey Hristov <andrey@php.net> | 2007-10-02 10:45:27 +0000 |
|---|---|---|
| committer | Andrey Hristov <andrey@php.net> | 2007-10-02 10:45:27 +0000 |
| commit | 9ac92cfecb9522d4679d7e3dc2e38be1b11a6467 (patch) | |
| tree | e7e5931f5d0359b749c0a4668658bd2b2efe2cea /ext/mysqli | |
| parent | f0e5df4544d0aa7378bc620577ba1e814a1a0aea (diff) | |
| download | php-git-9ac92cfecb9522d4679d7e3dc2e38be1b11a6467.tar.gz | |
Update mysqlnd in HEAD
Updated ext/mysql and ext/mysqli in HEAD
Diffstat (limited to 'ext/mysqli')
| -rw-r--r-- | ext/mysqli/mysqli.c | 118 | ||||
| -rw-r--r-- | ext/mysqli/mysqli_api.c | 45 | ||||
| -rw-r--r-- | ext/mysqli/mysqli_driver.c | 2 | ||||
| -rw-r--r-- | ext/mysqli/mysqli_fe.c | 4 | ||||
| -rw-r--r-- | ext/mysqli/mysqli_mysqlnd.h | 4 | ||||
| -rw-r--r-- | ext/mysqli/mysqli_nonapi.c | 195 | ||||
| -rw-r--r-- | ext/mysqli/mysqli_prop.c | 6 | ||||
| -rw-r--r-- | ext/mysqli/mysqli_warning.c | 2 | ||||
| -rw-r--r-- | ext/mysqli/php_mysqli_structs.h | 27 |
9 files changed, 295 insertions, 108 deletions
diff --git a/ext/mysqli/mysqli.c b/ext/mysqli/mysqli.c index c68ded2d7c..5a0b3ec427 100644 --- a/ext/mysqli/mysqli.c +++ b/ext/mysqli/mysqli.c @@ -72,15 +72,53 @@ typedef struct _mysqli_prop_handler { static int le_pmysqli; -/* Destructor for Persistent Connections */ -ZEND_RSRC_DTOR_FUNC(php_mysqli_dtor) + +static int php_mysqli_persistent_on_rshut(zend_rsrc_list_entry *le TSRMLS_DC) { - if (rsrc->ptr) { - MYSQL *mysql = (MYSQL *)rsrc->ptr; + if (le->type == le_pmysqli) { + mysqli_plist_entry *plist = (mysqli_plist_entry *) le->ptr; + HashPosition pos; + MYSQL **mysql; + ulong idx; + dtor_func_t pDestructor = plist->used_links.pDestructor; + plist->used_links.pDestructor = NULL; /* Don't call pDestructor now */ + + zend_hash_internal_pointer_reset_ex(&plist->used_links, &pos); + while (SUCCESS == zend_hash_get_current_data_ex(&plist->used_links, (void **)&mysql, &pos)) { + zend_hash_get_current_key_ex(&plist->used_links, NULL, NULL, &idx, FALSE, &pos); + /* Make it free */ + zend_hash_next_index_insert(&plist->free_links, mysql, sizeof(MYSQL *), NULL); + /* First move forward */ + zend_hash_move_forward_ex(&plist->used_links, &pos); + /* The delete, because del will free memory, but we need it's ->nextItem */ + zend_hash_index_del(&plist->used_links, idx); + } + + /* restore pDestructor, which should be php_mysqli_dtor_p_elements() */ + plist->used_links.pDestructor = pDestructor; + } + return ZEND_HASH_APPLY_KEEP; +} + +/* Destructor for mysqli entries in free_links/used_links */ +void php_mysqli_dtor_p_elements(void *data) +{ + MYSQL **mysql = (MYSQL **) data; + TSRMLS_FETCH(); #if defined(HAVE_MYSQLND) - mysqlnd_end_psession(mysql); + mysqlnd_end_psession(*mysql); #endif - mysqli_close(mysql, MYSQLI_CLOSE_IMPLICIT); + mysqli_close(*mysql, MYSQLI_CLOSE_IMPLICIT); +} + + +ZEND_RSRC_DTOR_FUNC(php_mysqli_dtor) +{ + if (rsrc->ptr) { + mysqli_plist_entry *plist = (mysqli_plist_entry *) rsrc->ptr; + zend_hash_destroy(&plist->free_links); + zend_hash_destroy(&plist->used_links); + free(plist); } } @@ -162,6 +200,10 @@ void php_clear_stmt_bind(MY_STMT *stmt TSRMLS_DC) /* {{{ php_clear_mysql */ void php_clear_mysql(MY_MYSQL *mysql) { + if (mysql->hash_key) { + efree(mysql->hash_key); + mysql->hash_key = NULL; + } if (mysql->li_read) { efree(Z_STRVAL_P(mysql->li_read)); FREE_ZVAL(mysql->li_read); @@ -508,6 +550,8 @@ ZEND_GET_MODULE(mysqli) */ PHP_INI_BEGIN() STD_PHP_INI_ENTRY_EX("mysqli.max_links", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_links, zend_mysqli_globals, mysqli_globals, display_link_numbers) + STD_PHP_INI_ENTRY_EX("mysqli.max_persistent", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_persistent, zend_mysqli_globals, mysqli_globals, display_link_numbers) + STD_PHP_INI_BOOLEAN("mysqli.allow_persistent", "1", PHP_INI_SYSTEM, OnUpdateLong, allow_persistent, zend_mysqli_globals, mysqli_globals) STD_PHP_INI_ENTRY("mysqli.default_host", NULL, PHP_INI_ALL, OnUpdateString, default_host, zend_mysqli_globals, mysqli_globals) STD_PHP_INI_ENTRY("mysqli.default_user", NULL, PHP_INI_ALL, OnUpdateString, default_user, zend_mysqli_globals, mysqli_globals) STD_PHP_INI_ENTRY("mysqli.default_pw", NULL, PHP_INI_ALL, OnUpdateString, default_pw, zend_mysqli_globals, mysqli_globals) @@ -527,7 +571,11 @@ PHP_INI_END() static PHP_GINIT_FUNCTION(mysqli) { mysqli_globals->num_links = 0; + mysqli_globals->num_active_persistent = 0; + mysqli_globals->num_inactive_persistent = 0; mysqli_globals->max_links = -1; + mysqli_globals->max_persistent = -1; + mysqli_globals->allow_persistent = 1; mysqli_globals->default_port = 0; mysqli_globals->default_host = NULL; mysqli_globals->default_user = NULL; @@ -559,9 +607,11 @@ PHP_MINIT_FUNCTION(mysqli) REGISTER_INI_ENTRIES(); #ifndef HAVE_MYSQLND +#if MYSQL_VERSION_ID >= 40000 if (mysql_server_init(0, NULL, NULL)) { return FAILURE; } +#endif #else mysqli_mysqlnd_zval_cache = mysqlnd_palloc_init_cache(MyG(cache_size)); mysqli_mysqlnd_qcache = mysqlnd_qcache_init_cache(); @@ -631,6 +681,8 @@ PHP_MINIT_FUNCTION(mysqli) REGISTER_LONG_CONSTANT("MYSQLI_INIT_COMMAND", MYSQL_INIT_COMMAND, CONST_CS | CONST_PERSISTENT); #if defined(HAVE_MYSQLND) REGISTER_LONG_CONSTANT("MYSQLI_OPT_NUMERIC_AND_DATETIME_AS_UNICODE", MYSQLND_OPT_NUMERIC_AND_DATETIME_AS_UNICODE, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("MYSQLI_OPT_NET_CMD_BUFFER_SIZE", MYSQLND_OPT_NET_CMD_BUFFER_SIZE, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("MYSQLI_OPT_NET_READ_BUFFER_SIZE", MYSQLND_OPT_NET_READ_BUFFER_SIZE, CONST_CS | CONST_PERSISTENT); #endif #ifdef MYSQLND_STRING_TO_INT_CONVERSION REGISTER_LONG_CONSTANT("MYSQLI_OPT_INT_AND_YEAR_AS_INT", MYSQLND_OPT_INT_AND_YEAR_AS_INT, CONST_CS | CONST_PERSISTENT); @@ -746,15 +798,20 @@ PHP_MINIT_FUNCTION(mysqli) PHP_MSHUTDOWN_FUNCTION(mysqli) { #ifndef HAVE_MYSQLND +#if MYSQL_VERSION_ID >= 40000 #ifdef PHP_WIN32 - unsigned long client_ver = mysql_get_client_version; - /* Can't call mysql_server_end() multiple times prior to 5.0.42 on Windows */ - if ((client_ver > 50042 && client_ver < 50100) || client_ver > 50122) { + unsigned long client_ver = mysql_get_client_version(); + /* + Can't call mysql_server_end() multiple times prior to 5.0.42 on Windows. + PHP bug#41350 MySQL bug#25621 + */ + if ((client_ver >= 50042 && client_ver < 50100) || client_ver > 50122) { mysql_server_end(); } #else mysql_server_end(); #endif +#endif #else mysqlnd_palloc_free_cache(mysqli_mysqlnd_zval_cache); mysqlnd_qcache_free_cache_reference(&mysqli_mysqlnd_qcache); @@ -776,7 +833,7 @@ PHP_MSHUTDOWN_FUNCTION(mysqli) */ PHP_RINIT_FUNCTION(mysqli) { -#if !defined(HAVE_MYSQLND) && defined(ZTS) +#if !defined(HAVE_MYSQLND) && defined(ZTS) && MYSQL_VERSION_ID >= 40000 if (mysql_thread_init()) { return FAILURE; } @@ -795,7 +852,10 @@ PHP_RINIT_FUNCTION(mysqli) */ PHP_RSHUTDOWN_FUNCTION(mysqli) { -#if !defined(HAVE_MYSQLND) && defined(ZTS) + /* check persistent connections, move used to free */ + zend_hash_apply(&EG(persistent_list), (apply_func_t) php_mysqli_persistent_on_rshut TSRMLS_CC); + +#if !defined(HAVE_MYSQLND) && defined(ZTS) && MYSQL_VERSION_ID >= 40000 mysql_thread_end(); #endif if (MyG(error_msg)) { @@ -813,6 +873,10 @@ PHP_RSHUTDOWN_FUNCTION(mysqli) */ PHP_MINFO_FUNCTION(mysqli) { +#if defined(HAVE_MYSQLND) + char buf[32]; +#endif + php_info_print_table_start(); php_info_print_table_header(2, "MysqlI Support", "enabled"); php_info_print_table_row(2, "Client API library version", mysql_get_client_info()); @@ -820,6 +884,12 @@ PHP_MINFO_FUNCTION(mysqli) php_info_print_table_row(2, "Client API header version", MYSQL_SERVER_VERSION); php_info_print_table_row(2, "MYSQLI_SOCKET", MYSQL_UNIX_ADDR); #else + snprintf(buf, sizeof(buf), "%ld", MyG(num_active_persistent)); + php_info_print_table_row(2, "Active Persistent Links", buf); + snprintf(buf, sizeof(buf), "%ld", MyG(num_inactive_persistent)); + php_info_print_table_row(2, "Inactive Persistent Links", buf); + snprintf(buf, sizeof(buf), "%ld", MyG(num_links)); + php_info_print_table_row(2, "Active Links", buf); { zval values; @@ -1151,6 +1221,9 @@ PHP_MYSQLI_API void php_mysqli_set_error(long mysql_errno, char *mysql_err TSRML } /* }}} */ +#if !defined(HAVE_MYSQLND) + + #define ALLOC_CALLBACK_ARGS(a, b, c)\ if (c) {\ a = (zval ***)safe_emalloc(c, sizeof(zval **), 0);\ @@ -1171,27 +1244,23 @@ if (a) {\ #define LOCAL_INFILE_ERROR_MSG(source,dest)\ memset(source, 0, LOCAL_INFILE_ERROR_LEN);\ -memcpy(source, dest, LOCAL_INFILE_ERROR_LEN-1);\ +memcpy(source, dest, MIN(strlen(dest), LOCAL_INFILE_ERROR_LEN-1));\ php_error_docref(NULL TSRMLS_CC, E_WARNING, dest); + /* {{{ void php_set_local_infile_handler_default */ void php_set_local_infile_handler_default(MY_MYSQL *mysql) { /* register internal callback functions */ -#if !defined(HAVE_MYSQLND) mysql_set_local_infile_handler(mysql->mysql, &php_local_infile_init, &php_local_infile_read, &php_local_infile_end, &php_local_infile_error, (void *)mysql); if (mysql->li_read) { zval_ptr_dtor(&mysql->li_read); mysql->li_read = NULL; } -#else - mysqlnd_local_infile_default(mysql->mysql, TRUE); -#endif } /* }}} */ -#if !defined(HAVE_MYSQLND) /* {{{ php_local_infile_init */ int php_local_infile_init(void **ptr, const char *filename, void *userdata) @@ -1304,6 +1373,16 @@ int php_local_infile_read(void *ptr, char *buf, uint buf_len) LOCAL_INFILE_ERROR_MSG(data->error_msg, "Can't execute load data local init callback function"); rc = -1; } + /* + If the (ab)user has closed the file handle we should + not try to use it anymore or even close it + */ + if (!zend_rsrc_list_get_rsrc_type(Z_LVAL_P(fp) TSRMLS_CC)) { + LOCAL_INFILE_ERROR_MSG(data->error_msg, "File handle closed"); + rc = -1; + /* Thus the end handler won't try to free already freed memory */ + mysql->li_stream = NULL; + } FREE_CALLBACK_ARGS(callback_args, 1, argc); efree(fp); @@ -1343,8 +1422,9 @@ void php_local_infile_end(void *ptr) } return; } - - php_stream_close(mysql->li_stream); + if (mysql->li_stream) { + php_stream_close(mysql->li_stream); + } free(data); return; } diff --git a/ext/mysqli/mysqli_api.c b/ext/mysqli/mysqli_api.c index 4d806018e6..19195d2719 100644 --- a/ext/mysqli/mysqli_api.c +++ b/ext/mysqli/mysqli_api.c @@ -28,6 +28,7 @@ #include "php.h" #include "php_ini.h" +#include "php_globals.h" #include "ext/standard/info.h" #include "php_mysqli_structs.h" @@ -518,6 +519,11 @@ PHP_FUNCTION(mysqli_change_user) RETURN_FALSE; } + /* Change user resets the charset in the server, change it back */ + if (UG(unicode)) { + mysql_set_character_set(mysql->mysql, "utf8"); + } + RETURN_TRUE; } /* }}} */ @@ -552,12 +558,31 @@ PHP_FUNCTION(mysqli_close) MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL *, &mysql_link, "mysqli_link", MYSQLI_STATUS_INITIALIZED); - php_clear_mysql(mysql); if (!mysql->persistent) { mysqli_close(mysql->mysql, MYSQLI_CLOSE_EXPLICIT); + mysql->mysql = NULL; + } else { + zend_rsrc_list_entry *le; + if (zend_hash_find(&EG(persistent_list), mysql->hash_key, strlen(mysql->hash_key) + 1, (void **)&le) == SUCCESS) { + if (Z_TYPE_P(le) == php_le_pmysqli()) { + mysqli_plist_entry *plist = (mysqli_plist_entry *) le->ptr; + dtor_func_t pDestructor = plist->used_links.pDestructor; + + plist->used_links.pDestructor = NULL; /* Don't call pDestructor now */ + zend_hash_index_del(&plist->used_links, mysql->hash_index); + plist->used_links.pDestructor = pDestructor; /* Restore the destructor */ + + zend_hash_next_index_insert(&plist->free_links, &mysql->mysql, sizeof(MYSQL *), NULL); + MyG(num_links)--; + MyG(num_active_persistent)--; + MyG(num_inactive_persistent)++; + } + } } + php_clear_mysql(mysql); + MYSQLI_CLEAR_RESOURCE(&mysql_link); efree(mysql); RETURN_TRUE; @@ -1365,6 +1390,7 @@ PHP_FUNCTION(mysqli_kill) /* {{{ proto void mysqli_set_local_infile_default(object link) U unsets user defined handler for load local infile command */ +#if !defined(HAVE_MYSQLND) PHP_FUNCTION(mysqli_set_local_infile_default) { MY_MYSQL *mysql; @@ -1376,15 +1402,10 @@ PHP_FUNCTION(mysqli_set_local_infile_default) MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL *, &mysql_link, "mysqli_link", MYSQLI_STATUS_VALID); -#if !defined(HAVE_MYSQLND) if (mysql->li_read) { - efree(Z_STRVAL_P(mysql->li_read)); zval_dtor(mysql->li_read); mysql->li_read = NULL; } -#else - mysqlnd_local_infile_default(mysql->mysql, TRUE); -#endif } /* }}} */ @@ -1417,19 +1438,16 @@ PHP_FUNCTION(mysqli_set_local_infile_handler) zval_dtor(&callback_name); /* save callback function */ -#if !defined(HAVE_MYSQLND) if (!mysql->li_read) { MAKE_STD_ZVAL(mysql->li_read); } else { zval_dtor(mysql->li_read); } ZVAL_STRINGL(mysql->li_read, Z_STRVAL_P(callback_func), Z_STRLEN_P(callback_func), 1); -#else - mysqlnd_set_local_infile_handler(mysql->mysql, callback_func->value.str.val); -#endif RETURN_TRUE; } +#endif /* }}} */ /* {{{ proto bool mysqli_more_results(object link) U @@ -1778,7 +1796,7 @@ PHP_FUNCTION(mysqli_real_escape_string) { newstr_len = mysql_real_escape_string(mysql->mysql, newstr, escapestr, escapestr_len); newstr = erealloc(newstr, newstr_len + 1); - RETURN_UTF8_STRING(newstr, ZSTR_AUTOFREE); + RETURN_UTF8_STRINGL(newstr, newstr_len, ZSTR_AUTOFREE); } /* }}} */ @@ -2290,7 +2308,10 @@ PHP_FUNCTION(mysqli_stmt_store_result) int i = 0; for (i = mysql_stmt_field_count(stmt->stmt) - 1; i >=0; --i) { - if (stmt->stmt->fields && stmt->stmt->fields[i].type == MYSQL_TYPE_BLOB) { + if (stmt->stmt->fields && (stmt->stmt->fields[i].type == MYSQL_TYPE_BLOB || + stmt->stmt->fields[i].type == MYSQL_TYPE_MEDIUM_BLOB || + stmt->stmt->fields[i].type == MYSQL_TYPE_LONG_BLOB)) + { my_bool tmp=1; mysql_stmt_attr_set(stmt->stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &tmp); break; diff --git a/ext/mysqli/mysqli_driver.c b/ext/mysqli/mysqli_driver.c index 2418bbc0b4..e1d3880a89 100644 --- a/ext/mysqli/mysqli_driver.c +++ b/ext/mysqli/mysqli_driver.c @@ -142,7 +142,7 @@ ZEND_FUNCTION(mysqli_driver_construct) ((mysqli_object *) zend_object_store_get_object(getThis() TSRMLS_CC))->ptr = mysqli_resource; } -mysqli_property_entry mysqli_driver_property_entries[] = { +const mysqli_property_entry mysqli_driver_property_entries[] = { {"client_info", driver_client_info_read, NULL}, {"client_version", driver_client_version_read, NULL}, {"driver_version", driver_driver_version_read, NULL}, diff --git a/ext/mysqli/mysqli_fe.c b/ext/mysqli/mysqli_fe.c index cae2188a0a..19a0412505 100644 --- a/ext/mysqli/mysqli_fe.c +++ b/ext/mysqli/mysqli_fe.c @@ -119,8 +119,10 @@ const zend_function_entry mysqli_functions[] = { PHP_FE(mysqli_info, NULL) PHP_FE(mysqli_insert_id, NULL) PHP_FE(mysqli_kill, NULL) +#if !defined(HAVE_MYSQLND) PHP_FE(mysqli_set_local_infile_default, NULL) PHP_FE(mysqli_set_local_infile_handler, NULL) +#endif PHP_FE(mysqli_more_results, NULL) PHP_FE(mysqli_multi_query, NULL) PHP_FE(mysqli_next_result, NULL) @@ -227,8 +229,10 @@ const zend_function_entry mysqli_link_methods[] = { PHP_FALIAS(get_warnings, mysqli_get_warnings, NULL) PHP_FALIAS(init,mysqli_init,NULL) PHP_FALIAS(kill,mysqli_kill,NULL) +#if !defined(HAVE_MYSQLND) PHP_FALIAS(set_local_infile_default,mysqli_set_local_infile_default,NULL) PHP_FALIAS(set_local_infile_handler,mysqli_set_local_infile_handler,NULL) +#endif PHP_FALIAS(multi_query,mysqli_multi_query,NULL) PHP_FALIAS(mysqli,mysqli_connect,NULL) PHP_FALIAS(more_results,mysqli_more_results, NULL) diff --git a/ext/mysqli/mysqli_mysqlnd.h b/ext/mysqli/mysqli_mysqlnd.h index e5cd4a14ea..2aaa61d0d8 100644 --- a/ext/mysqli/mysqli_mysqlnd.h +++ b/ext/mysqli/mysqli_mysqlnd.h @@ -19,8 +19,8 @@ */ -#ifndef MYSQL_MYSQLND_H -#define MYSQL_MYSQLND_H +#ifndef MYSQLI_MYSQLND_H +#define MYSQLI_MYSQLND_H #include "ext/mysqlnd/mysqlnd_libmysql_compat.h" diff --git a/ext/mysqli/mysqli_nonapi.c b/ext/mysqli/mysqli_nonapi.c index d2559f8e01..f8407c4117 100644 --- a/ext/mysqli/mysqli_nonapi.c +++ b/ext/mysqli/mysqli_nonapi.c @@ -38,17 +38,18 @@ Open a connection to a mysql server */ PHP_FUNCTION(mysqli_connect) { - MY_MYSQL *mysql; - MYSQLI_RESOURCE *mysqli_resource; - zval *object = getThis(); - char *hostname = NULL, *username=NULL, *passwd=NULL, *dbname=NULL, *socket=NULL; - unsigned int hostname_len = 0, username_len = 0, passwd_len = 0, dbname_len = 0, socket_len = 0; + MY_MYSQL *mysql = NULL; + MYSQLI_RESOURCE *mysqli_resource = NULL; + zval *object = getThis(); + char *hostname = NULL, *username=NULL, *passwd=NULL, *dbname=NULL, *socket=NULL; + unsigned int hostname_len = 0, username_len = 0, passwd_len = 0, dbname_len = 0, socket_len = 0; zend_bool persistent = FALSE; - long port=0; + long port = 0; uint hash_len; char *hash_key = NULL; zend_bool new_connection = FALSE; zend_rsrc_list_entry *le; + mysqli_plist_entry *plist = NULL; if (getThis() && !ZEND_NUM_ARGS()) { RETURN_NULL(); @@ -77,60 +78,123 @@ PHP_FUNCTION(mysqli_connect) hostname = MyG(default_host); } - mysql = (MY_MYSQL *) ecalloc(1, sizeof(MY_MYSQL)); - if (strlen(SAFE_STR(hostname)) > 2 && !strncasecmp(hostname, "p:", 2)) { - mysql->persistent = persistent = TRUE; - hostname += 2; - - if (!strlen(hostname)) { - hostname = MyG(default_host); + if (object && instanceof_function(Z_OBJCE_P(object), mysqli_link_class_entry TSRMLS_CC)) { + mysqli_resource = ((mysqli_object *) zend_object_store_get_object(object TSRMLS_CC))->ptr; + if (mysqli_resource && mysqli_resource->ptr && + mysqli_resource->status >= MYSQLI_STATUS_INITIALIZED) + { + mysql = (MY_MYSQL*)mysqli_resource->ptr; + php_clear_mysql(mysql); + if (mysql->mysql) { + mysqli_close(mysql->mysql, MYSQLI_CLOSE_EXPLICIT); + mysql->mysql = NULL; + } } + } + if (!mysql) { + mysql = (MY_MYSQL *) ecalloc(1, sizeof(MY_MYSQL)); + } - /* caclulate hash length: mysqli_ + Hostname + 5 (Port) + username + dbname + pw */ - hash_len = 7 + strlen(SAFE_STR(hostname)) + 5 + strlen(SAFE_STR(username)) - + strlen(SAFE_STR(dbname)) + strlen(SAFE_STR(passwd)) + 1; - - hash_key = emalloc(hash_len); - hash_len = snprintf(hash_key, hash_len, "mysqli_%s%ld%s%s%s", SAFE_STR(hostname), - port, SAFE_STR(username), SAFE_STR(dbname), - SAFE_STR(passwd)); - - /* check if we can reuse exisiting connection ... */ - if (zend_hash_find(&EG(persistent_list), hash_key, hash_len + 1, (void **)&le) == SUCCESS) { - if (Z_TYPE_P(le) == php_le_pmysqli()) { - mysql->mysql = (MYSQL *)le->ptr; - - /* reset variables */ - /* todo: option for ping or change_user */ + if (strlen(SAFE_STR(hostname)) > 2 && !strncasecmp(hostname, "p:", 2)) { + hostname += 2; + if (!MyG(allow_persistent)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Persistent connections are disabled. Downgrading to normal"); + } else { + mysql->persistent = persistent = TRUE; + + if (!strlen(hostname)) { + hostname = MyG(default_host); + } + + hash_len = spprintf(&hash_key, 0, "mysqli_%s%ld%s%s%s", SAFE_STR(hostname), + port, SAFE_STR(username), SAFE_STR(dbname), + SAFE_STR(passwd)); + + /* check if we can reuse exisiting connection ... */ + if (zend_hash_find(&EG(persistent_list), hash_key, hash_len + 1, (void **)&le) == SUCCESS) { + if (Z_TYPE_P(le) == php_le_pmysqli()) { + plist = (mysqli_plist_entry *) le->ptr; + + do { + if (zend_hash_num_elements(&plist->free_links)) { + HashPosition pos; + MYSQL **free_mysql; + ulong idx; + dtor_func_t pDestructor = plist->free_links.pDestructor; + + zend_hash_internal_pointer_reset_ex(&plist->free_links, &pos); + if (SUCCESS != zend_hash_get_current_data_ex(&plist->free_links, + (void **)&free_mysql, &pos)) { + break; + } + if (HASH_KEY_IS_LONG != zend_hash_get_current_key_ex(&plist->free_links, NULL, + NULL, &idx, FALSE, &pos)) { + break; + } + mysql->mysql = *free_mysql; + plist->free_links.pDestructor = NULL; /* Don't call pDestructor now */ + if (SUCCESS != zend_hash_index_del(&plist->free_links, idx)) { + plist->used_links.pDestructor = pDestructor; /* Restore the destructor */ + break; + } + plist->used_links.pDestructor = pDestructor; /* Restore the destructor */ + MyG(num_inactive_persistent)--; + MyG(num_active_persistent)++; + + /* reset variables */ + /* todo: option for ping or change_user */ #if G0 - if (!mysql_change_user(mysql->mysql, username, passwd, dbname)) { + if (!mysql_change_user(mysql->mysql, username, passwd, dbname)) { +#else + if (!mysql_ping(mysql->mysql)) { #endif - if (!mysql_ping(mysql->mysql)) { #ifdef HAVE_MYSQLND - mysqlnd_restart_psession(mysql->mysql); + mysqlnd_restart_psession(mysql->mysql); #endif - goto end; + idx = zend_hash_next_free_element(&plist->used_links); + if (SUCCESS != zend_hash_next_index_insert(&plist->used_links, &free_mysql, + sizeof(MYSQL *), NULL)) { + php_mysqli_dtor_p_elements(free_mysql); + break; + } + mysql->hash_index = idx; + mysql->hash_key = hash_key; + goto end; + } + } + } while (0); } - /* - Here we fall if the connection is not ok. - When we update EG(persistent_list) with a new connection, this one will - get destructed. No need to do it explicitly. - */ - } + } else { + zend_rsrc_list_entry le; + le.type = php_le_pmysqli(); + le.ptr = plist = calloc(1, sizeof(mysqli_plist_entry)); + + zend_hash_init(&plist->free_links, MAX(10, MyG(max_persistent)), NULL, php_mysqli_dtor_p_elements, 1); + zend_hash_init(&plist->used_links, MAX(10, MyG(max_persistent)), NULL, php_mysqli_dtor_p_elements, 1); + zend_hash_update(&EG(persistent_list), hash_key, hash_len + 1, (void *)&le, sizeof(le), NULL); + } } } + if (MyG(max_links) != -1 && MyG(num_links) >= MyG(max_links)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too many open links (%ld)", MyG(num_links)); + goto err; + } + if (persistent && MyG(max_persistent) != -1 && + (MyG(num_active_persistent) + MyG(num_inactive_persistent))>= MyG(max_persistent)) + { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too many open persistent links (%ld)", + MyG(num_active_persistent) + MyG(num_inactive_persistent)); + goto err; + } + #if !defined(HAVE_MYSQLND) if (!(mysql->mysql = mysql_init(NULL))) { #else if (!(mysql->mysql = mysqlnd_init(persistent))) { #endif - efree(mysql); - if (persistent) { - efree(hash_key); - } - RETURN_FALSE; + goto err; } new_connection = TRUE; @@ -138,7 +202,6 @@ PHP_FUNCTION(mysqli_connect) mysql_options(mysql->mysql, MYSQL_SET_CHARSET_NAME, "utf8"); } - #ifdef HAVE_EMBEDDED_MYSQLI if (hostname_len) { unsigned int external=1; @@ -162,11 +225,7 @@ PHP_FUNCTION(mysqli_connect) /* free mysql structure */ mysqli_close(mysql->mysql, MYSQLI_CLOSE_DISCONNECTED); - efree(mysql); - if (persistent) { - efree(hash_key); - } - RETURN_FALSE; + goto err; } /* when PHP runs in unicode, set default character set to utf8 */ @@ -187,38 +246,48 @@ PHP_FUNCTION(mysqli_connect) mysql_options(mysql->mysql, MYSQL_OPT_LOCAL_INFILE, (char *)&MyG(allow_local_infile)); end: - mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE)); - mysqli_resource->ptr = (void *)mysql; + if (!mysqli_resource) { + mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE)); + mysqli_resource->ptr = (void *)mysql; + } mysqli_resource->status = MYSQLI_STATUS_VALID; /* store persistent connection */ if (persistent && new_connection) { - zend_rsrc_list_entry le; - - le.type = php_le_pmysqli(); - le.ptr = mysql->mysql; - + ulong hash_index = zend_hash_next_free_element(&plist->used_links); /* save persistent connection */ - if (zend_hash_update(&EG(persistent_list), hash_key, hash_len + 1, (void *)&le, - sizeof(le), NULL) == FAILURE) { + if (SUCCESS != zend_hash_next_index_insert(&plist->used_links, &mysql->mysql, + sizeof(MYSQL *), NULL)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't store persistent connection"); - } - } - if (persistent) { - efree(hash_key); + } else { + mysql->hash_index = hash_index; + } + MyG(num_active_persistent)++; } + mysql->hash_key = hash_key; + MyG(num_links)++; + #if !defined(HAVE_MYSQLND) mysql->multi_query = 0; #else mysql->multi_query = 1; #endif + if (!object || !instanceof_function(Z_OBJCE_P(object), mysqli_link_class_entry TSRMLS_CC)) { MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_link_class_entry); } else { ((mysqli_object *) zend_object_store_get_object(object TSRMLS_CC))->ptr = mysqli_resource; } + return; + +err: + efree(mysql); + if (persistent) { + efree(hash_key); + } + RETVAL_FALSE; } /* }}} */ diff --git a/ext/mysqli/mysqli_prop.c b/ext/mysqli/mysqli_prop.c index a6ea40eca5..7ac113bb59 100644 --- a/ext/mysqli/mysqli_prop.c +++ b/ext/mysqli/mysqli_prop.c @@ -313,7 +313,7 @@ MYSQLI_MAP_PROPERTY_FUNC_STRING(stmt_error_read, mysql_stmt_error, MYSQLI_GET_ST MYSQLI_MAP_PROPERTY_FUNC_STRING(stmt_sqlstate_read, mysql_stmt_sqlstate, MYSQLI_GET_STMT(MYSQLI_STATUS_INITIALIZED)); /* }}} */ -mysqli_property_entry mysqli_link_property_entries[] = { +const mysqli_property_entry mysqli_link_property_entries[] = { {"affected_rows", link_affected_rows_read, NULL}, {"client_info", link_client_info_read, NULL}, {"client_version", link_client_version_read, NULL}, @@ -334,7 +334,7 @@ mysqli_property_entry mysqli_link_property_entries[] = { {NULL, NULL, NULL} }; -mysqli_property_entry mysqli_result_property_entries[] = { +const mysqli_property_entry mysqli_result_property_entries[] = { {"current_field", result_current_field_read, NULL}, {"field_count", result_field_count_read, NULL}, {"lengths", result_lengths_read, NULL}, @@ -343,7 +343,7 @@ mysqli_property_entry mysqli_result_property_entries[] = { {NULL, NULL, NULL} }; -mysqli_property_entry mysqli_stmt_property_entries[] = { +const mysqli_property_entry mysqli_stmt_property_entries[] = { {"affected_rows", stmt_affected_rows_read, NULL}, {"insert_id", stmt_insert_id_read, NULL}, {"num_rows", stmt_num_rows_read, NULL}, diff --git a/ext/mysqli/mysqli_warning.c b/ext/mysqli/mysqli_warning.c index 685995e20b..4ad4fcfd13 100644 --- a/ext/mysqli/mysqli_warning.c +++ b/ext/mysqli/mysqli_warning.c @@ -321,7 +321,7 @@ const zend_function_entry mysqli_warning_methods[] = { /* }}} */ /* {{{ mysqli_warning_property_entries */ -mysqli_property_entry mysqli_warning_property_entries[] = { +const mysqli_property_entry mysqli_warning_property_entries[] = { {"message", mysqli_warning_message, NULL}, {"sqlstate", mysqli_warning_sqlstate, NULL}, {"errno", mysqli_warning_errno, NULL}, diff --git a/ext/mysqli/php_mysqli_structs.h b/ext/mysqli/php_mysqli_structs.h index 0bb998ce0f..17997053eb 100644 --- a/ext/mysqli/php_mysqli_structs.h +++ b/ext/mysqli/php_mysqli_structs.h @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 5 | + | PHP Version 6 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2007 The PHP Group | +----------------------------------------------------------------------+ @@ -98,9 +98,11 @@ typedef struct { typedef struct { MYSQL *mysql; + char *hash_key; zval *li_read; php_stream *li_stream; zend_bool persistent; + unsigned long hash_index; /* Used when persistent, hold the index in plist->used_links */ unsigned int multi_query; UConverter *conv; } MY_MYSQL; @@ -145,6 +147,11 @@ typedef struct { } mysqli_local_infile; #endif +typedef struct { + HashTable free_links; + HashTable used_links; +} mysqli_plist_entry; + #ifdef PHP_WIN32 #define PHP_MYSQLI_API __declspec(dllexport) #define MYSQLI_LLU_SPEC "%I64u" @@ -173,11 +180,11 @@ extern const zend_function_entry mysqli_driver_methods[]; extern const zend_function_entry mysqli_warning_methods[]; extern const zend_function_entry mysqli_exception_methods[]; -extern mysqli_property_entry mysqli_link_property_entries[]; -extern mysqli_property_entry mysqli_result_property_entries[]; -extern mysqli_property_entry mysqli_stmt_property_entries[]; -extern mysqli_property_entry mysqli_driver_property_entries[]; -extern mysqli_property_entry mysqli_warning_property_entries[]; +extern const mysqli_property_entry mysqli_link_property_entries[]; +extern const mysqli_property_entry mysqli_result_property_entries[]; +extern const mysqli_property_entry mysqli_stmt_property_entries[]; +extern const mysqli_property_entry mysqli_driver_property_entries[]; +extern const mysqli_property_entry mysqli_warning_property_entries[]; #ifdef HAVE_MYSQLND extern MYSQLND_ZVAL_PCACHE *mysqli_mysqlnd_zval_cache; @@ -205,6 +212,7 @@ extern zend_class_entry *mysqli_driver_class_entry; extern zend_class_entry *mysqli_warning_class_entry; extern zend_class_entry *mysqli_exception_class_entry; extern int php_le_pmysqli(void); +extern void php_mysqli_dtor_p_elements(void *data); #ifdef HAVE_SPL extern PHPAPI zend_class_entry *spl_ce_RuntimeException; @@ -279,9 +287,10 @@ PHP_MYSQLI_EXPORT(zend_object_value) mysqli_objects_new(zend_class_entry * TSRML #define MYSQLI_RETURN_LONG_LONG(__val) \ { \ if ((__val) < LONG_MAX) { \ - RETURN_LONG((__val)); \ + RETURN_LONG((long) (__val)); \ } else { \ char *ret; \ + /* always used with my_ulonglong -> %llu */ \ int l = spprintf(&ret, 0, "%llu", (__val)); \ RETURN_STRINGL(ret, l, 0); \ } \ @@ -347,6 +356,10 @@ ZEND_BEGIN_MODULE_GLOBALS(mysqli) long default_link; long num_links; long max_links; + long num_active_persistent; + long num_inactive_persistent; + long max_persistent; + long allow_persistent; long cache_size; unsigned long default_port; char *default_host; |
