summaryrefslogtreecommitdiff
path: root/ext/mysqli
diff options
context:
space:
mode:
Diffstat (limited to 'ext/mysqli')
-rw-r--r--ext/mysqli/mysqli.c2
-rw-r--r--ext/mysqli/mysqli_api.c132
-rw-r--r--ext/mysqli/mysqli_fe.c19
-rw-r--r--ext/mysqli/mysqli_fe.h1
-rw-r--r--ext/mysqli/mysqli_nonapi.c17
-rw-r--r--ext/mysqli/mysqli_prop.c6
-rw-r--r--ext/mysqli/php_mysqli_structs.h1
-rw-r--r--ext/mysqli/tests/mysqli_class_mysqli_reflection.phpt4
-rw-r--r--ext/mysqli/tests/mysqli_class_mysqli_result_reflection.phpt4
-rw-r--r--ext/mysqli/tests/mysqli_pconn_max_links.phpt98
10 files changed, 200 insertions, 84 deletions
diff --git a/ext/mysqli/mysqli.c b/ext/mysqli/mysqli.c
index 929f776a43..2a5a8c61ff 100644
--- a/ext/mysqli/mysqli.c
+++ b/ext/mysqli/mysqli.c
@@ -558,6 +558,7 @@ 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_BOOLEAN("mysqli.rollback_on_cached_plink", "0",PHP_INI_SYSTEM, OnUpdateBool, rollback_on_cached_plink, 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)
@@ -597,6 +598,7 @@ static PHP_GINIT_FUNCTION(mysqli)
#else
mysqli_globals->embedded = 0;
#endif
+ mysqli_globals->rollback_on_cached_plink = FALSE;
}
/* }}} */
diff --git a/ext/mysqli/mysqli_api.c b/ext/mysqli/mysqli_api.c
index 9028401595..c2d184bd4d 100644
--- a/ext/mysqli/mysqli_api.c
+++ b/ext/mysqli/mysqli_api.c
@@ -34,6 +34,64 @@
#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);
+}
+/* }}} */
+
+
+/* {{{ 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 mixed mysqli_affected_rows(object link)
Get number of affected rows in previous MySQL operation */
PHP_FUNCTION(mysqli_affected_rows)
@@ -599,10 +657,20 @@ void php_mysqli_close(MY_MYSQL * mysql, int close_type, int resource_status TSRM
#if defined(MYSQLI_USE_MYSQLND)
mysqlnd_end_psession(mysql->mysql);
#endif
- zend_ptr_stack_push(&plist->free_links, mysql->mysql);
+ if (MyG(rollback_on_cached_plink) &&
+#if !defined(MYSQLI_USE_MYSQLND)
+ mysqli_commit_or_rollback_libmysql(mysql->mysql, FALSE, TRANS_COR_NO_OPT, NULL))
+#else
+ FAIL == mysqlnd_rollback(mysql->mysql, TRANS_COR_NO_OPT, NULL))
+#endif
+ {
+ mysqli_close(mysql->mysql, close_type);
+ } else {
+ zend_ptr_stack_push(&plist->free_links, mysql->mysql);
+ MyG(num_inactive_persistent)++;
+ }
MyG(num_active_persistent)--;
- MyG(num_inactive_persistent)++;
}
}
mysql->persistent = FALSE;
@@ -636,66 +704,6 @@ 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)
diff --git a/ext/mysqli/mysqli_fe.c b/ext/mysqli/mysqli_fe.c
index 78fe02ab76..3d31b8183c 100644
--- a/ext/mysqli/mysqli_fe.c
+++ b/ext/mysqli/mysqli_fe.c
@@ -43,23 +43,28 @@
#define MYSQLI_ZEND_ARG_OBJ_INFO_STMT() ZEND_ARG_INFO(0, stmt)
#endif
-ZEND_BEGIN_ARG_INFO(arginfo_mysqli_stmt_bind_result, 1)
+ZEND_BEGIN_ARG_INFO(arginfo_mysqli_stmt_bind_result, 0)
MYSQLI_ZEND_ARG_OBJ_INFO_STMT()
+ ZEND_ARG_VARIADIC_INFO(1, vars)
ZEND_END_ARG_INFO()
-ZEND_BEGIN_ARG_INFO(arginfo_mysqli_stmt_bind_param, 1)
+ZEND_BEGIN_ARG_INFO(arginfo_mysqli_stmt_bind_param, 0)
MYSQLI_ZEND_ARG_OBJ_INFO_STMT()
ZEND_ARG_INFO(0, types)
+ ZEND_ARG_VARIADIC_INFO(1, vars)
ZEND_END_ARG_INFO()
-ZEND_BEGIN_ARG_INFO(arginfo_class_mysqli_stmt_bind_result, 1)
+ZEND_BEGIN_ARG_INFO(arginfo_class_mysqli_stmt_bind_result, 0)
+ ZEND_ARG_VARIADIC_INFO(1, vars)
ZEND_END_ARG_INFO()
-ZEND_BEGIN_ARG_INFO(arginfo_class_mysqli_stmt_bind_param, 1)
+ZEND_BEGIN_ARG_INFO(arginfo_class_mysqli_stmt_bind_param, 0)
ZEND_ARG_INFO(0, types)
+ ZEND_ARG_VARIADIC_INFO(1, vars)
ZEND_END_ARG_INFO()
-ZEND_BEGIN_ARG_INFO(all_args_force_by_ref, 1)
+ZEND_BEGIN_ARG_INFO(all_args_force_by_ref, 0)
+ ZEND_ARG_VARIADIC_INFO(1, vars)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqli_poll, 0, 0, 4)
@@ -368,6 +373,9 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_mysqli_refresh, 0, 0, 1)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
+ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqli_no_options, 0, 0, 0)
+ZEND_END_ARG_INFO()
+
/* {{{ mysqli_functions[]
*
@@ -420,6 +428,7 @@ const zend_function_entry mysqli_functions[] = {
#endif
PHP_FE(mysqli_get_client_info, arginfo_mysqli_only_link)
PHP_FE(mysqli_get_client_version, arginfo_mysqli_only_link)
+ PHP_FE(mysqli_get_links_stats, arginfo_mysqli_no_options)
PHP_FE(mysqli_get_host_info, arginfo_mysqli_only_link)
PHP_FE(mysqli_get_proto_info, arginfo_mysqli_only_link)
PHP_FE(mysqli_get_server_info, arginfo_mysqli_only_link)
diff --git a/ext/mysqli/mysqli_fe.h b/ext/mysqli/mysqli_fe.h
index d5ae8a6ff9..9a9f851248 100644
--- a/ext/mysqli/mysqli_fe.h
+++ b/ext/mysqli/mysqli_fe.h
@@ -60,6 +60,7 @@ PHP_FUNCTION(mysqli_get_charset);
PHP_FUNCTION(mysqli_get_client_info);
PHP_FUNCTION(mysqli_get_client_version);
PHP_FUNCTION(mysqli_get_host_info);
+PHP_FUNCTION(mysqli_get_links_stats);
PHP_FUNCTION(mysqli_get_proto_info);
PHP_FUNCTION(mysqli_get_server_info);
PHP_FUNCTION(mysqli_get_server_version);
diff --git a/ext/mysqli/mysqli_nonapi.c b/ext/mysqli/mysqli_nonapi.c
index db0352baeb..312f2806ce 100644
--- a/ext/mysqli/mysqli_nonapi.c
+++ b/ext/mysqli/mysqli_nonapi.c
@@ -1207,6 +1207,23 @@ PHP_FUNCTION(mysqli_release_savepoint)
/* }}} */
+/* {{{ proto bool mysqli_get_links_stats()
+ Returns information about open and cached links */
+PHP_FUNCTION(mysqli_get_links_stats)
+{
+ if (ZEND_NUM_ARGS()) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "no parameters expected");
+ return;
+ }
+ array_init(return_value);
+ add_assoc_long_ex(return_value, "total", sizeof("total"), MyG(num_links));
+ add_assoc_long_ex(return_value, "active_plinks", sizeof("active_plinks"), MyG(num_active_persistent));
+ add_assoc_long_ex(return_value, "cached_plinks", sizeof("cached_plinks"), MyG(num_inactive_persistent));
+}
+/* }}} */
+
+
+
/*
* Local variables:
* tab-width: 4
diff --git a/ext/mysqli/mysqli_prop.c b/ext/mysqli/mysqli_prop.c
index 7060367394..2d36336372 100644
--- a/ext/mysqli/mysqli_prop.c
+++ b/ext/mysqli/mysqli_prop.c
@@ -311,19 +311,21 @@ static int result_lengths_read(mysqli_object *obj, zval **retval TSRMLS_DC)
{
MYSQL_RES *p;
ulong *ret;
+ uint field_count;
MAKE_STD_ZVAL(*retval);
CHECK_STATUS(MYSQLI_STATUS_VALID);
p = (MYSQL_RES *)((MYSQLI_RESOURCE *)(obj->ptr))->ptr;
- if (!p || !p->field_count || !(ret = mysql_fetch_lengths(p))) {
+ field_count = mysql_num_fields(p);
+ if (!p || !field_count || !(ret = mysql_fetch_lengths(p))) {
ZVAL_NULL(*retval);
} else {
ulong i;
array_init(*retval);
- for (i = 0; i < p->field_count; i++) {
+ for (i = 0; i < field_count; i++) {
add_index_long(*retval, i, ret[i]);
}
}
diff --git a/ext/mysqli/php_mysqli_structs.h b/ext/mysqli/php_mysqli_structs.h
index e7c02f9c9b..cc0c8fe63f 100644
--- a/ext/mysqli/php_mysqli_structs.h
+++ b/ext/mysqli/php_mysqli_structs.h
@@ -334,6 +334,7 @@ ZEND_BEGIN_MODULE_GLOBALS(mysqli)
HashTable *report_ht;
unsigned long multi_query;
unsigned long embedded;
+ zend_bool rollback_on_cached_plink;
ZEND_END_MODULE_GLOBALS(mysqli)
diff --git a/ext/mysqli/tests/mysqli_class_mysqli_reflection.phpt b/ext/mysqli/tests/mysqli_class_mysqli_reflection.phpt
index 259fcd9ae6..63ec7ca3c0 100644
--- a/ext/mysqli/tests/mysqli_class_mysqli_reflection.phpt
+++ b/ext/mysqli/tests/mysqli_class_mysqli_reflection.phpt
@@ -657,7 +657,7 @@ isDestructor: no
isInternal: yes
isUserDefined: no
returnsReference: no
-Modifiers: 257
+Modifiers: 268435713
Number of Parameters: 5
Number of Required Parameters: 4
@@ -1345,4 +1345,4 @@ Default property 'sqlstate'
Default property 'stat'
Default property 'thread_id'
Default property 'warning_count'
-done! \ No newline at end of file
+done!
diff --git a/ext/mysqli/tests/mysqli_class_mysqli_result_reflection.phpt b/ext/mysqli/tests/mysqli_class_mysqli_result_reflection.phpt
index 988b82732a..95400e43e0 100644
--- a/ext/mysqli/tests/mysqli_class_mysqli_result_reflection.phpt
+++ b/ext/mysqli/tests/mysqli_class_mysqli_result_reflection.phpt
@@ -233,7 +233,7 @@ isDestructor: no
isInternal: yes
isUserDefined: no
returnsReference: no
-Modifiers: 256
+Modifiers: 268435712
Number of Parameters: 2
Number of Required Parameters: 0
@@ -366,4 +366,4 @@ Default property 'field_count'
Default property 'lengths'
Default property 'num_rows'
Default property 'type'
-done! \ No newline at end of file
+done!
diff --git a/ext/mysqli/tests/mysqli_pconn_max_links.phpt b/ext/mysqli/tests/mysqli_pconn_max_links.phpt
index e87ef00b21..99e51e7c5e 100644
--- a/ext/mysqli/tests/mysqli_pconn_max_links.phpt
+++ b/ext/mysqli/tests/mysqli_pconn_max_links.phpt
@@ -42,6 +42,7 @@ Persistent connections and mysqli.max_links
--INI--
mysqli.allow_persistent=1
mysqli.max_persistent=2
+mysqli.rollback_on_cached_plink=1
--FILE--
<?php
require_once("connect.inc");
@@ -58,10 +59,18 @@ mysqli.max_persistent=2
mysqli_errno($plink), mysqli_error($plink));
}
+ var_dump(mysqli_get_links_stats(1));
+
+ echo "Before pconnect:";
+ var_dump(mysqli_get_links_stats());
+
if (!$plink = my_mysqli_connect('p:' . $host, 'pcontest', 'pcontest', $db, $port, $socket))
printf("[001] Cannot connect using the second DB user created during SKIPIF, [%d] %s\n",
mysqli_connect_errno(), mysqli_connect_error());
+ echo "After pconnect:";
+ var_dump(mysqli_get_links_stats());
+
ob_start();
phpinfo();
$phpinfo = strip_tags(ob_get_contents());
@@ -110,11 +119,17 @@ mysqli.max_persistent=2
if (isset($running_threads[$pthread_id]))
printf("[009] Persistent connection has not been killed\n");
+ echo "Before second pconnect:";
+ var_dump(mysqli_get_links_stats());
+
// this fails and we have 0 (<= $num_plinks) connections
if ($plink = @my_mysqli_connect('p:' . $host, 'pcontest', 'pcontest', $db, $port, $socket))
printf("[010] Can connect using the old password, [%d] %s\n",
mysqli_connect_errno($link), mysqli_connect_error($link));
+ echo "After second pconnect:";
+ var_dump(mysqli_get_links_stats());
+
ob_start();
phpinfo();
$phpinfo = strip_tags(ob_get_contents());
@@ -123,7 +138,13 @@ mysqli.max_persistent=2
if (!preg_match('@Active Persistent Links\s+=>\s+(\d+)@ismU', $phpinfo, $matches))
printf("[010] Cannot get # of active persistent links from phpinfo()\n");
+ var_dump(mysqli_get_links_stats());
+
$num_plinks_kill = $matches[1];
+ $sstats = mysqli_get_links_stats();
+ if ($sstats['active_plinks'] != $num_plinks_kill) {
+ printf("[010.2] Num of active plinks differ %s %s\n", $sstats['active_plinks'], $num_plinks_kill);
+ }
if ($num_plinks_kill > $num_plinks)
printf("[011] Expecting Active Persistent Links < %d, got %d\n", $num_plinks, $num_plinks_kill);
@@ -141,9 +162,11 @@ mysqli.max_persistent=2
mysqli_free_result($res);
var_dump($row);
- if ($plink2 = my_mysqli_connect('p:' . $host, 'pcontest', 'newpass', $db, $port, $socket))
+ if ($plink2 = my_mysqli_connect('p:' . $host, 'pcontest', 'newpass', $db, $port, $socket)) {
printf("[015] Can open more persistent connections than allowed, [%d] %s\n",
mysqli_connect_errno(), mysqli_connect_error());
+ var_dump(mysqli_get_links_stats());
+ }
ob_start();
phpinfo();
@@ -179,18 +202,71 @@ mysqli_query($link, 'DROP USER pcontest');
mysqli_close($link);
?>
--EXPECTF--
-array(2) {
- [%u|b%"id"]=>
- %unicode|string%(1) "1"
- [%u|b%"label"]=>
- %unicode|string%(1) "a"
+Warning: mysqli_get_links_stats(): no parameters expected in %s on line %d
+NULL
+Before pconnect:array(3) {
+ ["total"]=>
+ int(1)
+ ["active_plinks"]=>
+ int(0)
+ ["cached_plinks"]=>
+ int(0)
+}
+After pconnect:array(3) {
+ ["total"]=>
+ int(2)
+ ["active_plinks"]=>
+ int(1)
+ ["cached_plinks"]=>
+ int(0)
}
array(2) {
- [%u|b%"id"]=>
- %unicode|string%(1) "1"
- [%u|b%"label"]=>
- %unicode|string%(1) "a"
+ ["id"]=>
+ string(1) "1"
+ ["label"]=>
+ string(1) "a"
+}
+Before second pconnect:array(3) {
+ ["total"]=>
+ int(2)
+ ["active_plinks"]=>
+ int(1)
+ ["cached_plinks"]=>
+ int(0)
}
-Warning: %s: Too many open persistent links (%d) in %s on line %d
+Warning: main(): MySQL server has gone away in %s on line %d
+
+Warning: main(): Error reading result set's header in %s line %d
+After second pconnect:array(3) {
+ ["total"]=>
+ int(1)
+ ["active_plinks"]=>
+ int(0)
+ ["cached_plinks"]=>
+ int(0)
+}
+array(3) {
+ ["total"]=>
+ int(1)
+ ["active_plinks"]=>
+ int(0)
+ ["cached_plinks"]=>
+ int(0)
+}
+array(2) {
+ ["id"]=>
+ string(1) "1"
+ ["label"]=>
+ string(1) "a"
+}
+[015] Can open more persistent connections than allowed, [0]
+array(3) {
+ ["total"]=>
+ int(3)
+ ["active_plinks"]=>
+ int(2)
+ ["cached_plinks"]=>
+ int(0)
+}
done! \ No newline at end of file