xref: /php-src/ext/mysqli/mysqli_api.c (revision 2446500d)
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 "zend_smart_str.h"
27 #include "php_mysqli_structs.h"
28 #include "mysqli_priv.h"
29 #include "ext/mysqlnd/mysql_float_to_double.h"
30 
31 #define ERROR_ARG_POS(arg_num) (hasThis() ? (arg_num-1) : (arg_num))
32 
33 /* {{{ Get number of affected rows in previous MySQL operation */
PHP_FUNCTION(mysqli_affected_rows)34 PHP_FUNCTION(mysqli_affected_rows)
35 {
36 	MY_MYSQL 		*mysql;
37 	zval  			*mysql_link;
38 	my_ulonglong	rc;
39 
40 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
41 		RETURN_THROWS();
42 	}
43 
44 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
45 
46 	rc = mysql_affected_rows(mysql->mysql);
47 	if (rc == (my_ulonglong) -1) {
48 		RETURN_LONG(-1);
49 	}
50 	MYSQLI_RETURN_LONG_INT(rc);
51 }
52 /* }}} */
53 
54 /* {{{ Turn auto commit on or of */
PHP_FUNCTION(mysqli_autocommit)55 PHP_FUNCTION(mysqli_autocommit)
56 {
57 	MY_MYSQL	*mysql;
58 	zval		*mysql_link;
59 	bool	automode;
60 
61 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ob", &mysql_link, mysqli_link_class_entry, &automode) == FAILURE) {
62 		RETURN_THROWS();
63 	}
64 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
65 
66 	if (mysql_autocommit(mysql->mysql, (my_bool)automode)) {
67 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
68 		RETURN_FALSE;
69 	}
70 	RETURN_TRUE;
71 }
72 /* }}} */
73 
74 /* {{{ mysqli_stmt_bind_param_do_bind */
mysqli_stmt_bind_param_do_bind(MY_STMT * stmt,uint32_t num_vars,zval * args,const char * const types,unsigned int arg_num)75 static enum_func_status mysqli_stmt_bind_param_do_bind(MY_STMT *stmt, uint32_t num_vars, zval *args, const char * const types, unsigned int arg_num)
76 {
77 	MYSQLND_PARAM_BIND	*params;
78 	enum_func_status	ret = FAIL;
79 
80 	/* If no params -> skip binding and return directly */
81 	if (num_vars == 0) {
82 		return PASS;
83 	}
84 	params = mysqlnd_stmt_alloc_param_bind(stmt->stmt);
85 	if (!params) {
86 		goto end;
87 	}
88 	for (uint32_t i = 0; i < num_vars; i++) {
89 		uint8_t type;
90 		switch (types[i]) {
91 			case 'd': /* Double */
92 				type = MYSQL_TYPE_DOUBLE;
93 				break;
94 			case 'i': /* Integer */
95 #if SIZEOF_ZEND_LONG==8
96 				type = MYSQL_TYPE_LONGLONG;
97 #elif SIZEOF_ZEND_LONG==4
98 				type = MYSQL_TYPE_LONG;
99 #endif
100 				break;
101 			case 'b': /* Blob (send data) */
102 				type = MYSQL_TYPE_LONG_BLOB;
103 				break;
104 			case 's': /* string */
105 				type = MYSQL_TYPE_VAR_STRING;
106 				break;
107 			default:
108 				zend_argument_value_error(arg_num, "must only contain the \"b\", \"d\", \"i\", \"s\" type specifiers");
109 				ret = FAIL;
110 				mysqlnd_stmt_free_param_bind(stmt->stmt, params);
111 				goto end;
112 		}
113 		ZVAL_COPY_VALUE(&params[i].zv, &args[i]);
114 		params[i].type = type;
115 	}
116 	ret = mysqlnd_stmt_bind_param(stmt->stmt, params);
117 
118 end:
119 	return ret;
120 }
121 /* }}} */
122 
123 /* {{{ Bind variables to a prepared statement as parameters */
PHP_FUNCTION(mysqli_stmt_bind_param)124 PHP_FUNCTION(mysqli_stmt_bind_param)
125 {
126 	zval			*args;
127 	uint32_t		argc;
128 	MY_STMT			*stmt;
129 	zval			*mysql_stmt;
130 	char			*types;
131 	size_t			types_len;
132 
133 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os*", &mysql_stmt, mysqli_stmt_class_entry, &types, &types_len, &args, &argc) == FAILURE) {
134 		RETURN_THROWS();
135 	}
136 
137 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
138 
139 	if (!types_len) {
140 		zend_argument_must_not_be_empty_error(ERROR_ARG_POS(2));
141 		RETURN_THROWS();
142 	}
143 
144 	if (types_len != (size_t) argc) {
145 		/* number of bind variables doesn't match number of elements in type definition string */
146 		zend_argument_count_error("The number of elements in the type definition string must match the number of bind variables");
147 		RETURN_THROWS();
148 	}
149 
150 	if (types_len != mysql_stmt_param_count(stmt->stmt)) {
151 		zend_argument_count_error("The number of variables must match the number of parameters in the prepared statement");
152 		RETURN_THROWS();
153 	}
154 
155 	RETVAL_BOOL(mysqli_stmt_bind_param_do_bind(stmt, argc, args, types, ERROR_ARG_POS(2)) == PASS);
156 	MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
157 }
158 /* }}} */
159 
160 /* {{{ mysqli_stmt_bind_result_do_bind */
mysqli_stmt_bind_result_do_bind(MY_STMT * stmt,zval * args,uint32_t argc)161 static enum_func_status mysqli_stmt_bind_result_do_bind(MY_STMT *stmt, zval *args, uint32_t argc)
162 {
163 	MYSQLND_RESULT_BIND *params = mysqlnd_stmt_alloc_result_bind(stmt->stmt);
164 	if (params) {
165 		for (uint32_t i = 0; i < argc; i++) {
166 			ZVAL_COPY_VALUE(&params[i].zv, &args[i]);
167 		}
168 		return mysqlnd_stmt_bind_result(stmt->stmt, params);
169 	}
170 	return FAIL;
171 }
172 /* }}} */
173 
174 /* {{{ Bind variables to a prepared statement for result storage */
PHP_FUNCTION(mysqli_stmt_bind_result)175 PHP_FUNCTION(mysqli_stmt_bind_result)
176 {
177 	zval		*args;
178 	uint32_t	argc;
179 	MY_STMT		*stmt;
180 	zval		*mysql_stmt;
181 
182 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O+", &mysql_stmt, mysqli_stmt_class_entry, &args, &argc) == FAILURE) {
183 		RETURN_THROWS();
184 	}
185 
186 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
187 
188 	if (argc != mysql_stmt_field_count(stmt->stmt)) {
189 		zend_argument_count_error("Number of bind variables doesn't match number of fields in prepared statement");
190 		RETURN_THROWS();
191 	}
192 
193 	enum_func_status rc = mysqli_stmt_bind_result_do_bind(stmt, args, argc);
194 	RETURN_BOOL(rc == PASS);
195 }
196 /* }}} */
197 
198 /* {{{ Change logged-in user of the active connection */
PHP_FUNCTION(mysqli_change_user)199 PHP_FUNCTION(mysqli_change_user)
200 {
201 	MY_MYSQL	*mysql;
202 	zval		*mysql_link = NULL;
203 	char		*user, *password, *dbname;
204 	size_t			user_len, password_len, dbname_len;
205 
206 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Osss!", &mysql_link, mysqli_link_class_entry, &user, &user_len, &password, &password_len, &dbname, &dbname_len) == FAILURE) {
207 		RETURN_THROWS();
208 	}
209 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
210 
211 	enum_func_status rc = mysqlnd_change_user_ex(mysql->mysql, user, password, dbname, false, (size_t) password_len);
212 	MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
213 
214 	RETURN_BOOL(rc == PASS);
215 }
216 /* }}} */
217 
218 /* {{{ Returns the name of the character set used for this connection */
PHP_FUNCTION(mysqli_character_set_name)219 PHP_FUNCTION(mysqli_character_set_name)
220 {
221 	MY_MYSQL	*mysql;
222 	zval		*mysql_link;
223 
224 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
225 		RETURN_THROWS();
226 	}
227 
228 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
229 	RETURN_STRING(mysql_character_set_name(mysql->mysql));
230 }
231 /* }}} */
232 
233 /* {{{ php_mysqli_close */
php_mysqli_close(MY_MYSQL * mysql,int close_type,int resource_status)234 void php_mysqli_close(MY_MYSQL * mysql, int close_type, int resource_status)
235 {
236 	if (resource_status > MYSQLI_STATUS_INITIALIZED) {
237 		MyG(num_links)--;
238 	}
239 
240 	if (!mysql->persistent) {
241 		mysqli_close(mysql->mysql, close_type);
242 	} else {
243 		zend_resource *le;
244 		if ((le = zend_hash_find_ptr(&EG(persistent_list), mysql->hash_key)) != NULL) {
245 			if (le->type == php_le_pmysqli()) {
246 				mysqli_plist_entry *plist = (mysqli_plist_entry *) le->ptr;
247 				mysqlnd_end_psession(mysql->mysql);
248 
249 				if (MyG(rollback_on_cached_plink) &&
250 					FAIL == mysqlnd_rollback(mysql->mysql, TRANS_COR_NO_OPT, NULL))
251 				{
252 					mysqli_close(mysql->mysql, close_type);
253 				} else {
254 					zend_ptr_stack_push(&plist->free_links, mysql->mysql);
255 					MyG(num_inactive_persistent)++;
256 				}
257 				MyG(num_active_persistent)--;
258 			}
259 		}
260 		mysql->persistent = false;
261 	}
262 	mysql->mysql = NULL;
263 
264 	php_clear_mysql(mysql);
265 }
266 /* }}} */
267 
268 /* {{{ Close connection */
PHP_FUNCTION(mysqli_close)269 PHP_FUNCTION(mysqli_close)
270 {
271 	zval		*mysql_link;
272 	MY_MYSQL	*mysql;
273 
274 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
275 		RETURN_THROWS();
276 	}
277 
278 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_INITIALIZED);
279 
280 	php_mysqli_close(mysql, MYSQLI_CLOSE_EXPLICIT, ((MYSQLI_RESOURCE *)(Z_MYSQLI_P(mysql_link))->ptr)->status);
281 	((MYSQLI_RESOURCE *)(Z_MYSQLI_P(mysql_link))->ptr)->status = MYSQLI_STATUS_UNKNOWN;
282 
283 	MYSQLI_CLEAR_RESOURCE(mysql_link);
284 	efree(mysql);
285 	RETURN_TRUE;
286 }
287 /* }}} */
288 
289 /* {{{ Commit outstanding actions and close transaction */
PHP_FUNCTION(mysqli_commit)290 PHP_FUNCTION(mysqli_commit)
291 {
292 	MY_MYSQL	*mysql;
293 	zval		*mysql_link;
294 	zend_long		flags = TRANS_COR_NO_OPT;
295 	char *		name = NULL;
296 	size_t			name_len;
297 
298 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|ls!", &mysql_link, mysqli_link_class_entry, &flags, &name, &name_len) == FAILURE) {
299 		RETURN_THROWS();
300 	}
301 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
302 
303 	if (FAIL == mysqlnd_commit(mysql->mysql, flags, name)) {
304 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
305 		RETURN_FALSE;
306 	}
307 	RETURN_TRUE;
308 }
309 /* }}} */
310 
311 /* {{{ Move internal result pointer */
PHP_FUNCTION(mysqli_data_seek)312 PHP_FUNCTION(mysqli_data_seek)
313 {
314 	MYSQL_RES	*result;
315 	zval		*mysql_result;
316 	zend_long		offset;
317 
318 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_result, mysqli_result_class_entry, &offset) == FAILURE) {
319 		RETURN_THROWS();
320 	}
321 
322 	if (offset < 0) {
323 		zend_argument_value_error(ERROR_ARG_POS(2), "must be greater than or equal to 0");
324 		RETURN_THROWS();
325 	}
326 
327 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
328 
329 	if (mysqli_result_is_unbuffered(result)) {
330 		if (getThis()) {
331 			zend_throw_error(NULL, "mysqli_result::data_seek() cannot be used in MYSQLI_USE_RESULT mode");
332 		} else {
333 			zend_throw_error(NULL, "mysqli_data_seek() cannot be used in MYSQLI_USE_RESULT mode");
334 		}
335 		RETURN_THROWS();
336 	}
337 
338 	if ((uint64_t)offset >= mysql_num_rows(result)) {
339 		RETURN_FALSE;
340 	}
341 
342 	mysql_data_seek(result, offset);
343 	RETURN_TRUE;
344 }
345 /* }}} */
346 
347 /* {{{ */
PHP_FUNCTION(mysqli_debug)348 PHP_FUNCTION(mysqli_debug)
349 {
350 	char	*debug;
351 	size_t		debug_len;
352 
353 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &debug, &debug_len) == FAILURE) {
354 		RETURN_THROWS();
355 	}
356 
357 	mysql_debug(debug);
358 	RETURN_TRUE;
359 }
360 /* }}} */
361 
362 /* {{{ */
PHP_FUNCTION(mysqli_dump_debug_info)363 PHP_FUNCTION(mysqli_dump_debug_info)
364 {
365 	MY_MYSQL	*mysql;
366 	zval		*mysql_link;
367 
368 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
369 		RETURN_THROWS();
370 	}
371 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
372 
373 	RETURN_BOOL(!mysql_dump_debug_info(mysql->mysql));
374 }
375 /* }}} */
376 
377 /* {{{ Returns the numerical value of the error message from previous MySQL operation */
PHP_FUNCTION(mysqli_errno)378 PHP_FUNCTION(mysqli_errno)
379 {
380 	MY_MYSQL	*mysql;
381 	zval		*mysql_link;
382 
383 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
384 		RETURN_THROWS();
385 	}
386 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
387 	RETURN_LONG(mysql_errno(mysql->mysql));
388 }
389 /* }}} */
390 
391 /* {{{ Returns the text of the error message from previous MySQL operation */
PHP_FUNCTION(mysqli_error)392 PHP_FUNCTION(mysqli_error)
393 {
394 	MY_MYSQL	*mysql;
395 	zval		*mysql_link;
396 
397 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
398 		RETURN_THROWS();
399 	}
400 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
401 	RETURN_STRING(mysql_error(mysql->mysql));
402 }
403 /* }}} */
404 
405 /* {{{ Execute a prepared statement */
PHP_FUNCTION(mysqli_stmt_execute)406 PHP_FUNCTION(mysqli_stmt_execute)
407 {
408 	MY_STMT		*stmt;
409 	zval		*mysql_stmt;
410 	HashTable	*input_params = NULL;
411 
412 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|h!", &mysql_stmt, mysqli_stmt_class_entry, &input_params) == FAILURE) {
413 		RETURN_THROWS();
414 	}
415 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
416 
417 	// bind-in-execute
418 	if (input_params) {
419 		zval *tmp;
420 		unsigned int index;
421 		unsigned int hash_num_elements;
422 		unsigned int param_count;
423 		MYSQLND_PARAM_BIND	*params;
424 
425 		if (!zend_array_is_list(input_params)) {
426 			zend_argument_value_error(ERROR_ARG_POS(2), "must be a list array");
427 			RETURN_THROWS();
428 		}
429 
430 		hash_num_elements = zend_hash_num_elements(input_params);
431 		param_count = mysql_stmt_param_count(stmt->stmt);
432 		if (hash_num_elements != param_count) {
433 			zend_argument_value_error(ERROR_ARG_POS(2), "must consist of exactly %d elements, %d present", param_count, hash_num_elements);
434 			RETURN_THROWS();
435 		}
436 
437 		params = mysqlnd_stmt_alloc_param_bind(stmt->stmt);
438 		ZEND_ASSERT(params);
439 
440 		index = 0;
441 		ZEND_HASH_FOREACH_VAL(input_params, tmp) {
442 			ZVAL_COPY_VALUE(&params[index].zv, tmp);
443 			params[index].type = MYSQL_TYPE_VAR_STRING;
444 			index++;
445 		} ZEND_HASH_FOREACH_END();
446 
447 		if (mysqlnd_stmt_bind_param(stmt->stmt, params)) {
448 			MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
449 			RETVAL_FALSE;
450 		}
451 	}
452 
453 	if (mysql_stmt_execute(stmt->stmt)) {
454 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
455 		RETVAL_FALSE;
456 	} else {
457 		RETVAL_TRUE;
458 	}
459 
460 	if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
461 		php_mysqli_report_index(stmt->query, mysqli_stmt_server_status(stmt->stmt));
462 	}
463 }
464 /* }}} */
465 
close_stmt_and_copy_errors(MY_STMT * stmt,MY_MYSQL * mysql)466 void close_stmt_and_copy_errors(MY_STMT *stmt, MY_MYSQL *mysql)
467 {
468 	/* mysql_stmt_close() clears errors, so we have to store them temporarily */
469 	MYSQLND_ERROR_INFO error_info = *stmt->stmt->data->error_info;
470 	stmt->stmt->data->error_info->error_list.head = NULL;
471 	stmt->stmt->data->error_info->error_list.tail = NULL;
472 	stmt->stmt->data->error_info->error_list.count = 0;
473 
474 	/* we also remember affected_rows which gets cleared too */
475 	uint64_t affected_rows = mysql->mysql->data->upsert_status->affected_rows;
476 
477 	mysqli_stmt_close(stmt->stmt, false);
478 	stmt->stmt = NULL;
479 	php_clear_stmt_bind(stmt);
480 
481 	/* restore error messages, but into the mysql object */
482 	zend_llist_clean(&mysql->mysql->data->error_info->error_list);
483 	*mysql->mysql->data->error_info = error_info;
484 	mysql->mysql->data->upsert_status->affected_rows = affected_rows;
485 }
486 
PHP_FUNCTION(mysqli_execute_query)487 PHP_FUNCTION(mysqli_execute_query)
488 {
489 	MY_MYSQL		*mysql;
490 	MY_STMT			*stmt;
491 	char			*query = NULL;
492 	size_t				query_len;
493 	zval			*mysql_link;
494 	HashTable	*input_params = NULL;
495 	MYSQL_RES 		*result;
496 	MYSQLI_RESOURCE	*mysqli_resource;
497 
498 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os|h!", &mysql_link, mysqli_link_class_entry, &query, &query_len, &input_params) == FAILURE) {
499 		RETURN_THROWS();
500 	}
501 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
502 
503 	stmt = (MY_STMT *)ecalloc(1,sizeof(MY_STMT));
504 
505 	if (!(stmt->stmt = mysql_stmt_init(mysql->mysql))) {
506 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
507 		efree(stmt);
508 		RETURN_FALSE;
509 	}
510 
511 	if (FAIL == mysql_stmt_prepare(stmt->stmt, query, query_len)) {
512 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
513 
514 		close_stmt_and_copy_errors(stmt, mysql);
515 		RETURN_FALSE;
516 	}
517 
518 	/* The bit below, which is copied from mysqli_prepare, is needed for bad index exceptions */
519 	/* don't initialize stmt->query with NULL, we ecalloc()-ed the memory */
520 	/* Get performance boost if reporting is switched off */
521 	if (query_len && (MyG(report_mode) & MYSQLI_REPORT_INDEX)) {
522 		stmt->query = estrdup(query);
523 	}
524 
525 	// bind-in-execute
526 	// It's very similar to the mysqli_stmt::execute, but it uses different error handling
527 	if (input_params) {
528 		zval *tmp;
529 		unsigned int index;
530 		unsigned int hash_num_elements;
531 		unsigned int param_count;
532 		MYSQLND_PARAM_BIND	*params;
533 
534 		if (!zend_array_is_list(input_params)) {
535 			mysqli_stmt_close(stmt->stmt, false);
536 			stmt->stmt = NULL;
537 			efree(stmt);
538 			zend_argument_value_error(ERROR_ARG_POS(3), "must be a list array");
539 			RETURN_THROWS();
540 		}
541 
542 		hash_num_elements = zend_hash_num_elements(input_params);
543 		param_count = mysql_stmt_param_count(stmt->stmt);
544 		if (hash_num_elements != param_count) {
545 			mysqli_stmt_close(stmt->stmt, false);
546 			stmt->stmt = NULL;
547 			efree(stmt);
548 			zend_argument_value_error(ERROR_ARG_POS(3), "must consist of exactly %d elements, %d present", param_count, hash_num_elements);
549 			RETURN_THROWS();
550 		}
551 
552 		params = mysqlnd_stmt_alloc_param_bind(stmt->stmt);
553 		ZEND_ASSERT(params);
554 
555 		index = 0;
556 		ZEND_HASH_FOREACH_VAL(input_params, tmp) {
557 			ZVAL_COPY_VALUE(&params[index].zv, tmp);
558 			params[index].type = MYSQL_TYPE_VAR_STRING;
559 			index++;
560 		} ZEND_HASH_FOREACH_END();
561 
562 		if (mysqlnd_stmt_bind_param(stmt->stmt, params)) {
563 			close_stmt_and_copy_errors(stmt, mysql);
564 			RETURN_FALSE;
565 		}
566 
567 	}
568 
569 	if (mysql_stmt_execute(stmt->stmt)) {
570 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
571 
572 		if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
573 			php_mysqli_report_index(stmt->query, mysqli_stmt_server_status(stmt->stmt));
574 		}
575 
576 		close_stmt_and_copy_errors(stmt, mysql);
577 		RETURN_FALSE;
578 	}
579 
580 	if (!mysql_stmt_field_count(stmt->stmt)) {
581 		/* no result set - not a SELECT */
582 		close_stmt_and_copy_errors(stmt, mysql);
583 		RETURN_TRUE;
584 	}
585 
586 	if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
587 		php_mysqli_report_index(stmt->query, mysqli_stmt_server_status(stmt->stmt));
588 	}
589 
590 	/* get result */
591 	if (!(result = mysqlnd_stmt_get_result(stmt->stmt))) {
592 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
593 
594 		close_stmt_and_copy_errors(stmt, mysql);
595 		RETURN_FALSE;
596 	}
597 
598 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
599 	mysqli_resource->ptr = (void *)result;
600 	mysqli_resource->status = MYSQLI_STATUS_VALID;
601 	MYSQLI_RETVAL_RESOURCE(mysqli_resource, mysqli_result_class_entry);
602 
603 	close_stmt_and_copy_errors(stmt, mysql);
604 }
605 
606 /* {{{ mixed mysqli_stmt_fetch_mysqlnd */
mysqli_stmt_fetch_mysqlnd(INTERNAL_FUNCTION_PARAMETERS)607 void mysqli_stmt_fetch_mysqlnd(INTERNAL_FUNCTION_PARAMETERS)
608 {
609 	MY_STMT		*stmt;
610 	zval		*mysql_stmt;
611 	bool	fetched_anything;
612 
613 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
614 		RETURN_THROWS();
615 	}
616 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
617 
618 	if (FAIL == mysqlnd_stmt_fetch(stmt->stmt, &fetched_anything)) {
619 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
620 		RETURN_FALSE;
621 	} else if (fetched_anything) {
622 		RETURN_TRUE;
623 	} else {
624 		RETURN_NULL();
625 	}
626 }
627 /* }}} */
628 
629 /* {{{ Fetch results from a prepared statement into the bound variables */
PHP_FUNCTION(mysqli_stmt_fetch)630 PHP_FUNCTION(mysqli_stmt_fetch)
631 {
632 	mysqli_stmt_fetch_mysqlnd(INTERNAL_FUNCTION_PARAM_PASSTHRU);
633 }
634 /* }}} */
635 
636 /* {{{  php_add_field_properties */
php_add_field_properties(zval * value,const MYSQL_FIELD * field)637 static void php_add_field_properties(zval *value, const MYSQL_FIELD *field)
638 {
639 	add_property_str(value, "name", zend_string_copy(field->sname));
640 
641 	add_property_stringl(value, "orgname", (field->org_name ? field->org_name : ""), field->org_name_length);
642 	add_property_stringl(value, "table", (field->table ? field->table : ""), field->table_length);
643 	add_property_stringl(value, "orgtable", (field->org_table ? field->org_table : ""), field->org_table_length);
644 	add_property_stringl(value, "def", (field->def ? field->def : ""), field->def_length);
645 	add_property_stringl(value, "db", (field->db ? field->db : ""), field->db_length);
646 
647 	/* FIXME: manually set the catalog to "def" due to bug in
648 	 * libmysqlclient which does not initialize field->catalog
649 	 * and in addition, the catalog is always be "def"
650 	 */
651 	add_property_string(value, "catalog", "def");
652 
653 	add_property_long(value, "max_length", 0);
654 	add_property_long(value, "length", field->length);
655 	add_property_long(value, "charsetnr", field->charsetnr);
656 	add_property_long(value, "flags", field->flags);
657 	add_property_long(value, "type", field->type);
658 	add_property_long(value, "decimals", field->decimals);
659 }
660 /* }}} */
661 
662 /* {{{ Get column information from a result and return as an object */
PHP_FUNCTION(mysqli_fetch_field)663 PHP_FUNCTION(mysqli_fetch_field)
664 {
665 	MYSQL_RES	*result;
666 	zval		*mysql_result;
667 	const MYSQL_FIELD	*field;
668 
669 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) {
670 		RETURN_THROWS();
671 	}
672 
673 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
674 
675 	if (!(field = mysql_fetch_field(result))) {
676 		RETURN_FALSE;
677 	}
678 
679 	object_init(return_value);
680 	php_add_field_properties(return_value, field);
681 }
682 /* }}} */
683 
684 /* {{{ Return array of objects containing field meta-data */
PHP_FUNCTION(mysqli_fetch_fields)685 PHP_FUNCTION(mysqli_fetch_fields)
686 {
687 	MYSQL_RES	*result;
688 	zval		*mysql_result;
689 	zval		obj;
690 
691 	unsigned int i, num_fields;
692 
693 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) {
694 		RETURN_THROWS();
695 	}
696 
697 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
698 
699 	array_init(return_value);
700 	num_fields = mysql_num_fields(result);
701 
702 	for (i = 0; i < num_fields; i++) {
703 		const MYSQL_FIELD *field = mysql_fetch_field_direct(result, i);
704 
705 		object_init(&obj);
706 
707 		php_add_field_properties(&obj, field);
708 		add_index_zval(return_value, i, &obj);
709 	}
710 }
711 /* }}} */
712 
713 /* {{{ Fetch meta-data for a single field */
PHP_FUNCTION(mysqli_fetch_field_direct)714 PHP_FUNCTION(mysqli_fetch_field_direct)
715 {
716 	MYSQL_RES	*result;
717 	zval		*mysql_result;
718 	const MYSQL_FIELD	*field;
719 	zend_long		offset;
720 
721 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_result, mysqli_result_class_entry, &offset) == FAILURE) {
722 		RETURN_THROWS();
723 	}
724 
725 	if (offset < 0) {
726 		zend_argument_value_error(ERROR_ARG_POS(2), "must be greater than or equal to 0");
727 		RETURN_THROWS();
728 	}
729 
730 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
731 
732 	if (offset >= (zend_long) mysql_num_fields(result)) {
733 		zend_argument_value_error(ERROR_ARG_POS(2), "must be less than the number of fields for this result set");
734 		RETURN_THROWS();
735 	}
736 
737 	if (!(field = mysql_fetch_field_direct(result,offset))) {
738 		RETURN_FALSE;
739 	}
740 
741 	object_init(return_value);
742 	php_add_field_properties(return_value, field);
743 }
744 /* }}} */
745 
746 /* {{{ Get the length of each output in a result */
PHP_FUNCTION(mysqli_fetch_lengths)747 PHP_FUNCTION(mysqli_fetch_lengths)
748 {
749 	MYSQL_RES		*result;
750 	zval			*mysql_result;
751 	unsigned int	i, num_fields;
752 	const size_t	*ret;
753 
754 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) {
755 		RETURN_THROWS();
756 	}
757 
758 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
759 
760 	// TODO Warning?
761 	if (!(ret = mysql_fetch_lengths(result))) {
762 		RETURN_FALSE;
763 	}
764 
765 	array_init(return_value);
766 	num_fields = mysql_num_fields(result);
767 
768 	for (i = 0; i < num_fields; i++) {
769 		add_index_long(return_value, i, ret[i]);
770 	}
771 }
772 /* }}} */
773 
774 /* {{{ Get a result row as an enumerated array */
PHP_FUNCTION(mysqli_fetch_row)775 PHP_FUNCTION(mysqli_fetch_row)
776 {
777 	php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQLI_NUM, 0);
778 }
779 /* }}} */
780 
781 /* {{{ Fetch the number of fields returned by the last query for the given link */
PHP_FUNCTION(mysqli_field_count)782 PHP_FUNCTION(mysqli_field_count)
783 {
784 	MY_MYSQL	*mysql;
785 	zval		*mysql_link;
786 
787 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
788 		RETURN_THROWS();
789 	}
790 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
791 
792 	RETURN_LONG(mysql_field_count(mysql->mysql));
793 }
794 /* }}} */
795 
796 /* {{{ Set result pointer to a specified field offset */
PHP_FUNCTION(mysqli_field_seek)797 PHP_FUNCTION(mysqli_field_seek)
798 {
799 	MYSQL_RES		*result;
800 	zval			*mysql_result;
801 	zend_long	fieldnr;
802 
803 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_result, mysqli_result_class_entry, &fieldnr) == FAILURE) {
804 		RETURN_THROWS();
805 	}
806 
807 	if (fieldnr < 0) {
808 		zend_argument_value_error(ERROR_ARG_POS(2), "must be greater than or equal to 0");
809 		RETURN_THROWS();
810 	}
811 
812 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
813 
814 	if ((uint32_t)fieldnr >= mysql_num_fields(result)) {
815 		zend_argument_value_error(ERROR_ARG_POS(2), "must be less than the number of fields for this result set");
816 		RETURN_THROWS();
817 	}
818 
819 	mysql_field_seek(result, fieldnr);
820 	RETURN_TRUE;
821 }
822 /* }}} */
823 
824 /* {{{ Get current field offset of result pointer */
PHP_FUNCTION(mysqli_field_tell)825 PHP_FUNCTION(mysqli_field_tell)
826 {
827 	MYSQL_RES	*result;
828 	zval		*mysql_result;
829 
830 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) {
831 		RETURN_THROWS();
832 	}
833 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
834 
835 	RETURN_LONG(mysql_field_tell(result));
836 }
837 /* }}} */
838 
839 /* {{{ Free query result memory for the given result handle */
PHP_FUNCTION(mysqli_free_result)840 PHP_FUNCTION(mysqli_free_result)
841 {
842 	MYSQL_RES	*result;
843 	zval		*mysql_result;
844 
845 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) {
846 		RETURN_THROWS();
847 	}
848 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
849 
850 	mysqli_free_result(result, false);
851 	MYSQLI_CLEAR_RESOURCE(mysql_result);
852 }
853 /* }}} */
854 
855 /* {{{ Get MySQL client info */
PHP_FUNCTION(mysqli_get_client_info)856 PHP_FUNCTION(mysqli_get_client_info)
857 {
858 	if (getThis()) {
859 		if (zend_parse_parameters_none() == FAILURE) {
860 			RETURN_THROWS();
861 		}
862 	} else {
863 		zval *mysql_link;
864 
865 		if (zend_parse_parameters(ZEND_NUM_ARGS(), "|O!", &mysql_link, mysqli_link_class_entry) == FAILURE) {
866 			RETURN_THROWS();
867 		}
868 
869 		if (ZEND_NUM_ARGS()) {
870 			php_error_docref(NULL, E_DEPRECATED, "Passing connection object as an argument is deprecated");
871 		}
872 	}
873 
874 	RETURN_STRING(mysql_get_client_info());
875 }
876 /* }}} */
877 
878 /* {{{ Get MySQL client info */
PHP_FUNCTION(mysqli_get_client_version)879 PHP_FUNCTION(mysqli_get_client_version)
880 {
881 	if (zend_parse_parameters_none() == FAILURE) {
882 		RETURN_THROWS();
883 	}
884 
885 	RETURN_LONG((zend_long)mysql_get_client_version());
886 }
887 /* }}} */
888 
889 /* {{{ Get MySQL host info */
PHP_FUNCTION(mysqli_get_host_info)890 PHP_FUNCTION(mysqli_get_host_info)
891 {
892 	MY_MYSQL	*mysql;
893 	zval		*mysql_link = NULL;
894 
895 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
896 		RETURN_THROWS();
897 	}
898 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
899 	RETURN_STRING((mysql->mysql->data->host_info) ? mysql->mysql->data->host_info : "");
900 }
901 /* }}} */
902 
903 /* {{{ Get MySQL protocol information */
PHP_FUNCTION(mysqli_get_proto_info)904 PHP_FUNCTION(mysqli_get_proto_info)
905 {
906 	MY_MYSQL	*mysql;
907 	zval		*mysql_link = NULL;
908 
909 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
910 		RETURN_THROWS();
911 	}
912 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
913 	RETURN_LONG(mysql_get_proto_info(mysql->mysql));
914 }
915 /* }}} */
916 
917 /* {{{ Get MySQL server info */
PHP_FUNCTION(mysqli_get_server_info)918 PHP_FUNCTION(mysqli_get_server_info)
919 {
920 	MY_MYSQL	*mysql;
921 	zval		*mysql_link = NULL;
922 
923 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
924 		RETURN_THROWS();
925 	}
926 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
927 
928 	RETURN_STRING(mysql_get_server_info(mysql->mysql));
929 }
930 /* }}} */
931 
932 /* {{{ Return the MySQL version for the server referenced by the given link */
PHP_FUNCTION(mysqli_get_server_version)933 PHP_FUNCTION(mysqli_get_server_version)
934 {
935 	MY_MYSQL	*mysql;
936 	zval		*mysql_link = NULL;
937 
938 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
939 		RETURN_THROWS();
940 	}
941 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
942 
943 	RETURN_LONG(mysql_get_server_version(mysql->mysql));
944 }
945 /* }}} */
946 
947 /* {{{ Get information about the most recent query */
PHP_FUNCTION(mysqli_info)948 PHP_FUNCTION(mysqli_info)
949 {
950 	MY_MYSQL	*mysql;
951 	zval		*mysql_link = NULL;
952 	const char	*info;
953 
954 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
955 		RETURN_THROWS();
956 	}
957 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
958 
959 	info = mysql_info(mysql->mysql);
960 	if (info) {
961 		RETURN_STRING(info);
962 	}
963 }
964 /* }}} */
965 
966 /* {{{ php_mysqli_init() */
php_mysqli_init(INTERNAL_FUNCTION_PARAMETERS,bool is_method)967 void php_mysqli_init(INTERNAL_FUNCTION_PARAMETERS, bool is_method)
968 {
969 	MYSQLI_RESOURCE *mysqli_resource;
970 	MY_MYSQL *mysql;
971 
972 	if (zend_parse_parameters_none() == FAILURE) {
973 		RETURN_THROWS();
974 	}
975 
976 	if (is_method && (Z_MYSQLI_P(getThis()))->ptr) {
977 		return;
978 	}
979 
980 	mysql = (MY_MYSQL *)ecalloc(1, sizeof(MY_MYSQL));
981 
982 	/*
983 	  We create always persistent, as if the user want to connect
984 	  to p:somehost, we can't convert the handle then
985 	*/
986 	if (!(mysql->mysql = mysqlnd_init(MYSQLND_CLIENT_NO_FLAG, true)))
987 	{
988 		efree(mysql);
989 		RETURN_FALSE;
990 	}
991 
992 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
993 	mysqli_resource->ptr = (void *)mysql;
994 	mysqli_resource->status = MYSQLI_STATUS_INITIALIZED;
995 
996 	if (!is_method) {
997 		MYSQLI_RETVAL_RESOURCE(mysqli_resource, mysqli_link_class_entry);
998 	} else {
999 		(Z_MYSQLI_P(getThis()))->ptr = mysqli_resource;
1000 	}
1001 }
1002 /* }}} */
1003 
1004 /* {{{ Initialize mysqli and return a resource for use with mysql_real_connect */
PHP_FUNCTION(mysqli_init)1005 PHP_FUNCTION(mysqli_init)
1006 {
1007 	php_mysqli_init(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
1008 }
1009 /* }}} */
1010 
1011 /* {{{ Get the ID generated from the previous INSERT operation */
PHP_FUNCTION(mysqli_insert_id)1012 PHP_FUNCTION(mysqli_insert_id)
1013 {
1014 	MY_MYSQL		*mysql;
1015 	my_ulonglong	rc;
1016 	zval			*mysql_link;
1017 
1018 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1019 		RETURN_THROWS();
1020 	}
1021 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1022 	rc = mysql_insert_id(mysql->mysql);
1023 	MYSQLI_RETURN_LONG_INT(rc)
1024 }
1025 /* }}} */
1026 
1027 /* {{{ Kill a mysql process on the server */
PHP_FUNCTION(mysqli_kill)1028 PHP_FUNCTION(mysqli_kill)
1029 {
1030 	MY_MYSQL	*mysql;
1031 	zval		*mysql_link;
1032 	zend_long		processid;
1033 
1034 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_link, mysqli_link_class_entry, &processid) == FAILURE) {
1035 		RETURN_THROWS();
1036 	}
1037 
1038 	if (processid <= 0) {
1039 		zend_argument_value_error(ERROR_ARG_POS(2), "must be greater than 0");
1040 		RETURN_THROWS();
1041 	}
1042 
1043 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1044 
1045 	if (mysql_kill(mysql->mysql, processid)) {
1046 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1047 		RETURN_FALSE;
1048 	}
1049 	RETURN_TRUE;
1050 }
1051 /* }}} */
1052 
1053 /* {{{ check if there any more query results from a multi query */
PHP_FUNCTION(mysqli_more_results)1054 PHP_FUNCTION(mysqli_more_results)
1055 {
1056 	MY_MYSQL	*mysql;
1057 	zval		*mysql_link;
1058 
1059 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1060 		RETURN_THROWS();
1061 	}
1062 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1063 
1064 	RETURN_BOOL(mysql_more_results(mysql->mysql));
1065 }
1066 /* }}} */
1067 
1068 /* {{{ read next result from multi_query */
PHP_FUNCTION(mysqli_next_result)1069 PHP_FUNCTION(mysqli_next_result) {
1070 	MY_MYSQL	*mysql;
1071 	zval		*mysql_link;
1072 
1073 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1074 		RETURN_THROWS();
1075 	}
1076 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1077 
1078 	if (mysql_next_result(mysql->mysql)) {
1079 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1080 		RETURN_FALSE;
1081 	}
1082 	RETURN_TRUE;
1083 }
1084 /* }}} */
1085 
1086 
1087 /* {{{ check if there any more query results from a multi query */
PHP_FUNCTION(mysqli_stmt_more_results)1088 PHP_FUNCTION(mysqli_stmt_more_results)
1089 {
1090 	MY_STMT		*stmt;
1091 	zval		*mysql_stmt;
1092 
1093 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
1094 		RETURN_THROWS();
1095 	}
1096 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1097 
1098 	RETURN_BOOL(mysqlnd_stmt_more_results(stmt->stmt));
1099 }
1100 /* }}} */
1101 
1102 /* {{{ read next result from multi_query */
PHP_FUNCTION(mysqli_stmt_next_result)1103 PHP_FUNCTION(mysqli_stmt_next_result) {
1104 	MY_STMT		*stmt;
1105 	zval		*mysql_stmt;
1106 
1107 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
1108 		RETURN_THROWS();
1109 	}
1110 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1111 
1112 	if (mysql_stmt_next_result(stmt->stmt)) {
1113 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
1114 		RETURN_FALSE;
1115 	}
1116 	RETURN_TRUE;
1117 }
1118 /* }}} */
1119 
1120 /* {{{ Get number of fields in result */
PHP_FUNCTION(mysqli_num_fields)1121 PHP_FUNCTION(mysqli_num_fields)
1122 {
1123 	MYSQL_RES	*result;
1124 	zval		*mysql_result;
1125 
1126 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) {
1127 		RETURN_THROWS();
1128 	}
1129 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
1130 
1131 	RETURN_LONG(mysql_num_fields(result));
1132 }
1133 /* }}} */
1134 
1135 /* {{{ Get number of rows in result */
PHP_FUNCTION(mysqli_num_rows)1136 PHP_FUNCTION(mysqli_num_rows)
1137 {
1138 	MYSQL_RES	*result;
1139 	zval		*mysql_result;
1140 
1141 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) {
1142 		RETURN_THROWS();
1143 	}
1144 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
1145 
1146 	if (mysqli_result_is_unbuffered_and_not_everything_is_fetched(result)) {
1147 		zend_throw_error(NULL, "mysqli_num_rows() cannot be used in MYSQLI_USE_RESULT mode");
1148 		RETURN_THROWS();
1149 	}
1150 
1151 	MYSQLI_RETURN_LONG_INT(mysql_num_rows(result));
1152 }
1153 /* }}} */
1154 
1155 /* {{{ mysqli_options_get_option_zval_type */
mysqli_options_get_option_zval_type(int option)1156 static int mysqli_options_get_option_zval_type(int option)
1157 {
1158 	switch (option) {
1159 		case MYSQLND_OPT_NET_CMD_BUFFER_SIZE:
1160 		case MYSQLND_OPT_NET_READ_BUFFER_SIZE:
1161 		case MYSQLND_OPT_INT_AND_FLOAT_NATIVE:
1162 		case MYSQL_OPT_CONNECT_TIMEOUT:
1163 		case MYSQL_OPT_LOCAL_INFILE:
1164 		case MYSQL_OPT_NAMED_PIPE:
1165 		case MYSQL_OPT_PROTOCOL:
1166 		case MYSQL_OPT_READ_TIMEOUT:
1167 		case MYSQL_OPT_WRITE_TIMEOUT:
1168 		case MYSQL_OPT_SSL_VERIFY_SERVER_CERT:
1169 		case MYSQL_OPT_COMPRESS:
1170 		case MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS:
1171 			return IS_LONG;
1172 
1173 		case MYSQL_READ_DEFAULT_FILE:
1174 		case MYSQL_READ_DEFAULT_GROUP:
1175 		case MYSQL_INIT_COMMAND:
1176 		case MYSQL_SET_CHARSET_NAME:
1177 		case MYSQL_SERVER_PUBLIC_KEY:
1178 		case MYSQL_OPT_LOAD_DATA_LOCAL_DIR:
1179 			return IS_STRING;
1180 
1181 		default:
1182 			return IS_NULL;
1183 	}
1184 }
1185 /* }}} */
1186 
1187 /* {{{ Set options */
PHP_FUNCTION(mysqli_options)1188 PHP_FUNCTION(mysqli_options)
1189 {
1190 	MY_MYSQL		*mysql;
1191 	zval			*mysql_link = NULL;
1192 	zval			*mysql_value;
1193 	zend_long			mysql_option;
1194 	unsigned int	l_value;
1195 	zend_long			ret;
1196 	int				expected_type;
1197 
1198 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Olz", &mysql_link, mysqli_link_class_entry, &mysql_option, &mysql_value) == FAILURE) {
1199 		RETURN_THROWS();
1200 	}
1201 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_INITIALIZED);
1202 
1203 	expected_type = mysqli_options_get_option_zval_type(mysql_option);
1204 	if (expected_type != Z_TYPE_P(mysql_value)) {
1205 		switch (expected_type) {
1206 			case IS_STRING:
1207 				if (!try_convert_to_string(mysql_value)) {
1208 					RETURN_THROWS();
1209 				}
1210 				break;
1211 			case IS_LONG:
1212 				convert_to_long(mysql_value);
1213 				break;
1214 			default:
1215 				break;
1216 		}
1217 	}
1218 	switch (expected_type) {
1219 		case IS_STRING:
1220 			if ((ret = mysql_options(mysql->mysql, mysql_option, Z_STRVAL_P(mysql_value)))) {
1221 				MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1222 			}
1223 			break;
1224 		case IS_LONG:
1225 			l_value = Z_LVAL_P(mysql_value);
1226 			if ((ret = mysql_options(mysql->mysql, mysql_option, (char *)&l_value))) {
1227 				MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1228 			}
1229 			break;
1230 		default:
1231 			ret = 1;
1232 			break;
1233 	}
1234 
1235 	RETURN_BOOL(!ret);
1236 }
1237 /* }}} */
1238 
1239 /* {{{ Ping a server connection or reconnect if there is no connection */
PHP_FUNCTION(mysqli_ping)1240 PHP_FUNCTION(mysqli_ping)
1241 {
1242 	MY_MYSQL	*mysql;
1243 	zval		*mysql_link;
1244 	zend_long		rc;
1245 
1246 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1247 		RETURN_THROWS();
1248 	}
1249 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1250 	rc = mysql_ping(mysql->mysql);
1251 	MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1252 
1253 	RETURN_BOOL(!rc);
1254 }
1255 /* }}} */
1256 
1257 /* {{{ Prepare a SQL statement for execution */
PHP_FUNCTION(mysqli_prepare)1258 PHP_FUNCTION(mysqli_prepare)
1259 {
1260 	MY_MYSQL		*mysql;
1261 	MY_STMT			*stmt;
1262 	char			*query = NULL;
1263 	size_t				query_len;
1264 	zval			*mysql_link;
1265 	MYSQLI_RESOURCE	*mysqli_resource;
1266 
1267 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os",&mysql_link, mysqli_link_class_entry, &query, &query_len) == FAILURE) {
1268 		RETURN_THROWS();
1269 	}
1270 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1271 
1272 	stmt = (MY_STMT *)ecalloc(1,sizeof(MY_STMT));
1273 
1274 	if ((stmt->stmt = mysql_stmt_init(mysql->mysql))) {
1275 		if (mysql_stmt_prepare(stmt->stmt, query, query_len)) {
1276 			/* mysql_stmt_close() clears errors, so we have to store them temporarily */
1277 			MYSQLND_ERROR_INFO error_info = *mysql->mysql->data->error_info;
1278 			mysql->mysql->data->error_info->error_list.head = NULL;
1279 			mysql->mysql->data->error_info->error_list.tail = NULL;
1280 			mysql->mysql->data->error_info->error_list.count = 0;
1281 			mysqli_stmt_close(stmt->stmt, false);
1282 			stmt->stmt = NULL;
1283 
1284 			/* restore error messages */
1285 			zend_llist_clean(&mysql->mysql->data->error_info->error_list);
1286 			*mysql->mysql->data->error_info = error_info;
1287 		}
1288 	}
1289 
1290 	/* don't initialize stmt->query with NULL, we ecalloc()-ed the memory */
1291 	/* Get performance boost if reporting is switched off */
1292 	if (stmt->stmt && query_len && (MyG(report_mode) & MYSQLI_REPORT_INDEX)) {
1293 		stmt->query = estrdup(query);
1294 	}
1295 
1296 	/* don't join to the previous if because it won't work if mysql_stmt_prepare_fails */
1297 	if (!stmt->stmt) {
1298 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1299 		efree(stmt);
1300 		RETURN_FALSE;
1301 	}
1302 
1303 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
1304 	mysqli_resource->ptr = (void *)stmt;
1305 
1306 	/* change status */
1307 	mysqli_resource->status = MYSQLI_STATUS_VALID;
1308 	MYSQLI_RETVAL_RESOURCE(mysqli_resource, mysqli_stmt_class_entry);
1309 }
1310 /* }}} */
1311 
1312 /* {{{ Open a connection to a mysql server */
PHP_FUNCTION(mysqli_real_connect)1313 PHP_FUNCTION(mysqli_real_connect)
1314 {
1315 	mysqli_common_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, true, false);
1316 }
1317 /* }}} */
1318 
1319 /* {{{ Binary-safe version of mysql_query() */
PHP_FUNCTION(mysqli_real_query)1320 PHP_FUNCTION(mysqli_real_query)
1321 {
1322 	MY_MYSQL	*mysql;
1323 	zval		*mysql_link;
1324 	char		*query = NULL;
1325 	size_t		query_len;
1326 
1327 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_link, mysqli_link_class_entry, &query, &query_len) == FAILURE) {
1328 		RETURN_THROWS();
1329 	}
1330 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1331 
1332 	MYSQLI_DISABLE_MQ; /* disable multi statements/queries */
1333 
1334 	if (mysql_real_query(mysql->mysql, query, query_len)) {
1335 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1336 		RETURN_FALSE;
1337 	}
1338 
1339 	if (!mysql_field_count(mysql->mysql)) {
1340 		if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
1341 			php_mysqli_report_index(query, mysqli_server_status(mysql->mysql));
1342 		}
1343 	}
1344 
1345 	RETURN_TRUE;
1346 }
1347 /* }}} */
1348 
1349 # define mysql_real_escape_string_quote(mysql, to, from, length, quote) \
1350 	mysql_real_escape_string(mysql, to, from, length)
1351 
PHP_FUNCTION(mysqli_real_escape_string)1352 PHP_FUNCTION(mysqli_real_escape_string) {
1353 	MY_MYSQL	*mysql;
1354 	zval		*mysql_link = NULL;
1355 	char		*escapestr;
1356 	size_t			escapestr_len;
1357 	zend_string *newstr;
1358 
1359 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_link, mysqli_link_class_entry, &escapestr, &escapestr_len) == FAILURE) {
1360 		RETURN_THROWS();
1361 	}
1362 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1363 
1364 	newstr = zend_string_safe_alloc(2, escapestr_len, 0, 0);
1365 	ZSTR_LEN(newstr) = mysql_real_escape_string_quote(mysql->mysql, ZSTR_VAL(newstr), escapestr, escapestr_len, '\'');
1366 	newstr = zend_string_truncate(newstr, ZSTR_LEN(newstr), 0);
1367 
1368 	RETURN_NEW_STR(newstr);
1369 }
1370 
1371 /* {{{ Undo actions from current transaction */
PHP_FUNCTION(mysqli_rollback)1372 PHP_FUNCTION(mysqli_rollback)
1373 {
1374 	MY_MYSQL	*mysql;
1375 	zval		*mysql_link;
1376 	zend_long		flags = TRANS_COR_NO_OPT;
1377 	char *		name = NULL;
1378 	size_t			name_len = 0;
1379 
1380 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|ls!", &mysql_link, mysqli_link_class_entry, &flags, &name, &name_len) == FAILURE) {
1381 		RETURN_THROWS();
1382 	}
1383 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1384 
1385 
1386 	if (FAIL == mysqlnd_rollback(mysql->mysql, flags, name)) {
1387 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1388 		RETURN_FALSE;
1389 	}
1390 	RETURN_TRUE;
1391 }
1392 /* }}} */
1393 
1394 /* {{{ */
PHP_FUNCTION(mysqli_stmt_send_long_data)1395 PHP_FUNCTION(mysqli_stmt_send_long_data)
1396 {
1397 	MY_STMT *stmt;
1398 	zval	*mysql_stmt;
1399 	char	*data;
1400 	zend_long	param_nr;
1401 	size_t		data_len;
1402 
1403 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ols", &mysql_stmt, mysqli_stmt_class_entry, &param_nr, &data, &data_len) == FAILURE) {
1404 		RETURN_THROWS();
1405 	}
1406 
1407 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1408 
1409 	if (param_nr < 0) {
1410 		zend_argument_value_error(ERROR_ARG_POS(2), "must be greater than or equal to 0");
1411 		RETURN_THROWS();
1412 	}
1413 
1414 	if (mysql_stmt_send_long_data(stmt->stmt, param_nr, data, data_len)) {
1415 		RETURN_FALSE;
1416 	}
1417 	RETURN_TRUE;
1418 }
1419 /* }}} */
1420 
1421 /* {{{ Return the number of rows affected in the last query for the given link. */
PHP_FUNCTION(mysqli_stmt_affected_rows)1422 PHP_FUNCTION(mysqli_stmt_affected_rows)
1423 {
1424 	MY_STMT			*stmt;
1425 	zval			*mysql_stmt;
1426 	my_ulonglong	rc;
1427 
1428 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
1429 		RETURN_THROWS();
1430 	}
1431 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1432 
1433 	rc = mysql_stmt_affected_rows(stmt->stmt);
1434 	if (rc == (my_ulonglong) -1) {
1435 		RETURN_LONG(-1);
1436 	}
1437 	MYSQLI_RETURN_LONG_INT(rc)
1438 }
1439 /* }}} */
1440 
1441 /* {{{ Close statement */
PHP_FUNCTION(mysqli_stmt_close)1442 PHP_FUNCTION(mysqli_stmt_close)
1443 {
1444 	MY_STMT		*stmt;
1445 	zval		*mysql_stmt;
1446 
1447 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
1448 		RETURN_THROWS();
1449 	}
1450 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1451 
1452 	mysqli_stmt_close(stmt->stmt, false);
1453 	stmt->stmt = NULL;
1454 	php_clear_stmt_bind(stmt);
1455 	MYSQLI_CLEAR_RESOURCE(mysql_stmt);
1456 	RETURN_TRUE;
1457 }
1458 /* }}} */
1459 
1460 /* {{{ Move internal result pointer */
PHP_FUNCTION(mysqli_stmt_data_seek)1461 PHP_FUNCTION(mysqli_stmt_data_seek)
1462 {
1463 	MY_STMT		*stmt;
1464 	zval		*mysql_stmt;
1465 	zend_long		offset;
1466 
1467 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_stmt, mysqli_stmt_class_entry, &offset) == FAILURE) {
1468 		RETURN_THROWS();
1469 	}
1470 
1471 	if (offset < 0) {
1472 		zend_argument_value_error(ERROR_ARG_POS(2), "must be greater than or equal to 0");
1473 		RETURN_THROWS();
1474 	}
1475 
1476 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1477 
1478 	mysql_stmt_data_seek(stmt->stmt, offset);
1479 }
1480 /* }}} */
1481 
1482 /* {{{ Return the number of result columns for the given statement */
PHP_FUNCTION(mysqli_stmt_field_count)1483 PHP_FUNCTION(mysqli_stmt_field_count)
1484 {
1485 	MY_STMT		*stmt;
1486 	zval		*mysql_stmt;
1487 
1488 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
1489 		RETURN_THROWS();
1490 	}
1491 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1492 
1493 	RETURN_LONG(mysql_stmt_field_count(stmt->stmt));
1494 }
1495 /* }}} */
1496 
1497 /* {{{ Free stored result memory for the given statement handle */
PHP_FUNCTION(mysqli_stmt_free_result)1498 PHP_FUNCTION(mysqli_stmt_free_result)
1499 {
1500 	MY_STMT		*stmt;
1501 	zval		*mysql_stmt;
1502 
1503 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
1504 		RETURN_THROWS();
1505 	}
1506 
1507 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1508 
1509 	mysql_stmt_free_result(stmt->stmt);
1510 }
1511 /* }}} */
1512 
1513 /* {{{ Get the ID generated from the previous INSERT operation */
PHP_FUNCTION(mysqli_stmt_insert_id)1514 PHP_FUNCTION(mysqli_stmt_insert_id)
1515 {
1516 	MY_STMT			*stmt;
1517 	my_ulonglong	rc;
1518 	zval			*mysql_stmt;
1519 
1520 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
1521 		RETURN_THROWS();
1522 	}
1523 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1524 	rc = mysql_stmt_insert_id(stmt->stmt);
1525 	MYSQLI_RETURN_LONG_INT(rc)
1526 }
1527 /* }}} */
1528 
1529 /* {{{ Return the number of parameter for the given statement */
PHP_FUNCTION(mysqli_stmt_param_count)1530 PHP_FUNCTION(mysqli_stmt_param_count)
1531 {
1532 	MY_STMT		*stmt;
1533 	zval		*mysql_stmt;
1534 
1535 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
1536 		RETURN_THROWS();
1537 	}
1538 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1539 
1540 	RETURN_LONG(mysql_stmt_param_count(stmt->stmt));
1541 }
1542 /* }}} */
1543 
1544 /* {{{ reset a prepared statement */
PHP_FUNCTION(mysqli_stmt_reset)1545 PHP_FUNCTION(mysqli_stmt_reset)
1546 {
1547 	MY_STMT		*stmt;
1548 	zval		*mysql_stmt;
1549 
1550 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
1551 		RETURN_THROWS();
1552 	}
1553 
1554 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1555 
1556 	if (mysql_stmt_reset(stmt->stmt)) {
1557 		RETURN_FALSE;
1558 	}
1559 	RETURN_TRUE;
1560 }
1561 /* }}} */
1562 
1563 /* {{{ Return the number of rows in statements result set */
PHP_FUNCTION(mysqli_stmt_num_rows)1564 PHP_FUNCTION(mysqli_stmt_num_rows)
1565 {
1566 	MY_STMT			*stmt;
1567 	zval			*mysql_stmt;
1568 	my_ulonglong	rc;
1569 
1570 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
1571 		RETURN_THROWS();
1572 	}
1573 
1574 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1575 
1576 	rc = mysql_stmt_num_rows(stmt->stmt);
1577 	MYSQLI_RETURN_LONG_INT(rc)
1578 }
1579 /* }}} */
1580 
1581 /* {{{ Select a MySQL database */
PHP_FUNCTION(mysqli_select_db)1582 PHP_FUNCTION(mysqli_select_db)
1583 {
1584 	MY_MYSQL	*mysql;
1585 	zval		*mysql_link;
1586 	char		*dbname;
1587 	size_t			dbname_len;
1588 
1589 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_link, mysqli_link_class_entry, &dbname, &dbname_len) == FAILURE) {
1590 		RETURN_THROWS();
1591 	}
1592 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1593 
1594 	if (mysql_select_db(mysql->mysql, dbname)) {
1595 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1596 		RETURN_FALSE;
1597 	}
1598 	RETURN_TRUE;
1599 }
1600 /* }}} */
1601 
1602 /* {{{ Returns the SQLSTATE error from previous MySQL operation */
PHP_FUNCTION(mysqli_sqlstate)1603 PHP_FUNCTION(mysqli_sqlstate)
1604 {
1605 	MY_MYSQL	*mysql;
1606 	zval		*mysql_link;
1607 
1608 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1609 		RETURN_THROWS();
1610 	}
1611 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1612 	RETURN_STRING(mysql_sqlstate(mysql->mysql));
1613 }
1614 /* }}} */
1615 
1616 /* {{{ */
PHP_FUNCTION(mysqli_ssl_set)1617 PHP_FUNCTION(mysqli_ssl_set)
1618 {
1619 	MY_MYSQL	*mysql;
1620 	zval		*mysql_link;
1621 	char		*ssl_parm[5];
1622 	size_t			ssl_parm_len[5], i;
1623 
1624 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os!s!s!s!s!", &mysql_link, mysqli_link_class_entry, &ssl_parm[0], &ssl_parm_len[0], &ssl_parm[1], &ssl_parm_len[1], &ssl_parm[2], &ssl_parm_len[2], &ssl_parm[3], &ssl_parm_len[3], &ssl_parm[4], &ssl_parm_len[4])   == FAILURE) {
1625 		RETURN_THROWS();
1626 	}
1627 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_INITIALIZED);
1628 
1629 	for (i = 0; i < 5; i++) {
1630 		if (!ssl_parm_len[i]) {
1631 			ssl_parm[i] = NULL;
1632 		}
1633 	}
1634 
1635 	mysql_ssl_set(mysql->mysql, ssl_parm[0], ssl_parm[1], ssl_parm[2], ssl_parm[3], ssl_parm[4]);
1636 
1637 	RETURN_TRUE;
1638 }
1639 /* }}} */
1640 
1641 /* {{{ Get current system status */
PHP_FUNCTION(mysqli_stat)1642 PHP_FUNCTION(mysqli_stat)
1643 {
1644 	MY_MYSQL	*mysql;
1645 	zval		*mysql_link;
1646 	zend_string *stat;
1647 
1648 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1649 		RETURN_THROWS();
1650 	}
1651 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1652 
1653 	if (mysqlnd_stat(mysql->mysql, &stat) == PASS)
1654 	{
1655 		RETURN_STR(stat);
1656 	} else {
1657 		RETURN_FALSE;
1658 	}
1659 }
1660 
1661 /* }}} */
1662 
1663 /* {{{ Flush tables or caches, or reset replication server information */
PHP_FUNCTION(mysqli_refresh)1664 PHP_FUNCTION(mysqli_refresh)
1665 {
1666 	MY_MYSQL *mysql;
1667 	zval *mysql_link = NULL;
1668 	zend_long options;
1669 
1670 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_link, mysqli_link_class_entry, &options) == FAILURE) {
1671 		RETURN_THROWS();
1672 	}
1673 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_INITIALIZED);
1674 	RETURN_BOOL(!mysql_refresh(mysql->mysql, (uint8_t) options));
1675 }
1676 /* }}} */
1677 
1678 /* {{{ */
PHP_FUNCTION(mysqli_stmt_attr_set)1679 PHP_FUNCTION(mysqli_stmt_attr_set)
1680 {
1681 	MY_STMT	*stmt;
1682 	zval	*mysql_stmt;
1683 	zend_long	mode_in;
1684 	my_bool mode_b;
1685 	unsigned long	mode;
1686 	zend_long	attr;
1687 	void	*mode_p;
1688 
1689 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oll", &mysql_stmt, mysqli_stmt_class_entry, &attr, &mode_in) == FAILURE) {
1690 		RETURN_THROWS();
1691 	}
1692 
1693 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1694 
1695 	switch (attr) {
1696 	case STMT_ATTR_UPDATE_MAX_LENGTH:
1697 		if (mode_in != 0 && mode_in != 1) {
1698 			zend_argument_value_error(ERROR_ARG_POS(3), "must be 0 or 1 for attribute MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH");
1699 			RETURN_THROWS();
1700 		}
1701 		mode_b = (my_bool) mode_in;
1702 		mode_p = &mode_b;
1703 		break;
1704 	case STMT_ATTR_CURSOR_TYPE:
1705 		switch (mode_in) {
1706 			case CURSOR_TYPE_NO_CURSOR:
1707 			case CURSOR_TYPE_READ_ONLY:
1708 				break;
1709 			default:
1710 				zend_argument_value_error(ERROR_ARG_POS(3), "must be one of the MYSQLI_CURSOR_TYPE_* constants "
1711 					"for attribute MYSQLI_STMT_ATTR_CURSOR_TYPE");
1712 				RETURN_THROWS();
1713 		}
1714 		mode = mode_in;
1715 		mode_p = &mode;
1716 		break;
1717 	default:
1718 		zend_argument_value_error(ERROR_ARG_POS(2), "must be either "
1719 			"MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH or MYSQLI_STMT_ATTR_CURSOR_TYPE");
1720 		RETURN_THROWS();
1721 	}
1722 
1723 	if (FAIL == mysql_stmt_attr_set(stmt->stmt, attr, mode_p)) {
1724 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
1725 		RETURN_FALSE;
1726 	}
1727 	RETURN_TRUE;
1728 }
1729 /* }}} */
1730 
1731 /* {{{ */
PHP_FUNCTION(mysqli_stmt_attr_get)1732 PHP_FUNCTION(mysqli_stmt_attr_get)
1733 {
1734 	MY_STMT	*stmt;
1735 	zval	*mysql_stmt;
1736 	unsigned long	value = 0;
1737 	zend_long	attr;
1738 	int		rc;
1739 
1740 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_stmt, mysqli_stmt_class_entry, &attr) == FAILURE) {
1741 		RETURN_THROWS();
1742 	}
1743 
1744 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1745 
1746 	if ((rc = mysql_stmt_attr_get(stmt->stmt, attr, &value))) {
1747 		/* Success corresponds to 0 return value and a non-zero value
1748 		 * should only happen if the attr/option is unknown */
1749 		zend_argument_value_error(ERROR_ARG_POS(2), "must be either "
1750 			"MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH or MYSQLI_STMT_ATTR_CURSOR_TYPE");
1751 		RETURN_THROWS();
1752 	}
1753 
1754 	if (attr == STMT_ATTR_UPDATE_MAX_LENGTH)
1755 		value = (my_bool)value;
1756 
1757 	RETURN_LONG((unsigned long)value);
1758 }
1759 /* }}} */
1760 
1761 /* {{{ */
PHP_FUNCTION(mysqli_stmt_errno)1762 PHP_FUNCTION(mysqli_stmt_errno)
1763 {
1764 	MY_STMT	*stmt;
1765 	zval	*mysql_stmt;
1766 
1767 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
1768 		RETURN_THROWS();
1769 	}
1770 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_INITIALIZED);
1771 
1772 	RETURN_LONG(mysql_stmt_errno(stmt->stmt));
1773 }
1774 /* }}} */
1775 
1776 /* {{{ */
PHP_FUNCTION(mysqli_stmt_error)1777 PHP_FUNCTION(mysqli_stmt_error)
1778 {
1779 	MY_STMT	*stmt;
1780 	zval 	*mysql_stmt;
1781 
1782 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
1783 		RETURN_THROWS();
1784 	}
1785 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_INITIALIZED);
1786 
1787 	RETURN_STRING(mysql_stmt_error(stmt->stmt));
1788 }
1789 /* }}} */
1790 
1791 /* {{{ Initialize statement object */
PHP_FUNCTION(mysqli_stmt_init)1792 PHP_FUNCTION(mysqli_stmt_init)
1793 {
1794 	MY_MYSQL		*mysql;
1795 	MY_STMT			*stmt;
1796 	zval			*mysql_link;
1797 	MYSQLI_RESOURCE	*mysqli_resource;
1798 
1799 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",&mysql_link, mysqli_link_class_entry) == FAILURE) {
1800 		RETURN_THROWS();
1801 	}
1802 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1803 
1804 	stmt = (MY_STMT *)ecalloc(1,sizeof(MY_STMT));
1805 
1806 	if (!(stmt->stmt = mysql_stmt_init(mysql->mysql))) {
1807 		efree(stmt);
1808 		RETURN_FALSE;
1809 	}
1810 
1811 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
1812 	mysqli_resource->status = MYSQLI_STATUS_INITIALIZED;
1813 	mysqli_resource->ptr = (void *)stmt;
1814 	MYSQLI_RETVAL_RESOURCE(mysqli_resource, mysqli_stmt_class_entry);
1815 }
1816 /* }}} */
1817 
1818 /* {{{ prepare server side statement with query */
PHP_FUNCTION(mysqli_stmt_prepare)1819 PHP_FUNCTION(mysqli_stmt_prepare)
1820 {
1821 	MY_STMT	*stmt;
1822 	zval 	*mysql_stmt;
1823 	char	*query;
1824 	size_t		query_len;
1825 
1826 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_stmt, mysqli_stmt_class_entry, &query, &query_len) == FAILURE) {
1827 		RETURN_THROWS();
1828 	}
1829 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_INITIALIZED);
1830 
1831 	if (mysql_stmt_prepare(stmt->stmt, query, query_len)) {
1832 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
1833 		RETURN_FALSE;
1834 	}
1835 	/* change status */
1836 	MYSQLI_SET_STATUS(mysql_stmt, MYSQLI_STATUS_VALID);
1837 	RETURN_TRUE;
1838 }
1839 /* }}} */
1840 
1841 /* {{{ return result set from statement */
PHP_FUNCTION(mysqli_stmt_result_metadata)1842 PHP_FUNCTION(mysqli_stmt_result_metadata)
1843 {
1844 	MY_STMT			*stmt;
1845 	MYSQL_RES		*result;
1846 	zval			*mysql_stmt;
1847 	MYSQLI_RESOURCE	*mysqli_resource;
1848 
1849 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
1850 		RETURN_THROWS();
1851 	}
1852 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1853 
1854 	if (!(result = mysql_stmt_result_metadata(stmt->stmt))){
1855 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
1856 		RETURN_FALSE;
1857 	}
1858 
1859 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
1860 	mysqli_resource->ptr = (void *)result;
1861 	mysqli_resource->status = MYSQLI_STATUS_VALID;
1862 	MYSQLI_RETVAL_RESOURCE(mysqli_resource, mysqli_result_class_entry);
1863 }
1864 /* }}} */
1865 
1866 /* {{{ */
PHP_FUNCTION(mysqli_stmt_store_result)1867 PHP_FUNCTION(mysqli_stmt_store_result)
1868 {
1869 	MY_STMT	*stmt;
1870 	zval	*mysql_stmt;
1871 
1872 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
1873 		RETURN_THROWS();
1874 	}
1875 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1876 
1877 	if (mysql_stmt_store_result(stmt->stmt)){
1878 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
1879 		RETURN_FALSE;
1880 	}
1881 	RETURN_TRUE;
1882 }
1883 /* }}} */
1884 
1885 /* {{{ */
PHP_FUNCTION(mysqli_stmt_sqlstate)1886 PHP_FUNCTION(mysqli_stmt_sqlstate)
1887 {
1888 	MY_STMT	*stmt;
1889 	zval	*mysql_stmt;
1890 
1891 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
1892 		RETURN_THROWS();
1893 	}
1894 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1895 
1896 	RETURN_STRING(mysql_stmt_sqlstate(stmt->stmt));
1897 }
1898 /* }}} */
1899 
1900 /* {{{ Buffer result set on client */
PHP_FUNCTION(mysqli_store_result)1901 PHP_FUNCTION(mysqli_store_result)
1902 {
1903 	MY_MYSQL		*mysql;
1904 	MYSQL_RES		*result;
1905 	zval			*mysql_link;
1906 	MYSQLI_RESOURCE	*mysqli_resource;
1907 	zend_long flags = 0;
1908 
1909 
1910 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|l", &mysql_link, mysqli_link_class_entry, &flags) == FAILURE) {
1911 		RETURN_THROWS();
1912 	}
1913 
1914 	if ((hasThis() && ZEND_NUM_ARGS() == 1) || ZEND_NUM_ARGS() == 2) {
1915 		zend_error(E_DEPRECATED, "Passing the $mode parameter is deprecated since 8.4, as it has been ignored since 8.1");
1916 		if (UNEXPECTED(EG(exception))) {
1917 			RETURN_THROWS();
1918 		}
1919 	}
1920 
1921 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1922 	result = mysql_store_result(mysql->mysql);
1923 	if (!result) {
1924 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1925 		RETURN_FALSE;
1926 	}
1927 	if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
1928 		php_mysqli_report_index("from previous query", mysqli_server_status(mysql->mysql));
1929 	}
1930 
1931 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
1932 	mysqli_resource->ptr = (void *)result;
1933 	mysqli_resource->status = MYSQLI_STATUS_VALID;
1934 	MYSQLI_RETVAL_RESOURCE(mysqli_resource, mysqli_result_class_entry);
1935 }
1936 /* }}} */
1937 
1938 /* {{{ Return the current thread ID */
PHP_FUNCTION(mysqli_thread_id)1939 PHP_FUNCTION(mysqli_thread_id)
1940 {
1941 	MY_MYSQL	*mysql;
1942 	zval		*mysql_link;
1943 
1944 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1945 		RETURN_THROWS();
1946 	}
1947 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1948 
1949 	RETURN_LONG((zend_long) mysql_thread_id(mysql->mysql));
1950 }
1951 /* }}} */
1952 
1953 /* {{{ Return whether thread safety is given or not */
PHP_FUNCTION(mysqli_thread_safe)1954 PHP_FUNCTION(mysqli_thread_safe)
1955 {
1956 	if (zend_parse_parameters_none() == FAILURE) {
1957 		RETURN_THROWS();
1958 	}
1959 
1960 	RETURN_BOOL(mysql_thread_safe());
1961 }
1962 /* }}} */
1963 
1964 /* {{{ Directly retrieve query results - do not buffer results on client side */
PHP_FUNCTION(mysqli_use_result)1965 PHP_FUNCTION(mysqli_use_result)
1966 {
1967 	MY_MYSQL		*mysql;
1968 	MYSQL_RES		*result;
1969 	zval			*mysql_link;
1970 	MYSQLI_RESOURCE	*mysqli_resource;
1971 
1972 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1973 		RETURN_THROWS();
1974 	}
1975 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1976 
1977 	if (!(result = mysql_use_result(mysql->mysql))) {
1978 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1979 		RETURN_FALSE;
1980 	}
1981 
1982 	if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
1983 		php_mysqli_report_index("from previous query", mysqli_server_status(mysql->mysql));
1984 	}
1985 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
1986 	mysqli_resource->ptr = (void *)result;
1987 	mysqli_resource->status = MYSQLI_STATUS_VALID;
1988 	MYSQLI_RETVAL_RESOURCE(mysqli_resource, mysqli_result_class_entry);
1989 }
1990 /* }}} */
1991 
1992 /* {{{ Return number of warnings from the last query for the given link */
PHP_FUNCTION(mysqli_warning_count)1993 PHP_FUNCTION(mysqli_warning_count)
1994 {
1995 	MY_MYSQL	*mysql;
1996 	zval		*mysql_link;
1997 
1998 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1999 		RETURN_THROWS();
2000 	}
2001 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
2002 
2003 	RETURN_LONG(mysql_warning_count(mysql->mysql));
2004 }
2005 /* }}} */
2006