xref: /php-src/ext/mysqli/mysqli_nonapi.c (revision fd73681c)
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) (hasThis() ? (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_value_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 zend_result 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 
682 	array_init_size(&dest_array, zend_hash_num_elements(Z_ARRVAL_P(out_array)));
683 
684 	ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(out_array), elem) {
685 		if (Z_TYPE_P(elem) != IS_OBJECT ||
686 				!instanceof_function(Z_OBJCE_P(elem), mysqli_link_class_entry)) {
687 			continue;
688 		}
689 		{
690 			MY_MYSQL *mysql;
691 			MYSQLI_RESOURCE *my_res;
692 			mysqli_object *intern = Z_MYSQLI_P(elem);
693 			if (!(my_res = (MYSQLI_RESOURCE *)intern->ptr)) {
694 				zend_throw_error(NULL, "%s object is already closed", ZSTR_VAL(intern->zo.ce->name));
695 				return FAILURE;
696 		  	}
697 			mysql = (MY_MYSQL *) my_res->ptr;
698 			if (mysql->mysql == *p) {
699 				dest_elem = zend_hash_next_index_insert(Z_ARRVAL(dest_array), elem);
700 				if (dest_elem) {
701 					zval_add_ref(dest_elem);
702 				}
703 				p++;
704 			}
705 		}
706 	} ZEND_HASH_FOREACH_END();
707 
708 	/* destroy old array and add new one */
709 	zval_ptr_dtor(out_array);
710 	ZVAL_COPY_VALUE(out_array, &dest_array);
711 
712 	return SUCCESS;
713 }
714 /* }}} */
715 
716 /* {{{ mysqlnd_dont_poll_zval_array_from_mysqlnd_array */
717 static void mysqlnd_dont_poll_zval_array_from_mysqlnd_array(MYSQLND **in_array, zval *in_zval_array, zval *out_array)
718 {
719 	MYSQLND **p = in_array;
720 	zval proxy, *elem, *dest_elem;
721 
722 	array_init(&proxy);
723 	if (in_array) {
724 		ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(in_zval_array), elem) {
725 			MY_MYSQL *mysql;
726 			mysqli_object *intern = Z_MYSQLI_P(elem);
727 			mysql = (MY_MYSQL *)((MYSQLI_RESOURCE *)intern->ptr)->ptr;
728 			if (mysql->mysql == *p) {
729 				dest_elem = zend_hash_next_index_insert(Z_ARRVAL(proxy), elem);
730 				if (dest_elem) {
731 					zval_add_ref(dest_elem);
732 				}
733 				p++;
734 			}
735 		} ZEND_HASH_FOREACH_END();
736 	}
737 
738 	/* destroy old array and add new one */
739 	zval_ptr_dtor(out_array);
740 	ZVAL_COPY_VALUE(out_array, &proxy);
741 }
742 /* }}} */
743 
744 /* {{{ Poll connections */
745 PHP_FUNCTION(mysqli_poll)
746 {
747 	zval			*r_array, *e_array, *dont_poll_array;
748 	MYSQLND			**new_r_array = NULL, **new_e_array = NULL, **new_dont_poll_array = NULL;
749 	zend_long			sec = 0, usec = 0;
750 	enum_func_status ret;
751 	int 			desc_num;
752 
753 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "a!a!al|l", &r_array, &e_array, &dont_poll_array, &sec, &usec) == FAILURE) {
754 		RETURN_THROWS();
755 	}
756 	if (sec < 0) {
757 		zend_argument_value_error(4, "must be greater than or equal to 0");
758 		RETURN_THROWS();
759 	}
760 	if (usec < 0) {
761 		zend_argument_value_error(5, "must be greater than or equal to 0");
762 		RETURN_THROWS();
763 	}
764 
765 	if (!r_array && !e_array) {
766 		zend_value_error("No stream arrays were passed");
767 		RETURN_THROWS();
768 	}
769 
770 	if (r_array != NULL) {
771 		if (mysqlnd_zval_array_to_mysqlnd_array(r_array, &new_r_array) == FAILURE) {
772 			efree(new_r_array);
773 			RETURN_THROWS();
774 		}
775 	}
776 	if (e_array != NULL) {
777 		if (mysqlnd_zval_array_to_mysqlnd_array(e_array, &new_e_array) == FAILURE) {
778 			efree(new_e_array);
779 			efree(new_r_array);
780 			RETURN_THROWS();
781 		}
782 	}
783 
784 	ret = mysqlnd_poll(new_r_array, new_e_array, &new_dont_poll_array, sec, usec, &desc_num);
785 
786 	mysqlnd_dont_poll_zval_array_from_mysqlnd_array(r_array != NULL ? new_dont_poll_array:NULL, r_array, dont_poll_array);
787 
788 	if (r_array != NULL) {
789 		mysqlnd_zval_array_from_mysqlnd_array(new_r_array, r_array);
790 	}
791 	if (e_array != NULL) {
792 		mysqlnd_zval_array_from_mysqlnd_array(new_e_array, e_array);
793 	}
794 
795 	if (new_dont_poll_array) {
796 		efree(new_dont_poll_array);
797 	}
798 	if (new_r_array) {
799 		efree(new_r_array);
800 	}
801 	if (new_e_array) {
802 		efree(new_e_array);
803 	}
804 	if (ret == PASS) {
805 		RETURN_LONG(desc_num);
806 	} else {
807 		RETURN_FALSE;
808 	}
809 }
810 /* }}} */
811 
812 /* {{{ Poll connections */
813 PHP_FUNCTION(mysqli_reap_async_query)
814 {
815 	MY_MYSQL		*mysql;
816 	zval			*mysql_link;
817 	MYSQLI_RESOURCE		*mysqli_resource;
818 	MYSQL_RES 			*result = NULL;
819 
820 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
821 		RETURN_THROWS();
822 	}
823 
824 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
825 
826 	if (FAIL == mysqlnd_reap_async_query(mysql->mysql)) {
827 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
828 		RETURN_FALSE;
829 	}
830 
831 	if (!mysql_field_count(mysql->mysql)) {
832 		/* no result set - not a SELECT */
833 		if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
834 /*			php_mysqli_report_index("n/a", mysqli_server_status(mysql->mysql)); */
835 		}
836 		RETURN_TRUE;
837 	}
838 
839 	switch (mysql->async_result_fetch_type) {
840 		case MYSQLI_STORE_RESULT:
841 			result = mysql_store_result(mysql->mysql);
842 			break;
843 		case MYSQLI_USE_RESULT:
844 			result = mysql_use_result(mysql->mysql);
845 			break;
846 	}
847 
848 	if (!result) {
849 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
850 		RETURN_FALSE;
851 	}
852 
853 	if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
854 /*		php_mysqli_report_index("n/a", mysqli_server_status(mysql->mysql)); */
855 	}
856 
857 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
858 	mysqli_resource->ptr = (void *)result;
859 	mysqli_resource->status = MYSQLI_STATUS_VALID;
860 	MYSQLI_RETVAL_RESOURCE(mysqli_resource, mysqli_result_class_entry);
861 }
862 /* }}} */
863 
864 /* {{{ Buffer result set on client */
865 PHP_FUNCTION(mysqli_stmt_get_result)
866 {
867 	MYSQL_RES 		*result;
868 	MYSQLI_RESOURCE	*mysqli_resource;
869 	MY_STMT			*stmt;
870 	zval 			*mysql_stmt;
871 
872 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
873 		RETURN_THROWS();
874 	}
875 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
876 
877 	if (!(result = mysqlnd_stmt_get_result(stmt->stmt))) {
878 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
879 		RETURN_FALSE;
880 	}
881 
882 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
883 	mysqli_resource->ptr = (void *)result;
884 	mysqli_resource->status = MYSQLI_STATUS_VALID;
885 	MYSQLI_RETVAL_RESOURCE(mysqli_resource, mysqli_result_class_entry);
886 }
887 /* }}} */
888 
889 /* {{{ */
890 PHP_FUNCTION(mysqli_get_warnings)
891 {
892 	MY_MYSQL			*mysql;
893 	zval				*mysql_link;
894 	MYSQLI_RESOURCE		*mysqli_resource;
895 	MYSQLI_WARNING		*w = NULL;
896 
897 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
898 		RETURN_THROWS();
899 	}
900 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
901 
902 	if (mysql_warning_count(mysql->mysql)) {
903 		w = php_get_warnings(mysql->mysql->data);
904 	}
905 	if (!w) {
906 		RETURN_FALSE;
907 	}
908 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
909 	mysqli_resource->ptr = mysqli_resource->info = (void *)w;
910 	mysqli_resource->status = MYSQLI_STATUS_VALID;
911 	MYSQLI_RETVAL_RESOURCE(mysqli_resource, mysqli_warning_class_entry);
912 }
913 /* }}} */
914 
915 /* {{{ */
916 PHP_FUNCTION(mysqli_stmt_get_warnings)
917 {
918 	MY_STMT				*stmt;
919 	zval				*stmt_link;
920 	MYSQLI_RESOURCE		*mysqli_resource;
921 	MYSQLI_WARNING		*w = NULL;
922 
923 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &stmt_link, mysqli_stmt_class_entry) == FAILURE) {
924 		RETURN_THROWS();
925 	}
926 	MYSQLI_FETCH_RESOURCE_STMT(stmt, stmt_link, MYSQLI_STATUS_VALID);
927 
928 	if (mysqli_stmt_warning_count(stmt->stmt)) {
929 		w = php_get_warnings(mysqli_stmt_get_connection(stmt->stmt));
930 	}
931 	if (!w) {
932 		RETURN_FALSE;
933 	}
934 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
935 	mysqli_resource->ptr = mysqli_resource->info = (void *)w;
936 	mysqli_resource->status = MYSQLI_STATUS_VALID;
937 	MYSQLI_RETVAL_RESOURCE(mysqli_resource, mysqli_warning_class_entry);
938 }
939 /* }}} */
940 
941 /* {{{ sets client character set */
942 PHP_FUNCTION(mysqli_set_charset)
943 {
944 	MY_MYSQL	*mysql;
945 	zval		*mysql_link;
946 	char		*cs_name;
947 	size_t		csname_len;
948 
949 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_link, mysqli_link_class_entry, &cs_name, &csname_len) == FAILURE) {
950 		RETURN_THROWS();
951 	}
952 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
953 
954 	if (mysql_set_character_set(mysql->mysql, cs_name)) {
955 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
956 		RETURN_FALSE;
957 	}
958 	RETURN_TRUE;
959 }
960 /* }}} */
961 
962 /* {{{ returns a character set object */
963 PHP_FUNCTION(mysqli_get_charset)
964 {
965 	MY_MYSQL				*mysql;
966 	zval					*mysql_link;
967 	const char 				*name = NULL, *collation = NULL, *dir = NULL, *comment = NULL;
968 	uint32_t				minlength, maxlength, number, state;
969 	const MYSQLND_CHARSET	*cs;
970 
971 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
972 		RETURN_THROWS();
973 	}
974 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
975 
976 
977 	cs = mysql->mysql->data->charset;
978 	if (!cs) {
979 		php_error_docref(NULL, E_WARNING, "The connection has no charset associated");
980 		RETURN_NULL();
981 	}
982 	name = cs->name;
983 	collation = cs->collation;
984 	minlength = cs->char_minlen;
985 	maxlength = cs->char_maxlen;
986 	number = cs->nr;
987 	comment = cs->comment;
988 	state = 1;	/* all charsets are compiled in */
989 	object_init(return_value);
990 
991 	add_property_string(return_value, "charset", (name) ? (char *)name : "");
992 	add_property_string(return_value, "collation",(collation) ? (char *)collation : "");
993 	add_property_string(return_value, "dir", (dir) ? (char *)dir : "");
994 	add_property_long(return_value, "min_length", minlength);
995 	add_property_long(return_value, "max_length", maxlength);
996 	add_property_long(return_value, "number", number);
997 	add_property_long(return_value, "state", state);
998 	add_property_string(return_value, "comment", (comment) ? (char *)comment : "");
999 }
1000 /* }}} */
1001 
1002 /* {{{ Starts a transaction */
1003 PHP_FUNCTION(mysqli_begin_transaction)
1004 {
1005 	MY_MYSQL	*mysql;
1006 	zval		*mysql_link;
1007 	zend_long		flags = TRANS_START_NO_OPT;
1008 	char *		name = NULL;
1009 	size_t			name_len = 0;
1010 
1011 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|ls!", &mysql_link, mysqli_link_class_entry, &flags, &name, &name_len) == FAILURE) {
1012 		RETURN_THROWS();
1013 	}
1014 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1015 	if (flags < 0) {
1016 		zend_argument_value_error(ERROR_ARG_POS(2), "must be one of the MYSQLI_TRANS_* constants");
1017 		RETURN_THROWS();
1018 	}
1019 	if (name && !name_len) {
1020 		zend_argument_value_error(ERROR_ARG_POS(3), "cannot be empty");
1021 		RETURN_THROWS();
1022 	}
1023 
1024 	if (FAIL == mysqlnd_begin_transaction(mysql->mysql, flags, name)) {
1025 		RETURN_FALSE;
1026 	}
1027 	RETURN_TRUE;
1028 }
1029 /* }}} */
1030 
1031 /* {{{ Starts a transaction */
1032 PHP_FUNCTION(mysqli_savepoint)
1033 {
1034 	MY_MYSQL	*mysql;
1035 	zval		*mysql_link;
1036 	char *		name = NULL;
1037 	size_t			name_len;
1038 
1039 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_link, mysqli_link_class_entry, &name, &name_len) == FAILURE) {
1040 		RETURN_THROWS();
1041 	}
1042 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1043 	if (name_len == 0) {
1044 		zend_argument_value_error(ERROR_ARG_POS(2), "cannot be empty");
1045 		RETURN_THROWS();
1046 	}
1047 
1048 	if (FAIL == mysqlnd_savepoint(mysql->mysql, name)) {
1049 		RETURN_FALSE;
1050 	}
1051 	RETURN_TRUE;
1052 }
1053 /* }}} */
1054 
1055 /* {{{ Starts a transaction */
1056 PHP_FUNCTION(mysqli_release_savepoint)
1057 {
1058 	MY_MYSQL	*mysql;
1059 	zval		*mysql_link;
1060 	char *		name = NULL;
1061 	size_t			name_len;
1062 
1063 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_link, mysqli_link_class_entry, &name, &name_len) == FAILURE) {
1064 		RETURN_THROWS();
1065 	}
1066 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1067 	if (name_len == 0) {
1068 		zend_argument_value_error(ERROR_ARG_POS(2), "cannot be empty");
1069 		RETURN_THROWS();
1070 	}
1071 	if (FAIL == mysqlnd_release_savepoint(mysql->mysql, name)) {
1072 		RETURN_FALSE;
1073 	}
1074 	RETURN_TRUE;
1075 }
1076 /* }}} */
1077 
1078 /* {{{ Returns information about open and cached links */
1079 PHP_FUNCTION(mysqli_get_links_stats)
1080 {
1081 	if (zend_parse_parameters_none() == FAILURE) {
1082 		RETURN_THROWS();
1083 	}
1084 
1085 	array_init(return_value);
1086 	add_assoc_long_ex(return_value, "total", sizeof("total") - 1, MyG(num_links));
1087 	add_assoc_long_ex(return_value, "active_plinks", sizeof("active_plinks") - 1, MyG(num_active_persistent));
1088 	add_assoc_long_ex(return_value, "cached_plinks", sizeof("cached_plinks") - 1, MyG(num_inactive_persistent));
1089 }
1090 /* }}} */
1091