xref: /PHP-8.2/ext/mysqli/mysqli_nonapi.c (revision 646b8f6b)
1 /*
2   +----------------------------------------------------------------------+
3   | Copyright (c) The PHP Group                                          |
4   +----------------------------------------------------------------------+
5   | This source file is subject to version 3.01 of the PHP license,      |
6   | that is bundled with this package in the file LICENSE, and is        |
7   | available through the world-wide-web at the following url:           |
8   | https://www.php.net/license/3_01.txt                                 |
9   | If you did not receive a copy of the PHP license and are unable to   |
10   | obtain it through the world-wide-web, please send a note to          |
11   | license@php.net so we can mail you a copy immediately.               |
12   +----------------------------------------------------------------------+
13   | Authors: Georg Richter <georg@php.net>                               |
14   |          Andrey Hristov <andrey@php.net>                             |
15   |          Ulf Wendel <uw@php.net>                                     |
16   +----------------------------------------------------------------------+
17 */
18 
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22 
23 #include <signal.h>
24 
25 #include "php.h"
26 #include "php_ini.h"
27 #include "ext/standard/info.h"
28 #include "zend_smart_str.h"
29 #include "php_mysqli_structs.h"
30 #include "mysqli_priv.h"
31 #define ERROR_ARG_POS(arg_num) (getThis() ? (arg_num-1) : (arg_num))
32 
33 #define SAFE_STR(a) ((a)?a:"")
34 
35 /* {{{ php_mysqli_set_error */
php_mysqli_set_error(zend_long mysql_errno,char * mysql_err)36 static void php_mysqli_set_error(zend_long mysql_errno, char *mysql_err)
37 {
38 	MyG(error_no) = mysql_errno;
39 	if (MyG(error_msg)) {
40 		efree(MyG(error_msg));
41 	}
42 	if(mysql_err && *mysql_err) {
43 		MyG(error_msg) = estrdup(mysql_err);
44 	} else {
45 		MyG(error_msg) = NULL;
46 	}
47 }
48 /* }}} */
49 
mysqli_common_connect(INTERNAL_FUNCTION_PARAMETERS,bool is_real_connect,bool in_ctor)50 void mysqli_common_connect(INTERNAL_FUNCTION_PARAMETERS, bool is_real_connect, bool in_ctor) /* {{{ */
51 {
52 	MY_MYSQL			*mysql = NULL;
53 	MYSQLI_RESOURCE		*mysqli_resource = NULL;
54 	zval				*object = getThis();
55 	char				*hostname = NULL, *username=NULL, *passwd=NULL, *dbname=NULL, *socket=NULL,
56 						*ssl_key = NULL, *ssl_cert = NULL, *ssl_ca = NULL, *ssl_capath = NULL,
57 						*ssl_cipher = NULL;
58 	size_t				hostname_len = 0, username_len = 0, passwd_len = 0, dbname_len = 0, socket_len = 0;
59 	bool			persistent = false, ssl = false;
60 	zend_long			port = 0, flags = 0;
61 	bool           port_is_null = 1;
62 	zend_string			*hash_key = NULL;
63 	bool			new_connection = false;
64 	zend_resource		*le;
65 	mysqli_plist_entry *plist = NULL;
66 	bool			self_alloced = 0;
67 
68 
69 #if !defined(MYSQL_USE_MYSQLND)
70 	if ((MYSQL_VERSION_ID / 100) != (mysql_get_client_version() / 100)) {
71 		php_error_docref(NULL, E_WARNING,
72 						"Headers and client library minor version mismatch. Headers:%d Library:%ld",
73 						MYSQL_VERSION_ID, mysql_get_client_version());
74 	}
75 #endif
76 
77 	if (getThis() && !ZEND_NUM_ARGS() && in_ctor) {
78 		php_mysqli_init(INTERNAL_FUNCTION_PARAM_PASSTHRU, in_ctor);
79 		return;
80 	}
81 	hostname = username = dbname = passwd = socket = NULL;
82 
83 	if (!is_real_connect) {
84 		if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s!s!s!s!l!s!", &hostname, &hostname_len, &username, &username_len,
85 				&passwd, &passwd_len, &dbname, &dbname_len, &port, &port_is_null, &socket, &socket_len) == FAILURE) {
86 			RETURN_THROWS();
87 		}
88 
89 		if (object) {
90 			ZEND_ASSERT(instanceof_function(Z_OBJCE_P(object), mysqli_link_class_entry));
91 			mysqli_resource = (Z_MYSQLI_P(object))->ptr;
92 			if (mysqli_resource && mysqli_resource->ptr) {
93 				mysql = (MY_MYSQL*) mysqli_resource->ptr;
94 			}
95 		}
96 		if (!mysql) {
97 			mysql = (MY_MYSQL *) ecalloc(1, sizeof(MY_MYSQL));
98 			self_alloced = 1;
99 		}
100 		flags |= CLIENT_MULTI_RESULTS; /* needed for mysql_multi_query() */
101 	} else {
102 		/* We have flags too */
103 		if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|s!s!s!s!l!s!l", &object, mysqli_link_class_entry,
104 				&hostname, &hostname_len, &username, &username_len, &passwd, &passwd_len, &dbname, &dbname_len, &port, &port_is_null, &socket, &socket_len, &flags) == FAILURE) {
105 			RETURN_THROWS();
106 		}
107 
108 		mysqli_resource = (Z_MYSQLI_P(object))->ptr;
109 		MYSQLI_FETCH_RESOURCE_CONN(mysql, object, MYSQLI_STATUS_INITIALIZED);
110 
111 		/* set some required options */
112 		flags |= CLIENT_MULTI_RESULTS; /* needed for mysql_multi_query() */
113 		/* remove some insecure options */
114 		flags &= ~CLIENT_MULTI_STATEMENTS;   /* don't allow multi_queries via connect parameter */
115 	}
116 
117 	if (!socket_len || !socket) {
118 		socket = MyG(default_socket);
119 	}
120 	if (port_is_null || !port) {
121 		port = MyG(default_port);
122 	}
123 	if (!passwd) {
124 		passwd = MyG(default_pw);
125 		passwd_len = strlen(SAFE_STR(passwd));
126 	}
127 	if (!username){
128 		username = MyG(default_user);
129 	}
130 	if (!hostname || !hostname_len) {
131 		hostname = MyG(default_host);
132 	}
133 
134 	if (mysql->mysql && mysqli_resource &&
135 		(mysqli_resource->status > MYSQLI_STATUS_INITIALIZED))
136 	{
137 		/* already connected, we should close the connection */
138 		php_mysqli_close(mysql, MYSQLI_CLOSE_IMPLICIT, mysqli_resource->status);
139 	}
140 
141 	if (strlen(SAFE_STR(hostname)) > 2 && !strncasecmp(hostname, "p:", 2)) {
142 		hostname += 2;
143 		if (!MyG(allow_persistent)) {
144 			php_error_docref(NULL, E_WARNING, "Persistent connections are disabled. Downgrading to normal");
145 		} else {
146 			mysql->persistent = persistent = true;
147 
148 			hash_key = strpprintf(0, "mysqli_%s_%s" ZEND_LONG_FMT "%s%s%s", SAFE_STR(hostname), SAFE_STR(socket),
149 								port, SAFE_STR(username), SAFE_STR(dbname),
150 								SAFE_STR(passwd));
151 
152 			mysql->hash_key = hash_key;
153 
154 			/* check if we can reuse existing connection ... */
155 			if ((le = zend_hash_find_ptr(&EG(persistent_list), hash_key)) != NULL) {
156 				if (le->type == php_le_pmysqli()) {
157 					plist = (mysqli_plist_entry *) le->ptr;
158 
159 					do {
160 						if (zend_ptr_stack_num_elements(&plist->free_links)) {
161 							/* If we have an initialized (but unconnected) mysql resource,
162 							 * close it before we reuse an existing persistent resource. */
163 							if (mysql->mysql) {
164 								mysqli_close(mysql->mysql, MYSQLI_CLOSE_IMPLICIT);
165 							}
166 
167 							mysql->mysql = zend_ptr_stack_pop(&plist->free_links);
168 
169 							MyG(num_inactive_persistent)--;
170 							/* reset variables */
171 
172 #ifndef MYSQLI_NO_CHANGE_USER_ON_PCONNECT
173 							if (!mysqli_change_user_silent(mysql->mysql, username, passwd, dbname, passwd_len)) {
174 #else
175 							if (!mysql_ping(mysql->mysql)) {
176 #endif
177 								mysqlnd_restart_psession(mysql->mysql);
178 								MyG(num_active_persistent)++;
179 
180 								/* clear error */
181 								php_mysqli_set_error(mysql_errno(mysql->mysql), (char *) mysql_error(mysql->mysql));
182 
183 								goto end;
184 							} else {
185 								if (mysql->mysql->data->vio->data->ssl) {
186 									/* copy over pre-existing ssl settings so we can reuse them when reconnecting */
187 									ssl = true;
188 
189 									ssl_key = mysql->mysql->data->vio->data->options.ssl_key ? estrdup(mysql->mysql->data->vio->data->options.ssl_key) : NULL;
190 									ssl_cert = mysql->mysql->data->vio->data->options.ssl_cert ? estrdup(mysql->mysql->data->vio->data->options.ssl_cert) : NULL;
191 									ssl_ca = mysql->mysql->data->vio->data->options.ssl_ca ? estrdup(mysql->mysql->data->vio->data->options.ssl_ca) : NULL;
192 									ssl_capath = mysql->mysql->data->vio->data->options.ssl_capath ? estrdup(mysql->mysql->data->vio->data->options.ssl_capath) : NULL;
193 									ssl_cipher = mysql->mysql->data->vio->data->options.ssl_cipher ? estrdup(mysql->mysql->data->vio->data->options.ssl_cipher) : NULL;
194 								}
195 
196 								mysqli_close(mysql->mysql, MYSQLI_CLOSE_IMPLICIT);
197 								mysql->mysql = NULL;
198 							}
199 						}
200 					} while (0);
201 				}
202 			} else {
203 				plist = calloc(1, sizeof(mysqli_plist_entry));
204 
205 				zend_ptr_stack_init_ex(&plist->free_links, 1);
206 				zend_register_persistent_resource(ZSTR_VAL(hash_key), ZSTR_LEN(hash_key), plist, php_le_pmysqli());
207 			}
208 		}
209 	}
210 	if (MyG(max_links) != -1 && MyG(num_links) >= MyG(max_links)) {
211 		php_error_docref(NULL, E_WARNING, "Too many open links (" ZEND_LONG_FMT ")", MyG(num_links));
212 		goto err;
213 	}
214 
215 	if (persistent && MyG(max_persistent) != -1 &&
216 		(MyG(num_active_persistent) + MyG(num_inactive_persistent))>= MyG(max_persistent))
217 	{
218 		php_error_docref(NULL, E_WARNING, "Too many open persistent links (" ZEND_LONG_FMT ")",
219 								MyG(num_active_persistent) + MyG(num_inactive_persistent));
220 		goto err;
221 	}
222 	if (!mysql->mysql) {
223 		if (!(mysql->mysql = mysqlnd_init(MYSQLND_CLIENT_NO_FLAG, persistent))) {
224 			goto err;
225 		}
226 		new_connection = true;
227 	}
228 
229 	if (ssl) {
230 		/* if we're here, this means previous conn was ssl, repopulate settings */
231 		mysql_ssl_set(mysql->mysql, ssl_key, ssl_cert, ssl_ca, ssl_capath, ssl_cipher);
232 
233 		if (ssl_key) {
234 		    efree(ssl_key);
235 		}
236 
237 		if (ssl_cert) {
238 		    efree(ssl_cert);
239 		}
240 
241 		if (ssl_ca) {
242 		    efree(ssl_ca);
243 		}
244 
245 		if (ssl_capath) {
246 		    efree(ssl_capath);
247 		}
248 
249 		if (ssl_cipher) {
250 		    efree(ssl_cipher);
251 		}
252 	}
253 	if (mysqlnd_connect(mysql->mysql, hostname, username, passwd, passwd_len, dbname, dbname_len,
254 						port, socket, flags, MYSQLND_CLIENT_NO_FLAG) == NULL)
255 	{
256 		/* Save error messages - for mysqli_connect_error() & mysqli_connect_errno() */
257 		php_mysqli_set_error(mysql_errno(mysql->mysql), (char *) mysql_error(mysql->mysql));
258 		php_mysqli_throw_sql_exception((char *)mysql_sqlstate(mysql->mysql), mysql_errno(mysql->mysql),
259 										"%s", mysql_error(mysql->mysql));
260 		if (!is_real_connect) {
261 			/* free mysql structure */
262 			mysqli_close(mysql->mysql, MYSQLI_CLOSE_DISCONNECTED);
263 			mysql->mysql = NULL;
264 		}
265 		goto err;
266 	}
267 
268 	/* clear error */
269 	php_mysqli_set_error(mysql_errno(mysql->mysql), (char *) mysql_error(mysql->mysql));
270 
271 	unsigned int allow_local_infile = MyG(allow_local_infile);
272 	mysql_options(mysql->mysql, MYSQL_OPT_LOCAL_INFILE, (char *)&allow_local_infile);
273 
274 	if (MyG(local_infile_directory) && !php_check_open_basedir(MyG(local_infile_directory))) {
275 		mysql_options(mysql->mysql, MYSQL_OPT_LOAD_DATA_LOCAL_DIR, MyG(local_infile_directory));
276 	}
277 
278 end:
279 	if (!mysqli_resource) {
280 		mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
281 		mysqli_resource->ptr = (void *)mysql;
282 	}
283 	mysqli_resource->status = MYSQLI_STATUS_VALID;
284 
285 	/* store persistent connection */
286 	if (persistent && (new_connection || is_real_connect)) {
287 		MyG(num_active_persistent)++;
288 	}
289 
290 	MyG(num_links)++;
291 
292 	mysql->multi_query = 0;
293 
294 	if (object) {
295 		ZEND_ASSERT(instanceof_function(Z_OBJCE_P(object), mysqli_link_class_entry));
296 		(Z_MYSQLI_P(object))->ptr = mysqli_resource;
297 		RETURN_TRUE;
298 	} else {
299 		MYSQLI_RETVAL_RESOURCE(mysqli_resource, mysqli_link_class_entry);
300 		return;
301 	}
302 
303 err:
304 	if (mysql->hash_key) {
305 		zend_string_release_ex(mysql->hash_key, 0);
306 		mysql->hash_key = NULL;
307 		mysql->persistent = false;
308 	}
309 	if (!is_real_connect && self_alloced) {
310 		efree(mysql);
311 	}
312 	RETVAL_FALSE;
313 } /* }}} */
314 
315 /* {{{ Open a connection to a mysql server */
316 PHP_FUNCTION(mysqli_connect)
317 {
318 	mysqli_common_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, false, false);
319 }
320 /* }}} */
321 
322 PHP_METHOD(mysqli, __construct)
323 {
324 	mysqli_common_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, false, true);
325 }
326 
327 /* {{{ Initialize mysqli and return a resource for use with mysql_real_connect */
328 PHP_METHOD(mysqli, init)
329 {
330 	php_mysqli_init(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
331 }
332 /* }}} */
333 
334 /* {{{ Returns the numerical value of the error message from last connect command */
335 PHP_FUNCTION(mysqli_connect_errno)
336 {
337 	if (zend_parse_parameters_none() == FAILURE) {
338 		RETURN_THROWS();
339 	}
340 
341 	RETURN_LONG(MyG(error_no));
342 }
343 /* }}} */
344 
345 /* {{{ Returns the text of the error message from previous MySQL operation */
346 PHP_FUNCTION(mysqli_connect_error)
347 {
348 	if (zend_parse_parameters_none() == FAILURE) {
349 		RETURN_THROWS();
350 	}
351 
352 	if (MyG(error_msg)) {
353 		RETURN_STRING(MyG(error_msg));
354 	} else {
355 		RETURN_NULL();
356 	}
357 }
358 /* }}} */
359 
360 /* {{{ Fetch a result row as an associative array, a numeric array, or both */
361 PHP_FUNCTION(mysqli_fetch_array)
362 {
363 	php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0);
364 }
365 /* }}} */
366 
367 /* {{{ Fetch a result row as an associative array */
368 PHP_FUNCTION(mysqli_fetch_assoc)
369 {
370 	php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQLI_ASSOC, 0);
371 }
372 /* }}} */
373 
374 /* {{{ Fetch a column from the result row  */
375 PHP_FUNCTION(mysqli_fetch_column)
376 {
377 	MYSQL_RES		*result;
378 	zval			*mysql_result;
379 	zval 			row_array;
380 	zend_long		col_no = 0;
381 
382 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|l", &mysql_result, mysqli_result_class_entry, &col_no) == FAILURE) {
383 		RETURN_THROWS();
384 	}
385 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES*, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
386 
387 	if (col_no < 0) {
388 		zend_argument_value_error(ERROR_ARG_POS(2), "must be greater than or equal to 0");
389 		RETURN_THROWS();
390 	}
391 	if (col_no >= mysql_num_fields(result)) {
392 		zend_argument_value_error(ERROR_ARG_POS(2), "must be less than the number of fields for this result set");
393 		RETURN_THROWS();
394 	}
395 
396 	php_mysqli_fetch_into_hash_aux(&row_array, result, MYSQLI_NUM);
397 	if (Z_TYPE(row_array) != IS_ARRAY) {
398 		zval_ptr_dtor_nogc(&row_array);
399 		RETURN_FALSE;
400 	}
401 
402 	ZVAL_COPY(return_value, zend_hash_index_find(Z_ARR(row_array), col_no));
403 	zval_ptr_dtor_nogc(&row_array);
404 }
405 /* }}} */
406 
407 /* {{{ Fetches all result rows as an associative array, a numeric array, or both */
408 PHP_FUNCTION(mysqli_fetch_all)
409 {
410 	MYSQL_RES	*result;
411 	zval		*mysql_result;
412 	zend_long		mode = MYSQLI_NUM;
413 
414 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|l", &mysql_result, mysqli_result_class_entry, &mode) == FAILURE) {
415 		RETURN_THROWS();
416 	}
417 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
418 
419 	if (!mode || (mode & ~MYSQLI_BOTH)) {
420 		zend_argument_value_error(ERROR_ARG_POS(2), "must be one of MYSQLI_NUM, MYSQLI_ASSOC, or MYSQLI_BOTH");
421 		RETURN_THROWS();
422 	}
423 
424 	array_init_size(return_value, mysql_num_rows(result));
425 
426 	zend_ulong i = 0;
427 	do {
428 		zval row;
429 		php_mysqli_fetch_into_hash_aux(&row, result, mode);
430 		if (Z_TYPE(row) != IS_ARRAY) {
431 			zval_ptr_dtor_nogc(&row);
432 			break;
433 		}
434 		add_index_zval(return_value, i++, &row);
435 	} while (1);
436 }
437 /* }}} */
438 
439 /* {{{ Returns statistics about the zval cache */
440 PHP_FUNCTION(mysqli_get_client_stats)
441 {
442 	if (zend_parse_parameters_none() == FAILURE) {
443 		RETURN_THROWS();
444 	}
445 	mysqlnd_get_client_stats(return_value);
446 }
447 /* }}} */
448 
449 /* {{{ Returns statistics about the zval cache */
450 PHP_FUNCTION(mysqli_get_connection_stats)
451 {
452 	MY_MYSQL	*mysql;
453 	zval		*mysql_link;
454 
455 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
456 									 &mysql_link, mysqli_link_class_entry) == FAILURE) {
457 		RETURN_THROWS();
458 	}
459 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
460 
461 	mysqlnd_get_connection_stats(mysql->mysql, return_value);
462 }
463 /* }}} */
464 
465 /* {{{ Fetches all client errors */
466 PHP_FUNCTION(mysqli_error_list)
467 {
468 	MY_MYSQL	*mysql;
469 	zval		*mysql_link;
470 
471 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
472 		RETURN_THROWS();
473 	}
474 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
475 
476 	MYSQLND_ERROR_LIST_ELEMENT * message;
477 	zend_llist_position pos;
478 	array_init(return_value);
479 	for (message = (MYSQLND_ERROR_LIST_ELEMENT *) zend_llist_get_first_ex(&mysql->mysql->data->error_info->error_list, &pos);
480 			message;
481 			message = (MYSQLND_ERROR_LIST_ELEMENT *) zend_llist_get_next_ex(&mysql->mysql->data->error_info->error_list, &pos))
482 	{
483 		zval single_error;
484 		array_init(&single_error);
485 		add_assoc_long_ex(&single_error, "errno", sizeof("errno") - 1, message->error_no);
486 		add_assoc_string_ex(&single_error, "sqlstate", sizeof("sqlstate") - 1, message->sqlstate);
487 		add_assoc_string_ex(&single_error, "error", sizeof("error") - 1, message->error);
488 		add_next_index_zval(return_value, &single_error);
489 	}
490 }
491 /* }}} */
492 
493 /* {{{ */
494 PHP_FUNCTION(mysqli_stmt_error_list)
495 {
496 	MY_STMT	*stmt;
497 	zval 	*mysql_stmt;
498 
499 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
500 		RETURN_THROWS();
501 	}
502 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_INITIALIZED);
503 	if (stmt->stmt && stmt->stmt->data && stmt->stmt->data->error_info) {
504 		MYSQLND_ERROR_LIST_ELEMENT * message;
505 		zend_llist_position pos;
506 		array_init(return_value);
507 		for (message = (MYSQLND_ERROR_LIST_ELEMENT *) zend_llist_get_first_ex(&stmt->stmt->data->error_info->error_list, &pos);
508 			 message;
509 			 message = (MYSQLND_ERROR_LIST_ELEMENT *) zend_llist_get_next_ex(&stmt->stmt->data->error_info->error_list, &pos))
510 		{
511 			zval single_error;
512 			array_init(&single_error);
513 			add_assoc_long_ex(&single_error, "errno", sizeof("errno") - 1, message->error_no);
514 			add_assoc_string_ex(&single_error, "sqlstate", sizeof("sqlstate") - 1, message->sqlstate);
515 			add_assoc_string_ex(&single_error, "error", sizeof("error") - 1, message->error);
516 			add_next_index_zval(return_value, &single_error);
517 		}
518 	} else {
519 		RETURN_EMPTY_ARRAY();
520 	}
521 }
522 /* }}} */
523 
524 /* {{{ Fetch a result row as an object */
525 PHP_FUNCTION(mysqli_fetch_object)
526 {
527 	php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQLI_ASSOC, 1);
528 }
529 /* }}} */
530 
531 /* {{{ allows to execute multiple queries  */
532 PHP_FUNCTION(mysqli_multi_query)
533 {
534 	MY_MYSQL	*mysql;
535 	zval		*mysql_link;
536 	char		*query = NULL;
537 	size_t 		query_len;
538 
539 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_link, mysqli_link_class_entry, &query, &query_len) == FAILURE) {
540 		RETURN_THROWS();
541 	}
542 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
543 
544 	MYSQLI_ENABLE_MQ;
545 	if (mysql_real_query(mysql->mysql, query, query_len)) {
546 		MYSQLND_ERROR_INFO error_info = *mysql->mysql->data->error_info;
547 		mysql->mysql->data->error_info->error_list.head = NULL;
548 		mysql->mysql->data->error_info->error_list.tail = NULL;
549 		mysql->mysql->data->error_info->error_list.count = 0;
550 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
551 		MYSQLI_DISABLE_MQ;
552 
553 		zend_llist_clean(&mysql->mysql->data->error_info->error_list);
554 		*mysql->mysql->data->error_info = error_info;
555 		RETURN_FALSE;
556 	}
557 	RETURN_TRUE;
558 }
559 /* }}} */
560 
561 /* {{{ */
562 PHP_FUNCTION(mysqli_query)
563 {
564 	MY_MYSQL			*mysql;
565 	zval				*mysql_link;
566 	MYSQLI_RESOURCE		*mysqli_resource;
567 	MYSQL_RES 			*result = NULL;
568 	char				*query = NULL;
569 	size_t 				query_len;
570 	zend_long 				resultmode = MYSQLI_STORE_RESULT;
571 
572 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os|l", &mysql_link, mysqli_link_class_entry, &query, &query_len, &resultmode) == FAILURE) {
573 		RETURN_THROWS();
574 	}
575 
576 	if (!query_len) {
577 		zend_argument_value_error(ERROR_ARG_POS(2), "cannot be empty");
578 		RETURN_THROWS();
579 	}
580 	if ((resultmode & ~MYSQLI_ASYNC) != MYSQLI_USE_RESULT &&
581 		MYSQLI_STORE_RESULT != (resultmode & ~(MYSQLI_ASYNC | MYSQLI_STORE_RESULT_COPY_DATA))
582 	) {
583 		zend_argument_value_error(ERROR_ARG_POS(3), "must be either MYSQLI_USE_RESULT or MYSQLI_STORE_RESULT with MYSQLI_ASYNC as an optional bitmask flag");
584 		RETURN_THROWS();
585 	}
586 
587 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
588 
589 	MYSQLI_DISABLE_MQ;
590 
591 
592 	if (resultmode & MYSQLI_ASYNC) {
593 		if (mysqli_async_query(mysql->mysql, query, query_len)) {
594 			MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
595 			RETURN_FALSE;
596 		}
597 		mysql->async_result_fetch_type = resultmode & ~MYSQLI_ASYNC;
598 		RETURN_TRUE;
599 	}
600 
601 	if (mysql_real_query(mysql->mysql, query, query_len)) {
602 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
603 		RETURN_FALSE;
604 	}
605 
606 	if (!mysql_field_count(mysql->mysql)) {
607 		/* no result set - not a SELECT */
608 		if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
609 			php_mysqli_report_index(query, mysqli_server_status(mysql->mysql));
610 		}
611 		RETURN_TRUE;
612 	}
613 
614 	switch (resultmode & ~(MYSQLI_ASYNC | MYSQLI_STORE_RESULT_COPY_DATA)) {
615 		case MYSQLI_STORE_RESULT:
616 			result = mysql_store_result(mysql->mysql);
617 			break;
618 		case MYSQLI_USE_RESULT:
619 			result = mysql_use_result(mysql->mysql);
620 			break;
621 	}
622 	if (!result) {
623 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
624 		RETURN_FALSE;
625 	}
626 
627 	if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
628 		php_mysqli_report_index(query, mysqli_server_status(mysql->mysql));
629 	}
630 
631 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
632 	mysqli_resource->ptr = (void *)result;
633 	mysqli_resource->status = MYSQLI_STATUS_VALID;
634 	MYSQLI_RETVAL_RESOURCE(mysqli_resource, mysqli_result_class_entry);
635 }
636 /* }}} */
637 
638 #include "php_network.h"
639 /* {{{ mysqlnd_zval_array_to_mysqlnd_array functions */
640 static int mysqlnd_zval_array_to_mysqlnd_array(zval *in_array, MYSQLND ***out_array)
641 {
642 	zval *elem;
643 	int i = 0, current = 0;
644 
645 	if (Z_TYPE_P(in_array) != IS_ARRAY) {
646 		return SUCCESS;
647 	}
648 	*out_array = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(in_array)) + 1, sizeof(MYSQLND *));
649 	ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(in_array), elem) {
650 		i++;
651 		if (Z_TYPE_P(elem) != IS_OBJECT ||
652 			!instanceof_function(Z_OBJCE_P(elem), mysqli_link_class_entry)) {
653 			zend_argument_type_error(i, "must be an instance of mysqli, %s given", zend_zval_type_name(elem));
654 			return FAILURE;
655 		} else {
656 			MY_MYSQL *mysql;
657 			MYSQLI_RESOURCE *my_res;
658 			mysqli_object *intern = Z_MYSQLI_P(elem);
659 			if (!(my_res = (MYSQLI_RESOURCE *)intern->ptr)) {
660 				zend_throw_error(NULL, "%s object is already closed", ZSTR_VAL(intern->zo.ce->name));
661 				return FAILURE;
662 		  	}
663 			mysql = (MY_MYSQL*) my_res->ptr;
664 			if (my_res->status < MYSQLI_STATUS_VALID) {
665 				zend_throw_error(NULL, "%s object is not fully initialized", ZSTR_VAL(intern->zo.ce->name));
666 				return FAILURE;
667 			}
668 			(*out_array)[current++] = mysql->mysql;
669 		}
670 	} ZEND_HASH_FOREACH_END();
671 	return SUCCESS;
672 }
673 /* }}} */
674 
675 /* {{{ mysqlnd_zval_array_from_mysqlnd_array */
676 static int mysqlnd_zval_array_from_mysqlnd_array(MYSQLND **in_array, zval *out_array)
677 {
678 	MYSQLND **p = in_array;
679 	zval dest_array;
680 	zval *elem, *dest_elem;
681 	int ret = 0;
682 
683 	array_init_size(&dest_array, zend_hash_num_elements(Z_ARRVAL_P(out_array)));
684 
685 	ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(out_array), elem) {
686 		if (Z_TYPE_P(elem) != IS_OBJECT ||
687 				!instanceof_function(Z_OBJCE_P(elem), mysqli_link_class_entry)) {
688 			continue;
689 		}
690 		{
691 			MY_MYSQL *mysql;
692 			MYSQLI_RESOURCE *my_res;
693 			mysqli_object *intern = Z_MYSQLI_P(elem);
694 			if (!(my_res = (MYSQLI_RESOURCE *)intern->ptr)) {
695 				zend_throw_error(NULL, "%s object is already closed", ZSTR_VAL(intern->zo.ce->name));
696 				return FAILURE;
697 		  	}
698 			mysql = (MY_MYSQL *) my_res->ptr;
699 			if (mysql->mysql == *p) {
700 				dest_elem = zend_hash_next_index_insert(Z_ARRVAL(dest_array), elem);
701 				if (dest_elem) {
702 					zval_add_ref(dest_elem);
703 				}
704 				ret++;
705 				p++;
706 			}
707 		}
708 	} ZEND_HASH_FOREACH_END();
709 
710 	/* destroy old array and add new one */
711 	zval_ptr_dtor(out_array);
712 	ZVAL_COPY_VALUE(out_array, &dest_array);
713 
714 	return 0;
715 }
716 /* }}} */
717 
718 /* {{{ mysqlnd_dont_poll_zval_array_from_mysqlnd_array */
719 static int mysqlnd_dont_poll_zval_array_from_mysqlnd_array(MYSQLND **in_array, zval *in_zval_array, zval *out_array)
720 {
721 	MYSQLND **p = in_array;
722 	zval proxy, *elem, *dest_elem;
723 	int ret = 0;
724 
725 	array_init(&proxy);
726 	if (in_array) {
727 		ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(in_zval_array), elem) {
728 			MY_MYSQL *mysql;
729 			mysqli_object *intern = Z_MYSQLI_P(elem);
730 			mysql = (MY_MYSQL *)((MYSQLI_RESOURCE *)intern->ptr)->ptr;
731 			if (mysql->mysql == *p) {
732 				dest_elem = zend_hash_next_index_insert(Z_ARRVAL(proxy), elem);
733 				if (dest_elem) {
734 					zval_add_ref(dest_elem);
735 				}
736 				ret++;
737 				p++;
738 			}
739 		} ZEND_HASH_FOREACH_END();
740 	}
741 
742 	/* destroy old array and add new one */
743 	zval_ptr_dtor(out_array);
744 	ZVAL_COPY_VALUE(out_array, &proxy);
745 
746 	return 0;
747 }
748 /* }}} */
749 
750 /* {{{ Poll connections */
751 PHP_FUNCTION(mysqli_poll)
752 {
753 	zval			*r_array, *e_array, *dont_poll_array;
754 	MYSQLND			**new_r_array = NULL, **new_e_array = NULL, **new_dont_poll_array = NULL;
755 	zend_long			sec = 0, usec = 0;
756 	enum_func_status ret;
757 	int 			desc_num;
758 
759 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "a!a!al|l", &r_array, &e_array, &dont_poll_array, &sec, &usec) == FAILURE) {
760 		RETURN_THROWS();
761 	}
762 	if (sec < 0) {
763 		zend_argument_value_error(4, "must be greater than or equal to 0");
764 		RETURN_THROWS();
765 	}
766 	if (usec < 0) {
767 		zend_argument_value_error(5, "must be greater than or equal to 0");
768 		RETURN_THROWS();
769 	}
770 
771 	// TODO Error promotion
772 	if (!r_array && !e_array) {
773 		php_error_docref(NULL, E_WARNING, "No stream arrays were passed");
774 		RETURN_FALSE;
775 	}
776 
777 	if (r_array != NULL) {
778 		if (mysqlnd_zval_array_to_mysqlnd_array(r_array, &new_r_array) == FAILURE) {
779 			efree(new_r_array);
780 			RETURN_THROWS();
781 		}
782 	}
783 	if (e_array != NULL) {
784 		if (mysqlnd_zval_array_to_mysqlnd_array(e_array, &new_e_array) == FAILURE) {
785 			efree(new_e_array);
786 			efree(new_r_array);
787 			RETURN_THROWS();
788 		}
789 	}
790 
791 	ret = mysqlnd_poll(new_r_array, new_e_array, &new_dont_poll_array, sec, usec, &desc_num);
792 
793 	mysqlnd_dont_poll_zval_array_from_mysqlnd_array(r_array != NULL ? new_dont_poll_array:NULL, r_array, dont_poll_array);
794 
795 	if (r_array != NULL) {
796 		mysqlnd_zval_array_from_mysqlnd_array(new_r_array, r_array);
797 	}
798 	if (e_array != NULL) {
799 		mysqlnd_zval_array_from_mysqlnd_array(new_e_array, e_array);
800 	}
801 
802 	if (new_dont_poll_array) {
803 		efree(new_dont_poll_array);
804 	}
805 	if (new_r_array) {
806 		efree(new_r_array);
807 	}
808 	if (new_e_array) {
809 		efree(new_e_array);
810 	}
811 	if (ret == PASS) {
812 		RETURN_LONG(desc_num);
813 	} else {
814 		RETURN_FALSE;
815 	}
816 }
817 /* }}} */
818 
819 /* {{{ Poll connections */
820 PHP_FUNCTION(mysqli_reap_async_query)
821 {
822 	MY_MYSQL		*mysql;
823 	zval			*mysql_link;
824 	MYSQLI_RESOURCE		*mysqli_resource;
825 	MYSQL_RES 			*result = NULL;
826 
827 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
828 		RETURN_THROWS();
829 	}
830 
831 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
832 
833 	if (FAIL == mysqlnd_reap_async_query(mysql->mysql)) {
834 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
835 		RETURN_FALSE;
836 	}
837 
838 	if (!mysql_field_count(mysql->mysql)) {
839 		/* no result set - not a SELECT */
840 		if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
841 /*			php_mysqli_report_index("n/a", mysqli_server_status(mysql->mysql)); */
842 		}
843 		RETURN_TRUE;
844 	}
845 
846 	switch (mysql->async_result_fetch_type) {
847 		case MYSQLI_STORE_RESULT:
848 			result = mysql_store_result(mysql->mysql);
849 			break;
850 		case MYSQLI_USE_RESULT:
851 			result = mysql_use_result(mysql->mysql);
852 			break;
853 	}
854 
855 	if (!result) {
856 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
857 		RETURN_FALSE;
858 	}
859 
860 	if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
861 /*		php_mysqli_report_index("n/a", mysqli_server_status(mysql->mysql)); */
862 	}
863 
864 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
865 	mysqli_resource->ptr = (void *)result;
866 	mysqli_resource->status = MYSQLI_STATUS_VALID;
867 	MYSQLI_RETVAL_RESOURCE(mysqli_resource, mysqli_result_class_entry);
868 }
869 /* }}} */
870 
871 /* {{{ Buffer result set on client */
872 PHP_FUNCTION(mysqli_stmt_get_result)
873 {
874 	MYSQL_RES 		*result;
875 	MYSQLI_RESOURCE	*mysqli_resource;
876 	MY_STMT			*stmt;
877 	zval 			*mysql_stmt;
878 
879 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
880 		RETURN_THROWS();
881 	}
882 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
883 
884 	if (!(result = mysqlnd_stmt_get_result(stmt->stmt))) {
885 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
886 		RETURN_FALSE;
887 	}
888 
889 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
890 	mysqli_resource->ptr = (void *)result;
891 	mysqli_resource->status = MYSQLI_STATUS_VALID;
892 	MYSQLI_RETVAL_RESOURCE(mysqli_resource, mysqli_result_class_entry);
893 }
894 /* }}} */
895 
896 /* {{{ */
897 PHP_FUNCTION(mysqli_get_warnings)
898 {
899 	MY_MYSQL			*mysql;
900 	zval				*mysql_link;
901 	MYSQLI_RESOURCE		*mysqli_resource;
902 	MYSQLI_WARNING		*w = NULL;
903 
904 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
905 		RETURN_THROWS();
906 	}
907 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
908 
909 	if (mysql_warning_count(mysql->mysql)) {
910 		w = php_get_warnings(mysql->mysql->data);
911 	}
912 	if (!w) {
913 		RETURN_FALSE;
914 	}
915 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
916 	mysqli_resource->ptr = mysqli_resource->info = (void *)w;
917 	mysqli_resource->status = MYSQLI_STATUS_VALID;
918 	MYSQLI_RETVAL_RESOURCE(mysqli_resource, mysqli_warning_class_entry);
919 }
920 /* }}} */
921 
922 /* {{{ */
923 PHP_FUNCTION(mysqli_stmt_get_warnings)
924 {
925 	MY_STMT				*stmt;
926 	zval				*stmt_link;
927 	MYSQLI_RESOURCE		*mysqli_resource;
928 	MYSQLI_WARNING		*w = NULL;
929 
930 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &stmt_link, mysqli_stmt_class_entry) == FAILURE) {
931 		RETURN_THROWS();
932 	}
933 	MYSQLI_FETCH_RESOURCE_STMT(stmt, stmt_link, MYSQLI_STATUS_VALID);
934 
935 	if (mysqli_stmt_warning_count(stmt->stmt)) {
936 		w = php_get_warnings(mysqli_stmt_get_connection(stmt->stmt));
937 	}
938 	if (!w) {
939 		RETURN_FALSE;
940 	}
941 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
942 	mysqli_resource->ptr = mysqli_resource->info = (void *)w;
943 	mysqli_resource->status = MYSQLI_STATUS_VALID;
944 	MYSQLI_RETVAL_RESOURCE(mysqli_resource, mysqli_warning_class_entry);
945 }
946 /* }}} */
947 
948 /* {{{ sets client character set */
949 PHP_FUNCTION(mysqli_set_charset)
950 {
951 	MY_MYSQL	*mysql;
952 	zval		*mysql_link;
953 	char		*cs_name;
954 	size_t		csname_len;
955 
956 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_link, mysqli_link_class_entry, &cs_name, &csname_len) == FAILURE) {
957 		RETURN_THROWS();
958 	}
959 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
960 
961 	if (mysql_set_character_set(mysql->mysql, cs_name)) {
962 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
963 		RETURN_FALSE;
964 	}
965 	RETURN_TRUE;
966 }
967 /* }}} */
968 
969 /* {{{ returns a character set object */
970 PHP_FUNCTION(mysqli_get_charset)
971 {
972 	MY_MYSQL				*mysql;
973 	zval					*mysql_link;
974 	const char 				*name = NULL, *collation = NULL, *dir = NULL, *comment = NULL;
975 	uint32_t				minlength, maxlength, number, state;
976 	const MYSQLND_CHARSET	*cs;
977 
978 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
979 		RETURN_THROWS();
980 	}
981 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
982 
983 
984 	cs = mysql->mysql->data->charset;
985 	if (!cs) {
986 		php_error_docref(NULL, E_WARNING, "The connection has no charset associated");
987 		RETURN_NULL();
988 	}
989 	name = cs->name;
990 	collation = cs->collation;
991 	minlength = cs->char_minlen;
992 	maxlength = cs->char_maxlen;
993 	number = cs->nr;
994 	comment = cs->comment;
995 	state = 1;	/* all charsets are compiled in */
996 	object_init(return_value);
997 
998 	add_property_string(return_value, "charset", (name) ? (char *)name : "");
999 	add_property_string(return_value, "collation",(collation) ? (char *)collation : "");
1000 	add_property_string(return_value, "dir", (dir) ? (char *)dir : "");
1001 	add_property_long(return_value, "min_length", minlength);
1002 	add_property_long(return_value, "max_length", maxlength);
1003 	add_property_long(return_value, "number", number);
1004 	add_property_long(return_value, "state", state);
1005 	add_property_string(return_value, "comment", (comment) ? (char *)comment : "");
1006 }
1007 /* }}} */
1008 
1009 /* {{{ Starts a transaction */
1010 PHP_FUNCTION(mysqli_begin_transaction)
1011 {
1012 	MY_MYSQL	*mysql;
1013 	zval		*mysql_link;
1014 	zend_long		flags = TRANS_START_NO_OPT;
1015 	char *		name = NULL;
1016 	size_t			name_len = 0;
1017 
1018 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|ls!", &mysql_link, mysqli_link_class_entry, &flags, &name, &name_len) == FAILURE) {
1019 		RETURN_THROWS();
1020 	}
1021 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1022 	if (flags < 0) {
1023 		zend_argument_value_error(ERROR_ARG_POS(2), "must be one of the MYSQLI_TRANS_* constants");
1024 		RETURN_THROWS();
1025 	}
1026 	if (name && !name_len) {
1027 		zend_argument_value_error(ERROR_ARG_POS(3), "cannot be empty");
1028 		RETURN_THROWS();
1029 	}
1030 
1031 	if (FAIL == mysqlnd_begin_transaction(mysql->mysql, flags, name)) {
1032 		RETURN_FALSE;
1033 	}
1034 	RETURN_TRUE;
1035 }
1036 /* }}} */
1037 
1038 /* {{{ Starts a transaction */
1039 PHP_FUNCTION(mysqli_savepoint)
1040 {
1041 	MY_MYSQL	*mysql;
1042 	zval		*mysql_link;
1043 	char *		name = NULL;
1044 	size_t			name_len;
1045 
1046 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_link, mysqli_link_class_entry, &name, &name_len) == FAILURE) {
1047 		RETURN_THROWS();
1048 	}
1049 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1050 	if (name_len == 0) {
1051 		zend_argument_value_error(ERROR_ARG_POS(2), "cannot be empty");
1052 		RETURN_THROWS();
1053 	}
1054 
1055 	if (FAIL == mysqlnd_savepoint(mysql->mysql, name)) {
1056 		RETURN_FALSE;
1057 	}
1058 	RETURN_TRUE;
1059 }
1060 /* }}} */
1061 
1062 /* {{{ Starts a transaction */
1063 PHP_FUNCTION(mysqli_release_savepoint)
1064 {
1065 	MY_MYSQL	*mysql;
1066 	zval		*mysql_link;
1067 	char *		name = NULL;
1068 	size_t			name_len;
1069 
1070 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_link, mysqli_link_class_entry, &name, &name_len) == FAILURE) {
1071 		RETURN_THROWS();
1072 	}
1073 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1074 	if (name_len == 0) {
1075 		zend_argument_value_error(ERROR_ARG_POS(2), "cannot be empty");
1076 		RETURN_THROWS();
1077 	}
1078 	if (FAIL == mysqlnd_release_savepoint(mysql->mysql, name)) {
1079 		RETURN_FALSE;
1080 	}
1081 	RETURN_TRUE;
1082 }
1083 /* }}} */
1084 
1085 /* {{{ Returns information about open and cached links */
1086 PHP_FUNCTION(mysqli_get_links_stats)
1087 {
1088 	if (zend_parse_parameters_none() == FAILURE) {
1089 		RETURN_THROWS();
1090 	}
1091 
1092 	array_init(return_value);
1093 	add_assoc_long_ex(return_value, "total", sizeof("total") - 1, MyG(num_links));
1094 	add_assoc_long_ex(return_value, "active_plinks", sizeof("active_plinks") - 1, MyG(num_active_persistent));
1095 	add_assoc_long_ex(return_value, "cached_plinks", sizeof("cached_plinks") - 1, MyG(num_inactive_persistent));
1096 }
1097 /* }}} */
1098