xref: /PHP-5.3/ext/mysqli/mysqli_nonapi.c (revision a2045ff3)
1 /*
2   +----------------------------------------------------------------------+
3   | PHP Version 5                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2013 The PHP Group                                |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 3.01 of the PHP license,      |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available through the world-wide-web at the following url:           |
10   | http://www.php.net/license/3_01.txt                                  |
11   | If you did not receive a copy of the PHP license and are unable to   |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@php.net so we can mail you a copy immediately.               |
14   +----------------------------------------------------------------------+
15   | Authors: Georg Richter <georg@php.net>                               |
16   |          Andrey Hristov <andrey@php.net>                             |
17   |          Ulf Wendel <uw@php.net>                                     |
18   +----------------------------------------------------------------------+
19 
20   $Id$
21 */
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #include <signal.h>
28 
29 #include "php.h"
30 #include "php_ini.h"
31 #include "ext/standard/info.h"
32 #include "php_mysqli_structs.h"
33 #include "mysqli_priv.h"
34 
35 #define SAFE_STR(a) ((a)?a:"")
36 
37 #ifndef zend_parse_parameters_none
38 #define zend_parse_parameters_none()	\
39         zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "")
40 #endif
41 
42 /* {{{ php_mysqli_set_error
43  */
php_mysqli_set_error(long mysql_errno,char * mysql_err TSRMLS_DC)44 static void php_mysqli_set_error(long mysql_errno, char *mysql_err TSRMLS_DC)
45 {
46 	MyG(error_no) = mysql_errno;
47 	if (MyG(error_msg)) {
48 		efree(MyG(error_msg));
49 	}
50 	if(mysql_err && *mysql_err) {
51 		MyG(error_msg) = estrdup(mysql_err);
52 	} else {
53 		MyG(error_msg) = NULL;
54 	}
55 }
56 /* }}} */
57 
58 
mysqli_common_connect(INTERNAL_FUNCTION_PARAMETERS,zend_bool is_real_connect,zend_bool in_ctor)59 void mysqli_common_connect(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_real_connect, zend_bool in_ctor)
60 {
61 	MY_MYSQL			*mysql = NULL;
62 	MYSQLI_RESOURCE		*mysqli_resource = NULL;
63 	zval				*object = getThis();
64 	char				*hostname = NULL, *username=NULL, *passwd=NULL, *dbname=NULL, *socket=NULL;
65 	int					hostname_len = 0, username_len = 0, passwd_len = 0, dbname_len = 0, socket_len = 0;
66 	zend_bool			persistent = FALSE;
67 	long				port = 0, flags = 0;
68 	uint				hash_len;
69 	char				*hash_key = NULL;
70 	zend_bool			new_connection = FALSE;
71 	zend_rsrc_list_entry	*le;
72 	mysqli_plist_entry *plist = NULL;
73 	zend_bool			self_alloced = 0;
74 
75 
76 #if !defined(MYSQL_USE_MYSQLND)
77 	if ((MYSQL_VERSION_ID / 100) != (mysql_get_client_version() / 100)) {
78 		php_error_docref(NULL TSRMLS_CC, E_WARNING,
79 						"Headers and client library minor version mismatch. Headers:%d Library:%ld",
80 						MYSQL_VERSION_ID, mysql_get_client_version());
81 	}
82 #endif
83 
84 	if (getThis() && !ZEND_NUM_ARGS() && in_ctor) {
85 		php_mysqli_init(INTERNAL_FUNCTION_PARAM_PASSTHRU);
86 		return;
87 	}
88 	hostname = username = dbname = passwd = socket = NULL;
89 
90 	if (!is_real_connect) {
91 		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ssssls", &hostname, &hostname_len, &username, &username_len,
92 									&passwd, &passwd_len, &dbname, &dbname_len, &port, &socket, &socket_len) == FAILURE) {
93 			return;
94 		}
95 
96 		if (object && instanceof_function(Z_OBJCE_P(object), mysqli_link_class_entry TSRMLS_CC)) {
97 			mysqli_resource = ((mysqli_object *) zend_object_store_get_object(object TSRMLS_CC))->ptr;
98 			if (mysqli_resource && mysqli_resource->ptr) {
99 				mysql = (MY_MYSQL*) mysqli_resource->ptr;
100 			}
101 		}
102 		if (!mysql) {
103 			mysql = (MY_MYSQL *) ecalloc(1, sizeof(MY_MYSQL));
104 			self_alloced = 1;
105 		}
106 		flags |= CLIENT_MULTI_RESULTS; /* needed for mysql_multi_query() */
107 	} else {
108 		/* We have flags too */
109 		if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O|sssslsl", &object, mysqli_link_class_entry,
110 										&hostname, &hostname_len, &username, &username_len, &passwd, &passwd_len, &dbname, &dbname_len, &port, &socket, &socket_len,
111 										&flags) == FAILURE) {
112 			return;
113 		}
114 
115 		mysqli_resource = ((mysqli_object *) zend_object_store_get_object(object TSRMLS_CC))->ptr;
116 		MYSQLI_FETCH_RESOURCE_CONN(mysql, &object, MYSQLI_STATUS_INITIALIZED);
117 
118 		/* set some required options */
119 		flags |= CLIENT_MULTI_RESULTS; /* needed for mysql_multi_query() */
120 		/* remove some insecure options */
121 		flags &= ~CLIENT_MULTI_STATEMENTS;   /* don't allow multi_queries via connect parameter */
122 		if (PG(open_basedir) && PG(open_basedir)[0] != '\0') {
123 			flags &= ~CLIENT_LOCAL_FILES;
124 		}
125 	}
126 
127 	if (!socket_len || !socket) {
128 		socket = MyG(default_socket);
129 	}
130 	if (!port){
131 		port = MyG(default_port);
132 	}
133 	if (!passwd) {
134 		passwd = MyG(default_pw);
135 		passwd_len = strlen(SAFE_STR(passwd));
136 	}
137 	if (!username){
138 		username = MyG(default_user);
139 	}
140 	if (!hostname || !hostname_len) {
141 		hostname = MyG(default_host);
142 	}
143 
144 	if (mysql->mysql && mysqli_resource &&
145 		(mysqli_resource->status > MYSQLI_STATUS_INITIALIZED))
146 	{
147 		/* already connected, we should close the connection */
148 		php_mysqli_close(mysql, MYSQLI_CLOSE_IMPLICIT, mysqli_resource->status TSRMLS_CC);
149 	}
150 
151 	if (strlen(SAFE_STR(hostname)) > 2 && !strncasecmp(hostname, "p:", 2)) {
152 		hostname += 2;
153 		if (!MyG(allow_persistent)) {
154 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Persistent connections are disabled. Downgrading to normal");
155 		} else {
156 			mysql->persistent = persistent = TRUE;
157 
158 			hash_len = spprintf(&hash_key, 0, "mysqli_%s_%s%ld%s%s%s", SAFE_STR(hostname), SAFE_STR(socket),
159 								port, SAFE_STR(username), SAFE_STR(dbname),
160 								SAFE_STR(passwd));
161 
162 			mysql->hash_key = hash_key;
163 
164 			/* check if we can reuse exisiting connection ... */
165 			if (zend_hash_find(&EG(persistent_list), hash_key, hash_len + 1, (void **)&le) == SUCCESS) {
166 				if (Z_TYPE_P(le) == php_le_pmysqli()) {
167 					plist = (mysqli_plist_entry *) le->ptr;
168 
169 					do {
170 						if (zend_ptr_stack_num_elements(&plist->free_links)) {
171 							mysql->mysql = zend_ptr_stack_pop(&plist->free_links);
172 
173 							MyG(num_inactive_persistent)--;
174 							/* reset variables */
175 
176 #ifndef MYSQLI_NO_CHANGE_USER_ON_PCONNECT
177 							if (!mysqli_change_user_silent(mysql->mysql, username, passwd, dbname)) {
178 #else
179 							if (!mysql_ping(mysql->mysql)) {
180 #endif
181 #ifdef MYSQLI_USE_MYSQLND
182 								mysqlnd_restart_psession(mysql->mysql);
183 #endif
184 								MyG(num_active_persistent)++;
185 								goto end;
186 							} else {
187 								mysqli_close(mysql->mysql, MYSQLI_CLOSE_IMPLICIT);
188 								mysql->mysql = NULL;
189 							}
190 						}
191 					} while (0);
192 				}
193 			} else {
194 				zend_rsrc_list_entry le;
195 				le.type = php_le_pmysqli();
196 				le.ptr = plist = calloc(1, sizeof(mysqli_plist_entry));
197 
198 				zend_ptr_stack_init_ex(&plist->free_links, 1);
199 				zend_hash_update(&EG(persistent_list), hash_key, hash_len + 1, (void *)&le, sizeof(le), NULL);
200 			}
201 		}
202 	}
203 	if (MyG(max_links) != -1 && MyG(num_links) >= MyG(max_links)) {
204 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too many open links (%ld)", MyG(num_links));
205 		goto err;
206 	}
207 
208 	if (persistent && MyG(max_persistent) != -1 &&
209 		(MyG(num_active_persistent) + MyG(num_inactive_persistent))>= MyG(max_persistent))
210 	{
211 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too many open persistent links (%ld)",
212 								MyG(num_active_persistent) + MyG(num_inactive_persistent));
213 		goto err;
214 	}
215 	if (!mysql->mysql) {
216 #if !defined(MYSQLI_USE_MYSQLND)
217 		if (!(mysql->mysql = mysql_init(NULL))) {
218 #else
219 		if (!(mysql->mysql = mysqlnd_init(persistent))) {
220 #endif
221 			goto err;
222 		}
223 		new_connection = TRUE;
224 	}
225 
226 #ifdef HAVE_EMBEDDED_MYSQLI
227 	if (hostname_len) {
228 		unsigned int external=1;
229 		mysql_options(mysql->mysql, MYSQL_OPT_USE_REMOTE_CONNECTION, (char *)&external);
230 	} else {
231 		mysql_options(mysql->mysql, MYSQL_OPT_USE_EMBEDDED_CONNECTION, 0);
232 	}
233 #endif
234 
235 #if !defined(MYSQLI_USE_MYSQLND)
236 	/* BC for prior to bug fix #53425 */
237 	flags |= CLIENT_MULTI_RESULTS;
238 
239 	if (mysql_real_connect(mysql->mysql, hostname, username, passwd, dbname, port, socket, flags) == NULL)
240 #else
241 	if (mysqlnd_connect(mysql->mysql, hostname, username, passwd, passwd_len, dbname, dbname_len,
242 						port, socket, flags TSRMLS_CC) == NULL)
243 #endif
244 	{
245 		/* Save error messages - for mysqli_connect_error() & mysqli_connect_errno() */
246 		php_mysqli_set_error(mysql_errno(mysql->mysql), (char *) mysql_error(mysql->mysql) TSRMLS_CC);
247 		php_mysqli_throw_sql_exception((char *)mysql_sqlstate(mysql->mysql), mysql_errno(mysql->mysql) TSRMLS_CC,
248 										"%s", mysql_error(mysql->mysql));
249 		if (!is_real_connect) {
250 			/* free mysql structure */
251 			mysqli_close(mysql->mysql, MYSQLI_CLOSE_DISCONNECTED);
252 			mysql->mysql = NULL;
253 		}
254 		goto err;
255 	}
256 
257 	/* clear error */
258 	php_mysqli_set_error(mysql_errno(mysql->mysql), (char *) mysql_error(mysql->mysql) TSRMLS_CC);
259 
260 #if !defined(MYSQLI_USE_MYSQLND)
261 	mysql->mysql->reconnect = MyG(reconnect);
262 
263 	/* set our own local_infile handler */
264 	php_set_local_infile_handler_default(mysql);
265 #endif
266 
267 	mysql_options(mysql->mysql, MYSQL_OPT_LOCAL_INFILE, (char *)&MyG(allow_local_infile));
268 
269 end:
270 	if (!mysqli_resource) {
271 		mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
272 		mysqli_resource->ptr = (void *)mysql;
273 	}
274 	mysqli_resource->status = MYSQLI_STATUS_VALID;
275 
276 	/* store persistent connection */
277 	if (persistent && (new_connection || is_real_connect)) {
278 		MyG(num_active_persistent)++;
279 	}
280 
281 	MyG(num_links)++;
282 
283 	mysql->multi_query = 0;
284 
285 	if (!object || !instanceof_function(Z_OBJCE_P(object), mysqli_link_class_entry TSRMLS_CC)) {
286 		MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_link_class_entry);
287 	} else {
288 		((mysqli_object *) zend_object_store_get_object(object TSRMLS_CC))->ptr = mysqli_resource;
289 	}
290 	if (!is_real_connect) {
291 		return;
292 	} else {
293 		RETURN_TRUE;
294 	}
295 
296 err:
297 	if (mysql->hash_key) {
298 		efree(mysql->hash_key);
299 		mysql->hash_key = NULL;
300 		mysql->persistent = FALSE;
301 	}
302 	if (!is_real_connect && self_alloced) {
303 		efree(mysql);
304 	}
305 	RETVAL_FALSE;
306 }
307 
308 
309 /* {{{ proto object mysqli_connect([string hostname [,string username [,string passwd [,string dbname [,int port [,string socket]]]]]])
310    Open a connection to a mysql server */
311 PHP_FUNCTION(mysqli_connect)
312 {
313 	mysqli_common_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, FALSE, FALSE);
314 }
315 /* }}} */
316 
317 
318 /* {{{ proto object mysqli_link_construct()
319   */
320 PHP_FUNCTION(mysqli_link_construct)
321 {
322 	mysqli_common_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, FALSE, TRUE);
323 }
324 /* }}} */
325 
326 
327 /* {{{ proto int mysqli_connect_errno(void)
328    Returns the numerical value of the error message from last connect command */
329 PHP_FUNCTION(mysqli_connect_errno)
330 {
331 	RETURN_LONG(MyG(error_no));
332 }
333 /* }}} */
334 
335 /* {{{ proto string mysqli_connect_error(void)
336    Returns the text of the error message from previous MySQL operation */
337 PHP_FUNCTION(mysqli_connect_error)
338 {
339 	if (MyG(error_msg)) {
340 		RETURN_STRING(MyG(error_msg),1);
341 	} else {
342 		RETURN_NULL();
343 	}
344 }
345 /* }}} */
346 
347 
348 /* {{{ proto mixed mysqli_fetch_array (object result [,int resulttype])
349    Fetch a result row as an associative array, a numeric array, or both */
350 PHP_FUNCTION(mysqli_fetch_array)
351 {
352 	php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0);
353 }
354 /* }}} */
355 
356 /* {{{ proto mixed mysqli_fetch_assoc (object result)
357    Fetch a result row as an associative array */
358 PHP_FUNCTION(mysqli_fetch_assoc)
359 {
360 	php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQLI_ASSOC, 0);
361 }
362 /* }}} */
363 
364 
365 /* {{{ proto mixed mysqli_fetch_all (object result [,int resulttype])
366    Fetches all result rows as an associative array, a numeric array, or both */
367 #if defined(MYSQLI_USE_MYSQLND)
368 PHP_FUNCTION(mysqli_fetch_all)
369 {
370 	MYSQL_RES	*result;
371 	zval		*mysql_result;
372 	long		mode = MYSQLND_FETCH_NUM;
373 
374 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O|l", &mysql_result, mysqli_result_class_entry, &mode) == FAILURE) {
375 		return;
376 	}
377 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, &mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
378 
379 	if (!mode || (mode & ~MYSQLND_FETCH_BOTH)) {
380 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Mode can be only MYSQLI_FETCH_NUM, "
381 		                 "MYSQLI_FETCH_ASSOC or MYSQLI_FETCH_BOTH");
382 		RETURN_FALSE;
383 	}
384 
385 	mysqlnd_fetch_all(result, mode, return_value);
386 }
387 /* }}} */
388 
389 
390 /* {{{ proto array mysqli_cache_stats(void) U
391    Returns statistics about the zval cache */
392 PHP_FUNCTION(mysqli_get_cache_stats)
393 {
394 	if (zend_parse_parameters_none() == FAILURE) {
395 		return;
396 	}
397 	array_init(return_value);
398 }
399 /* }}} */
400 
401 
402 /* {{{ proto array mysqli_get_client_stats(void)
403    Returns statistics about the zval cache */
404 PHP_FUNCTION(mysqli_get_client_stats)
405 {
406 	if (zend_parse_parameters_none() == FAILURE) {
407 		return;
408 	}
409 	mysqlnd_get_client_stats(return_value);
410 }
411 /* }}} */
412 
413 
414 /* {{{ proto array mysqli_get_connection_stats(void)
415    Returns statistics about the zval cache */
416 PHP_FUNCTION(mysqli_get_connection_stats)
417 {
418 	MY_MYSQL	*mysql;
419 	zval		*mysql_link;
420 
421 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
422 									 &mysql_link, mysqli_link_class_entry) == FAILURE) {
423 		return;
424 	}
425 	MYSQLI_FETCH_RESOURCE_CONN(mysql, &mysql_link, MYSQLI_STATUS_VALID);
426 
427 	mysqlnd_get_connection_stats(mysql->mysql, return_value);
428 }
429 #endif
430 /* }}} */
431 
432 
433 /* {{{ proto mixed mysqli_fetch_object (object result [, string class_name [, NULL|array ctor_params]])
434    Fetch a result row as an object */
435 PHP_FUNCTION(mysqli_fetch_object)
436 {
437 	php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQLI_ASSOC, 1);
438 }
439 /* }}} */
440 
441 /* {{{ proto bool mysqli_multi_query(object link, string query)
442    allows to execute multiple queries  */
443 PHP_FUNCTION(mysqli_multi_query)
444 {
445 	MY_MYSQL	*mysql;
446 	zval		*mysql_link;
447 	char		*query = NULL;
448 	int 		query_len;
449 
450 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &mysql_link, mysqli_link_class_entry, &query, &query_len) == FAILURE) {
451 		return;
452 	}
453 	MYSQLI_FETCH_RESOURCE_CONN(mysql, &mysql_link, MYSQLI_STATUS_VALID);
454 
455 	MYSQLI_ENABLE_MQ;
456 	if (mysql_real_query(mysql->mysql, query, query_len)) {
457 #ifndef MYSQLI_USE_MYSQLND
458 		char s_error[MYSQL_ERRMSG_SIZE], s_sqlstate[SQLSTATE_LENGTH+1];
459 		unsigned int s_errno;
460 		/* we have to save error information, cause
461 		MYSQLI_DISABLE_MQ will reset error information */
462 		strcpy(s_error, mysql_error(mysql->mysql));
463 		strcpy(s_sqlstate, mysql_sqlstate(mysql->mysql));
464 		s_errno = mysql_errno(mysql->mysql);
465 #else
466 		MYSQLND_ERROR_INFO error_info = mysql->mysql->error_info;
467 #endif
468 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
469 		MYSQLI_DISABLE_MQ;
470 
471 #ifndef MYSQLI_USE_MYSQLND
472 		/* restore error information */
473 		strcpy(mysql->mysql->net.last_error, s_error);
474 		strcpy(mysql->mysql->net.sqlstate, s_sqlstate);
475 		mysql->mysql->net.last_errno = s_errno;
476 #else
477 		mysql->mysql->error_info = error_info;
478 #endif
479 		RETURN_FALSE;
480 	}
481 	RETURN_TRUE;
482 }
483 /* }}} */
484 
485 /* {{{ proto mixed mysqli_query(object link, string query [,int resultmode]) */
486 PHP_FUNCTION(mysqli_query)
487 {
488 	MY_MYSQL			*mysql;
489 	zval				*mysql_link;
490 	MYSQLI_RESOURCE		*mysqli_resource;
491 	MYSQL_RES 			*result;
492 	char				*query = NULL;
493 	int 				query_len;
494 	long 				resultmode = MYSQLI_STORE_RESULT;
495 
496 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os|l", &mysql_link, mysqli_link_class_entry, &query, &query_len, &resultmode) == FAILURE) {
497 		return;
498 	}
499 
500 	if (!query_len) {
501 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty query");
502 		RETURN_FALSE;
503 	}
504 	if ((resultmode & ~MYSQLI_ASYNC) != MYSQLI_USE_RESULT && (resultmode & ~MYSQLI_ASYNC) != MYSQLI_STORE_RESULT) {
505 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid value for resultmode");
506 		RETURN_FALSE;
507 	}
508 
509 	MYSQLI_FETCH_RESOURCE_CONN(mysql, &mysql_link, MYSQLI_STATUS_VALID);
510 
511 	MYSQLI_DISABLE_MQ;
512 
513 
514 #ifdef MYSQLI_USE_MYSQLND
515 	if (resultmode & MYSQLI_ASYNC) {
516 		if (mysqli_async_query(mysql->mysql, query, query_len)) {
517 			MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
518 			RETURN_FALSE;
519 		}
520 		mysql->async_result_fetch_type = resultmode & ~MYSQLI_ASYNC;
521 		RETURN_TRUE;
522 	}
523 #endif
524 
525 	if (mysql_real_query(mysql->mysql, query, query_len)) {
526 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
527 		RETURN_FALSE;
528 	}
529 
530 	if (!mysql_field_count(mysql->mysql)) {
531 		/* no result set - not a SELECT */
532 		if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
533 			php_mysqli_report_index(query, mysqli_server_status(mysql->mysql) TSRMLS_CC);
534 		}
535 		RETURN_TRUE;
536 	}
537 
538 	switch (resultmode) {
539 		case MYSQLI_STORE_RESULT:
540 			result = mysql_store_result(mysql->mysql);
541 			break;
542 		case MYSQLI_USE_RESULT:
543 			result = mysql_use_result(mysql->mysql);
544 			break;
545 	}
546 	if (!result) {
547 		php_mysqli_throw_sql_exception((char *)mysql_sqlstate(mysql->mysql), mysql_errno(mysql->mysql) TSRMLS_CC,
548 										"%s", mysql_error(mysql->mysql));
549 		RETURN_FALSE;
550 	}
551 
552 	if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
553 		php_mysqli_report_index(query, mysqli_server_status(mysql->mysql) TSRMLS_CC);
554 	}
555 
556 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
557 	mysqli_resource->ptr = (void *)result;
558 	mysqli_resource->status = MYSQLI_STATUS_VALID;
559 	MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_result_class_entry);
560 }
561 /* }}} */
562 
563 
564 #if defined(MYSQLI_USE_MYSQLND)
565 #include "php_network.h"
566 /* {{{ mysqlnd_zval_array_to_mysqlnd_array functions */
567 static int mysqlnd_zval_array_to_mysqlnd_array(zval *in_array, MYSQLND ***out_array TSRMLS_DC)
568 {
569 	zval **elem;
570 	int i = 0, current = 0;
571 
572 	if (Z_TYPE_P(in_array) != IS_ARRAY) {
573 		return 0;
574 	}
575 	*out_array = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(in_array)) + 1, sizeof(MYSQLND *));
576 	for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(in_array));
577 		 zend_hash_get_current_data(Z_ARRVAL_P(in_array), (void **) &elem) == SUCCESS;
578 		 zend_hash_move_forward(Z_ARRVAL_P(in_array))) {
579 		i++;
580 		if (Z_TYPE_PP(elem) != IS_OBJECT ||
581 			!instanceof_function(Z_OBJCE_PP(elem), mysqli_link_class_entry TSRMLS_CC)) {
582 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Parameter %d not a mysqli object", i);
583 		} else {
584 			MY_MYSQL *mysql;
585 			MYSQLI_RESOURCE *my_res;
586 			mysqli_object *intern = (mysqli_object *)zend_object_store_get_object(*elem TSRMLS_CC);
587 			if (!(my_res = (MYSQLI_RESOURCE *)intern->ptr)) {
588 		  		php_error_docref(NULL TSRMLS_CC, E_WARNING, "[%d] Couldn't fetch %s", i, intern->zo.ce->name);
589 				continue;
590 		  	}
591 			mysql = (MY_MYSQL*) my_res->ptr;
592 			if (MYSQLI_STATUS_VALID && my_res->status < MYSQLI_STATUS_VALID) {
593 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid object %d or resource %s", i, intern->zo.ce->name);
594 				continue;
595 			}
596 			(*out_array)[current++] = mysql->mysql;
597 		}
598 	}
599 	return 0;
600 }
601 /* }}} */
602 
603 
604 /* {{{ mysqlnd_zval_array_from_mysqlnd_array */
605 static int mysqlnd_zval_array_from_mysqlnd_array(MYSQLND **in_array, zval *out_array TSRMLS_DC)
606 {
607 	MYSQLND **p = in_array;
608 	HashTable *new_hash;
609 	zval **elem, **dest_elem;
610 	int ret = 0, i = 0;
611 
612 	ALLOC_HASHTABLE(new_hash);
613 	zend_hash_init(new_hash, zend_hash_num_elements(Z_ARRVAL_P(out_array)), NULL, ZVAL_PTR_DTOR, 0);
614 
615 	for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(out_array));
616 		 zend_hash_get_current_data(Z_ARRVAL_P(out_array), (void **) &elem) == SUCCESS;
617 		 zend_hash_move_forward(Z_ARRVAL_P(out_array)))
618 	{
619 		i++;
620 		if (Z_TYPE_PP(elem) != IS_OBJECT || !instanceof_function(Z_OBJCE_PP(elem), mysqli_link_class_entry TSRMLS_CC)) {
621 			continue;
622 		}
623 		{
624 			MY_MYSQL *mysql;
625 			MYSQLI_RESOURCE *my_res;
626 			mysqli_object *intern = (mysqli_object *)zend_object_store_get_object(*elem TSRMLS_CC);
627 			if (!(my_res = (MYSQLI_RESOURCE *)intern->ptr)) {
628 		  		php_error_docref(NULL TSRMLS_CC, E_WARNING, "[%d] Couldn't fetch %s", i, intern->zo.ce->name);
629 				continue;
630 		  	}
631 			mysql = (MY_MYSQL *) my_res->ptr;
632 			if (mysql->mysql == *p) {
633 				zend_hash_next_index_insert(new_hash, (void *)elem, sizeof(zval *), (void **)&dest_elem);
634 				if (dest_elem) {
635 					zval_add_ref(dest_elem);
636 				}
637 				ret++;
638 				p++;
639 			}
640 		}
641 	}
642 
643 	/* destroy old array and add new one */
644 	zend_hash_destroy(Z_ARRVAL_P(out_array));
645 	efree(Z_ARRVAL_P(out_array));
646 
647 	zend_hash_internal_pointer_reset(new_hash);
648 	Z_ARRVAL_P(out_array) = new_hash;
649 
650 	return 0;
651 }
652 /* }}} */
653 
654 
655 /* {{{ mysqlnd_dont_poll_zval_array_from_mysqlnd_array */
656 static int mysqlnd_dont_poll_zval_array_from_mysqlnd_array(MYSQLND **in_array, zval *in_zval_array, zval *out_array TSRMLS_DC)
657 {
658 	MYSQLND **p = in_array;
659 	HashTable *new_hash;
660 	zval **elem, **dest_elem;
661 	int ret = 0;
662 
663 	ALLOC_HASHTABLE(new_hash);
664 	zend_hash_init(new_hash, zend_hash_num_elements(Z_ARRVAL_P(in_zval_array)), NULL, ZVAL_PTR_DTOR, 0);
665 	if (in_array) {
666 		for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(in_zval_array));
667 			 zend_hash_get_current_data(Z_ARRVAL_P(in_zval_array), (void **) &elem) == SUCCESS;
668 			 zend_hash_move_forward(Z_ARRVAL_P(in_zval_array)))
669 		{
670 			MY_MYSQL *mysql;
671 			mysqli_object *intern = (mysqli_object *)zend_object_store_get_object(*elem TSRMLS_CC);
672 			mysql = (MY_MYSQL *) ((MYSQLI_RESOURCE *)intern->ptr)->ptr;
673 			if (mysql->mysql == *p) {
674 				zend_hash_next_index_insert(new_hash, (void *)elem, sizeof(zval *), (void **)&dest_elem);
675 				if (dest_elem) {
676 					zval_add_ref(dest_elem);
677 				}
678 				ret++;
679 				p++;
680 			}
681 		}
682 	}
683 
684 	/* destroy old array and add new one */
685 	zend_hash_destroy(Z_ARRVAL_P(out_array));
686 	efree(Z_ARRVAL_P(out_array));
687 
688 	zend_hash_internal_pointer_reset(new_hash);
689 	Z_ARRVAL_P(out_array) = new_hash;
690 
691 	return 0;
692 }
693 /* }}} */
694 
695 
696 /* {{{ proto int mysqli_poll(array read, array write, array error, long sec [, long usec]) U
697    Poll connections */
698 PHP_FUNCTION(mysqli_poll)
699 {
700 	zval			*r_array, *e_array, *dont_poll_array;
701 	MYSQLND			**new_r_array = NULL, **new_e_array = NULL, **new_dont_poll_array = NULL;
702 	long			sec = 0, usec = 0;
703 	enum_func_status ret;
704 	uint 			desc_num;
705 
706 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a!a!al|l", &r_array, &e_array, &dont_poll_array, &sec, &usec) == FAILURE) {
707 		return;
708 	}
709 	if (sec < 0 || usec < 0) {
710 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Negative values passed for sec and/or usec");
711 		RETURN_FALSE;
712 	}
713 
714 	if (!r_array && !e_array) {
715 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No stream arrays were passed");
716 		RETURN_FALSE;
717 	}
718 
719 	if (r_array != NULL) {
720 		mysqlnd_zval_array_to_mysqlnd_array(r_array, &new_r_array TSRMLS_CC);
721 	}
722 	if (e_array != NULL) {
723 		mysqlnd_zval_array_to_mysqlnd_array(e_array, &new_e_array TSRMLS_CC);
724 	}
725 
726 	ret = mysqlnd_poll(new_r_array, new_e_array, &new_dont_poll_array, sec, usec, &desc_num);
727 
728 	mysqlnd_dont_poll_zval_array_from_mysqlnd_array(r_array != NULL ? new_dont_poll_array:NULL, r_array, dont_poll_array TSRMLS_CC);
729 
730 	if (r_array != NULL) {
731 		mysqlnd_zval_array_from_mysqlnd_array(new_r_array, r_array TSRMLS_CC);
732 	}
733 	if (e_array != NULL) {
734 		mysqlnd_zval_array_from_mysqlnd_array(new_e_array, e_array TSRMLS_CC);
735 	}
736 
737 	if (new_dont_poll_array) {
738 		efree(new_dont_poll_array);
739 	}
740 	if (new_r_array) {
741 		efree(new_r_array);
742 	}
743 	if (new_e_array) {
744 		efree(new_e_array);
745 	}
746 	if (ret == PASS) {
747 		RETURN_LONG(desc_num);
748 	} else {
749 		RETURN_FALSE;
750 	}
751 }
752 /* }}} */
753 
754 
755 /* {{{ proto int mysqli_reap_async_query(object link) U
756    Poll connections */
757 PHP_FUNCTION(mysqli_reap_async_query)
758 {
759 	MY_MYSQL		*mysql;
760 	zval			*mysql_link;
761 	MYSQLI_RESOURCE		*mysqli_resource;
762 	MYSQL_RES 			*result;
763 
764 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
765 		return;
766 	}
767 
768 	MYSQLI_FETCH_RESOURCE_CONN(mysql, &mysql_link, MYSQLI_STATUS_VALID);
769 
770 	if (FAIL == mysqlnd_reap_async_query(mysql->mysql)) {
771 		RETURN_FALSE;
772 	}
773 
774 	if (!mysql_field_count(mysql->mysql)) {
775 		/* no result set - not a SELECT */
776 		if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
777 /*			php_mysqli_report_index("n/a", mysqli_server_status(mysql->mysql) TSRMLS_CC); */
778 		}
779 		RETURN_TRUE;
780 	}
781 
782 	switch (mysql->async_result_fetch_type) {
783 		case MYSQLI_STORE_RESULT:
784 			result = mysql_store_result(mysql->mysql);
785 			break;
786 		case MYSQLI_USE_RESULT:
787 			result = mysql_use_result(mysql->mysql);
788 			break;
789 	}
790 
791 	if (!result) {
792 		php_mysqli_throw_sql_exception((char *)mysql_sqlstate(mysql->mysql), mysql_errno(mysql->mysql) TSRMLS_CC,
793 										"%s", mysql_error(mysql->mysql));
794 		RETURN_FALSE;
795 	}
796 
797 	if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
798 /*		php_mysqli_report_index("n/a", mysqli_server_status(mysql->mysql) TSRMLS_CC); */
799 	}
800 
801 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
802 	mysqli_resource->ptr = (void *)result;
803 	mysqli_resource->status = MYSQLI_STATUS_VALID;
804 	MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_result_class_entry);
805 }
806 /* }}} */
807 
808 
809 /* {{{ proto object mysqli_stmt_get_result(object link) U
810    Buffer result set on client */
811 PHP_FUNCTION(mysqli_stmt_get_result)
812 {
813 	MYSQL_RES 		*result;
814 	MYSQLI_RESOURCE	*mysqli_resource;
815 	MY_STMT			*stmt;
816 	zval 			*mysql_stmt;
817 
818 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
819 		return;
820 	}
821 	MYSQLI_FETCH_RESOURCE_STMT(stmt, &mysql_stmt, MYSQLI_STATUS_VALID);
822 
823 	if (!(result = mysqlnd_stmt_get_result(stmt->stmt))) {
824 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
825 		RETURN_FALSE;
826 	}
827 
828 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
829 	mysqli_resource->ptr = (void *)result;
830 	mysqli_resource->status = MYSQLI_STATUS_VALID;
831 	MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_result_class_entry);
832 }
833 /* }}} */
834 #endif
835 
836 
837 /* {{{ proto object mysqli_get_warnings(object link) */
838 PHP_FUNCTION(mysqli_get_warnings)
839 {
840 	MY_MYSQL			*mysql;
841 	zval				*mysql_link;
842 	MYSQLI_RESOURCE		*mysqli_resource;
843 	MYSQLI_WARNING		*w;
844 
845 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
846 		return;
847 	}
848 	MYSQLI_FETCH_RESOURCE_CONN(mysql, &mysql_link, MYSQLI_STATUS_VALID);
849 
850 	if (mysql_warning_count(mysql->mysql)) {
851 		w = php_get_warnings(mysql->mysql TSRMLS_CC);
852 	} else {
853 		RETURN_FALSE;
854 	}
855 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
856 	mysqli_resource->ptr = mysqli_resource->info = (void *)w;
857 	mysqli_resource->status = MYSQLI_STATUS_VALID;
858 	MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_warning_class_entry);
859 }
860 /* }}} */
861 
862 /* {{{ proto object mysqli_stmt_get_warnings(object link) */
863 PHP_FUNCTION(mysqli_stmt_get_warnings)
864 {
865 	MY_STMT				*stmt;
866 	zval				*stmt_link;
867 	MYSQLI_RESOURCE		*mysqli_resource;
868 	MYSQLI_WARNING		*w;
869 
870 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &stmt_link, mysqli_stmt_class_entry) == FAILURE) {
871 		return;
872 	}
873 	MYSQLI_FETCH_RESOURCE_STMT(stmt, &stmt_link, MYSQLI_STATUS_VALID);
874 
875 	if (mysqli_stmt_warning_count(stmt->stmt)) {
876 		w = php_get_warnings(mysqli_stmt_get_connection(stmt->stmt) TSRMLS_CC);
877 	} else {
878 		RETURN_FALSE;
879 	}
880 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
881 	mysqli_resource->ptr = mysqli_resource->info = (void *)w;
882 	mysqli_resource->status = MYSQLI_STATUS_VALID;
883 	MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_warning_class_entry);
884 }
885 /* }}} */
886 
887 #ifdef HAVE_MYSQLI_SET_CHARSET
888 /* {{{ proto bool mysqli_set_charset(object link, string csname)
889    sets client character set */
890 PHP_FUNCTION(mysqli_set_charset)
891 {
892 	MY_MYSQL	*mysql;
893 	zval		*mysql_link;
894 	char		*cs_name;
895 	int			csname_len;
896 
897 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &mysql_link, mysqli_link_class_entry, &cs_name, &csname_len) == FAILURE) {
898 		return;
899 	}
900 	MYSQLI_FETCH_RESOURCE_CONN(mysql, &mysql_link, MYSQLI_STATUS_VALID);
901 
902 	if (mysql_set_character_set(mysql->mysql, cs_name)) {
903 		RETURN_FALSE;
904 	}
905 	RETURN_TRUE;
906 }
907 /* }}} */
908 #endif
909 
910 #ifdef HAVE_MYSQLI_GET_CHARSET
911 /* {{{ proto object mysqli_get_charset(object link) U
912    returns a character set object */
913 PHP_FUNCTION(mysqli_get_charset)
914 {
915 	MY_MYSQL				*mysql;
916 	zval					*mysql_link;
917 	const char 				*name = NULL, *collation = NULL, *dir = NULL, *comment = NULL;
918 	uint					minlength, maxlength, number, state;
919 #if !defined(MYSQLI_USE_MYSQLND)
920 	MY_CHARSET_INFO			cs;
921 #else
922 	const MYSQLND_CHARSET	*cs;
923 #endif
924 
925 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
926 		return;
927 	}
928 	MYSQLI_FETCH_RESOURCE_CONN(mysql, &mysql_link, MYSQLI_STATUS_VALID);
929 
930 
931 #if !defined(MYSQLI_USE_MYSQLND)
932 	mysql_get_character_set_info(mysql->mysql, &cs);
933 	name = (char *)cs.csname;
934 	collation = (char *)cs.name;
935 	dir = (char *)cs.dir;
936 	minlength = cs.mbminlen;
937 	maxlength = cs.mbmaxlen;
938 	number = cs.number;
939 	state = cs.state;
940 	comment = cs.comment;
941 #else
942 	cs = mysql->mysql->charset;
943 	if (!cs) {
944 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "The connection has no charset associated");
945 		RETURN_NULL();
946 	}
947 	name = cs->name;
948 	collation = cs->collation;
949 	minlength = cs->char_minlen;
950 	maxlength = cs->char_maxlen;
951 	number = cs->nr;
952 	comment = cs->comment;
953 	state = 1;	/* all charsets are compiled in */
954 #endif
955 	object_init(return_value);
956 
957 	add_property_string(return_value, "charset", (name) ? (char *)name : "", 1);
958 	add_property_string(return_value, "collation",(collation) ? (char *)collation : "", 1);
959 	add_property_string(return_value, "dir", (dir) ? (char *)dir : "", 1);
960 	add_property_long(return_value, "min_length", minlength);
961 	add_property_long(return_value, "max_length", maxlength);
962 	add_property_long(return_value, "number", number);
963 	add_property_long(return_value, "state", state);
964 	add_property_string(return_value, "comment", (comment) ? (char *)comment : "", 1);
965 }
966 /* }}} */
967 #endif
968 
969 /*
970  * Local variables:
971  * tab-width: 4
972  * c-basic-offset: 4
973  * End:
974  * vim600: noet sw=4 ts=4 fdm=marker
975  * vim<600: noet sw=4 ts=4
976  */
977