summaryrefslogtreecommitdiff
path: root/ext/mysqli
diff options
context:
space:
mode:
authorAndrey Hristov <andrey@php.net>2007-10-02 10:45:27 +0000
committerAndrey Hristov <andrey@php.net>2007-10-02 10:45:27 +0000
commit9ac92cfecb9522d4679d7e3dc2e38be1b11a6467 (patch)
treee7e5931f5d0359b749c0a4668658bd2b2efe2cea /ext/mysqli
parentf0e5df4544d0aa7378bc620577ba1e814a1a0aea (diff)
downloadphp-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.c118
-rw-r--r--ext/mysqli/mysqli_api.c45
-rw-r--r--ext/mysqli/mysqli_driver.c2
-rw-r--r--ext/mysqli/mysqli_fe.c4
-rw-r--r--ext/mysqli/mysqli_mysqlnd.h4
-rw-r--r--ext/mysqli/mysqli_nonapi.c195
-rw-r--r--ext/mysqli/mysqli_prop.c6
-rw-r--r--ext/mysqli/mysqli_warning.c2
-rw-r--r--ext/mysqli/php_mysqli_structs.h27
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;