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