xref: /PHP-8.1/ext/mysqli/mysqli_api.c (revision 15e7e570)
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 
37 #ifndef MYSQLI_USE_MYSQLND
38 /* {{{ mysqli_tx_cor_options_to_string */
mysqli_tx_cor_options_to_string(const MYSQL * const conn,smart_str * str,const uint32_t mode)39 static void mysqli_tx_cor_options_to_string(const MYSQL * const conn, smart_str * str, const uint32_t mode)
40 {
41 	if (mode & TRANS_COR_AND_CHAIN && !(mode & TRANS_COR_AND_NO_CHAIN)) {
42 		if (str->s && ZSTR_LEN(str->s)) {
43 			smart_str_appendl(str, " ", sizeof(" ") - 1);
44 		}
45 		smart_str_appendl(str, "AND CHAIN", sizeof("AND CHAIN") - 1);
46 	} else if (mode & TRANS_COR_AND_NO_CHAIN && !(mode & TRANS_COR_AND_CHAIN)) {
47 		if (str->s && ZSTR_LEN(str->s)) {
48 			smart_str_appendl(str, " ", sizeof(" ") - 1);
49 		}
50 		smart_str_appendl(str, "AND NO CHAIN", sizeof("AND NO CHAIN") - 1);
51 	}
52 
53 	if (mode & TRANS_COR_RELEASE && !(mode & TRANS_COR_NO_RELEASE)) {
54 		if (str->s && ZSTR_LEN(str->s)) {
55 			smart_str_appendl(str, " ", sizeof(" ") - 1);
56 		}
57 		smart_str_appendl(str, "RELEASE", sizeof("RELEASE") - 1);
58 	} else if (mode & TRANS_COR_NO_RELEASE && !(mode & TRANS_COR_RELEASE)) {
59 		if (str->s && ZSTR_LEN(str->s)) {
60 			smart_str_appendl(str, " ", sizeof(" ") - 1);
61 		}
62 		smart_str_appendl(str, "NO RELEASE", sizeof("NO RELEASE") - 1);
63 	}
64 	smart_str_0(str);
65 }
66 /* }}} */
67 
68 /* {{{ mysqlnd_escape_string_for_tx_name_in_comment */
69 char *
mysqli_escape_string_for_tx_name_in_comment(const char * const name)70 mysqli_escape_string_for_tx_name_in_comment(const char * const name)
71 {
72 	char * ret = NULL;
73 	if (name) {
74 		bool warned = false;
75 		const char * p_orig = name;
76 		char * p_copy;
77 		p_copy = ret = emalloc(strlen(name) + 1 + 2 + 2 + 1); /* space, open, close, NullS */
78 		*p_copy++ = ' ';
79 		*p_copy++ = '/';
80 		*p_copy++ = '*';
81 		while (1) {
82 			char v = *p_orig;
83 			if (v == 0) {
84 				break;
85 			}
86 			if ((v >= '0' && v <= '9') ||
87 				(v >= 'a' && v <= 'z') ||
88 				(v >= 'A' && v <= 'Z') ||
89 				v == '-' ||
90 				v == '_' ||
91 				v == ' ' ||
92 				v == '=')
93 			{
94 				*p_copy++ = v;
95 			} else if (!warned) {
96 				php_error_docref(NULL, E_WARNING, "Transaction name has been truncated, since it can only contain the A-Z, a-z, 0-9, \"\\\", \"-\", \"_\", and \"=\" characters");
97 				warned = true;
98 			}
99 			++p_orig;
100 		}
101 		*p_copy++ = '*';
102 		*p_copy++ = '/';
103 		*p_copy++ = 0;
104 	}
105 	return ret;
106 }
107 /* }}} */
108 
109 /* {{{ mysqli_commit_or_rollback_libmysql */
mysqli_commit_or_rollback_libmysql(MYSQL * conn,bool commit,const uint32_t mode,const char * const name)110 static int mysqli_commit_or_rollback_libmysql(MYSQL * conn, bool commit, const uint32_t mode, const char * const name)
111 {
112 	int ret;
113 	smart_str tmp_str = {0};
114 	mysqli_tx_cor_options_to_string(conn, &tmp_str, mode);
115 	smart_str_0(&tmp_str);
116 
117 	{
118 		char *query;
119 		char *name_esc = mysqli_escape_string_for_tx_name_in_comment(name);
120 		size_t query_len;
121 
122 		query_len = spprintf(&query, 0,
123 				(commit? "COMMIT%s %s":"ROLLBACK%s %s"), name_esc? name_esc:"", tmp_str.s? ZSTR_VAL(tmp_str.s):"");
124 		smart_str_free(&tmp_str);
125 		if (name_esc) {
126 			efree(name_esc);
127 			name_esc = NULL;
128 		}
129 
130 		ret = mysql_real_query(conn, query, query_len);
131 		efree(query);
132 	}
133 	return ret;
134 }
135 /* }}} */
136 #endif
137 
138 /* {{{ Get number of affected rows in previous MySQL operation */
PHP_FUNCTION(mysqli_affected_rows)139 PHP_FUNCTION(mysqli_affected_rows)
140 {
141 	MY_MYSQL 		*mysql;
142 	zval  			*mysql_link;
143 	my_ulonglong	rc;
144 
145 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
146 		RETURN_THROWS();
147 	}
148 
149 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
150 
151 	rc = mysql_affected_rows(mysql->mysql);
152 	if (rc == (my_ulonglong) -1) {
153 		RETURN_LONG(-1);
154 	}
155 	MYSQLI_RETURN_LONG_INT(rc);
156 }
157 /* }}} */
158 
159 /* {{{ Turn auto commit on or of */
PHP_FUNCTION(mysqli_autocommit)160 PHP_FUNCTION(mysqli_autocommit)
161 {
162 	MY_MYSQL	*mysql;
163 	zval		*mysql_link;
164 	bool	automode;
165 
166 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ob", &mysql_link, mysqli_link_class_entry, &automode) == FAILURE) {
167 		RETURN_THROWS();
168 	}
169 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
170 
171 	if (mysql_autocommit(mysql->mysql, (my_bool)automode)) {
172 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
173 		RETURN_FALSE;
174 	}
175 	RETURN_TRUE;
176 }
177 /* }}} */
178 
179 /* {{{ mysqli_stmt_bind_param_do_bind */
180 #ifndef MYSQLI_USE_MYSQLND
181 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)182 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)
183 {
184 	int				i, ofs;
185 	MYSQL_BIND		*bind;
186 	unsigned long	rc;
187 
188 	/* prevent leak if variables are already bound */
189 	if (stmt->param.var_cnt) {
190 		php_free_stmt_bind_buffer(stmt->param, FETCH_SIMPLE);
191 	}
192 
193 	stmt->param.is_null = ecalloc(num_vars, sizeof(char));
194 	bind = (MYSQL_BIND *) ecalloc(num_vars, sizeof(MYSQL_BIND));
195 
196 	ofs = 0;
197 	for (i = 0; i < num_vars; i++) {
198 		zval *param;
199 		if (Z_ISREF(args[i])) {
200 			param = Z_REFVAL(args[i]);
201 		} else {
202 			param = &args[i];
203 		}
204 		/* set specified type */
205 		switch (types[ofs]) {
206 			case 'd': /* Double */
207 				bind[ofs].buffer_type = MYSQL_TYPE_DOUBLE;
208 				bind[ofs].buffer = &Z_DVAL_P(param);
209 				bind[ofs].is_null = &stmt->param.is_null[ofs];
210 				break;
211 
212 			case 'i': /* Integer */
213 #if SIZEOF_ZEND_LONG==8
214 				bind[ofs].buffer_type = MYSQL_TYPE_LONGLONG;
215 #elif SIZEOF_ZEND_LONG==4
216 				bind[ofs].buffer_type = MYSQL_TYPE_LONG;
217 #endif
218 				bind[ofs].buffer = &Z_LVAL_P(param);
219 				bind[ofs].is_null = &stmt->param.is_null[ofs];
220 				break;
221 
222 			case 'b': /* Blob (send data) */
223 				bind[ofs].buffer_type = MYSQL_TYPE_LONG_BLOB;
224 				/* don't initialize is_null and length to 0 because we use ecalloc */
225 				break;
226 
227 			case 's': /* string */
228 				bind[ofs].buffer_type = MYSQL_TYPE_VAR_STRING;
229 				/* don't initialize buffer and buffer_length because we use ecalloc */
230 				bind[ofs].is_null = &stmt->param.is_null[ofs];
231 				break;
232 
233 			default:
234 				zend_argument_value_error(num_extra_args, "must only contain the \"b\", \"d\", \"i\", \"s\" type specifiers");
235 				rc = 1;
236 				goto end_1;
237 		}
238 		ofs++;
239 	}
240 	rc = mysql_stmt_bind_param(stmt->stmt, bind);
241 
242 end_1:
243 	if (rc) {
244 		efree(stmt->param.is_null);
245 	} else {
246 		stmt->param.var_cnt = num_vars;
247 		stmt->param.vars = safe_emalloc(num_vars, sizeof(zval), 0);
248 		for (i = 0; i < num_vars; i++) {
249 			if (bind[i].buffer_type != MYSQL_TYPE_LONG_BLOB) {
250 				ZVAL_COPY(&stmt->param.vars[i], &args[i]);
251 			} else {
252 				ZVAL_UNDEF(&stmt->param.vars[i]);
253 			}
254 		}
255 	}
256 	efree(bind);
257 
258 	return rc;
259 }
260 #else
261 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)262 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)
263 {
264 	unsigned int i;
265 	MYSQLND_PARAM_BIND	*params;
266 	enum_func_status	ret = FAIL;
267 
268 	/* If no params -> skip binding and return directly */
269 	if (num_vars == 0) {
270 		return PASS;
271 	}
272 	params = mysqlnd_stmt_alloc_param_bind(stmt->stmt);
273 	if (!params) {
274 		goto end;
275 	}
276 	for (i = 0; i < num_vars; i++) {
277 		zend_uchar type;
278 		switch (types[i]) {
279 			case 'd': /* Double */
280 				type = MYSQL_TYPE_DOUBLE;
281 				break;
282 			case 'i': /* Integer */
283 #if SIZEOF_ZEND_LONG==8
284 				type = MYSQL_TYPE_LONGLONG;
285 #elif SIZEOF_ZEND_LONG==4
286 				type = MYSQL_TYPE_LONG;
287 #endif
288 				break;
289 			case 'b': /* Blob (send data) */
290 				type = MYSQL_TYPE_LONG_BLOB;
291 				break;
292 			case 's': /* string */
293 				type = MYSQL_TYPE_VAR_STRING;
294 				break;
295 			default:
296 				zend_argument_value_error(num_extra_args, "must only contain the \"b\", \"d\", \"i\", \"s\" type specifiers");
297 				ret = FAIL;
298 				mysqlnd_stmt_free_param_bind(stmt->stmt, params);
299 				goto end;
300 		}
301 		ZVAL_COPY_VALUE(&params[i].zv, &args[i]);
302 		params[i].type = type;
303 	}
304 	ret = mysqlnd_stmt_bind_param(stmt->stmt, params);
305 
306 end:
307 	return ret;
308 }
309 #endif
310 /* }}} */
311 
312 /* {{{ Bind variables to a prepared statement as parameters */
PHP_FUNCTION(mysqli_stmt_bind_param)313 PHP_FUNCTION(mysqli_stmt_bind_param)
314 {
315 	zval			*args;
316 	int				argc;
317 	MY_STMT			*stmt;
318 	zval			*mysql_stmt;
319 	char			*types;
320 	size_t			types_len;
321 
322 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os*", &mysql_stmt, mysqli_stmt_class_entry, &types, &types_len, &args, &argc) == FAILURE) {
323 		RETURN_THROWS();
324 	}
325 
326 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
327 
328 	if (!types_len) {
329 		zend_argument_value_error(ERROR_ARG_POS(2), "cannot be empty");
330 		RETURN_THROWS();
331 	}
332 
333 	if (types_len != (size_t) argc) {
334 		/* number of bind variables doesn't match number of elements in type definition string */
335 		zend_argument_count_error("The number of elements in the type definition string must match the number of bind variables");
336 		RETURN_THROWS();
337 	}
338 
339 	if (types_len != mysql_stmt_param_count(stmt->stmt)) {
340 		zend_argument_count_error("The number of variables must match the number of parameters in the prepared statement");
341 		RETURN_THROWS();
342 	}
343 
344 	RETVAL_BOOL(!mysqli_stmt_bind_param_do_bind(stmt, argc, args, types, getThis() ? 1 : 2));
345 	MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
346 }
347 /* }}} */
348 
349 /* {{{ mysqli_stmt_bind_result_do_bind */
350 #ifndef MYSQLI_USE_MYSQLND
351 /* TODO:
352    do_alloca, free_alloca
353 */
354 static int
mysqli_stmt_bind_result_do_bind(MY_STMT * stmt,zval * args,unsigned int argc)355 mysqli_stmt_bind_result_do_bind(MY_STMT *stmt, zval *args, unsigned int argc)
356 {
357 	MYSQL_BIND	*bind;
358 	int			i, ofs;
359 	int			var_cnt = argc;
360 	zend_long		col_type;
361 	zend_ulong		rc;
362 
363 	/* prevent leak if variables are already bound */
364 	if (stmt->result.var_cnt) {
365 		php_free_stmt_bind_buffer(stmt->result, FETCH_RESULT);
366 	}
367 
368 	bind = (MYSQL_BIND *)ecalloc(var_cnt, sizeof(MYSQL_BIND));
369 	{
370 		int size;
371 		char *p = emalloc(size= var_cnt * (sizeof(char) + sizeof(VAR_BUFFER)));
372 		stmt->result.buf = (VAR_BUFFER *) p;
373 		stmt->result.is_null = (my_bool *) (p + var_cnt * sizeof(VAR_BUFFER));
374 		memset(p, 0, size);
375 	}
376 
377 	for (i = 0; i < var_cnt; i++) {
378 		ofs = i;
379 		col_type = (stmt->stmt->fields) ? stmt->stmt->fields[ofs].type : MYSQL_TYPE_STRING;
380 
381 		switch (col_type) {
382 			case MYSQL_TYPE_FLOAT:
383 				stmt->result.buf[ofs].type = IS_DOUBLE;
384 				stmt->result.buf[ofs].buflen = sizeof(float);
385 
386 				stmt->result.buf[ofs].val = (char *)emalloc(sizeof(float));
387 				bind[ofs].buffer_type = MYSQL_TYPE_FLOAT;
388 				bind[ofs].buffer = stmt->result.buf[ofs].val;
389 				bind[ofs].is_null = &stmt->result.is_null[ofs];
390 				break;
391 
392 			case MYSQL_TYPE_DOUBLE:
393 				stmt->result.buf[ofs].type = IS_DOUBLE;
394 				stmt->result.buf[ofs].buflen = sizeof(double);
395 
396 				/* allocate buffer for double */
397 				stmt->result.buf[ofs].val = (char *)emalloc(sizeof(double));
398 				bind[ofs].buffer_type = MYSQL_TYPE_DOUBLE;
399 				bind[ofs].buffer = stmt->result.buf[ofs].val;
400 				bind[ofs].is_null = &stmt->result.is_null[ofs];
401 				break;
402 
403 			case MYSQL_TYPE_NULL:
404 				stmt->result.buf[ofs].type = IS_NULL;
405 				/*
406 				  don't initialize to 0 :
407 				  1. stmt->result.buf[ofs].buflen
408 				  2. bind[ofs].buffer
409 				  3. bind[ofs].buffer_length
410 				  because memory was allocated with ecalloc
411 				*/
412 				bind[ofs].buffer_type = MYSQL_TYPE_NULL;
413 				bind[ofs].is_null = &stmt->result.is_null[ofs];
414 				break;
415 
416 			case MYSQL_TYPE_SHORT:
417 			case MYSQL_TYPE_TINY:
418 			case MYSQL_TYPE_LONG:
419 			case MYSQL_TYPE_INT24:
420 			case MYSQL_TYPE_YEAR:
421 				stmt->result.buf[ofs].type = IS_LONG;
422 				/* don't set stmt->result.buf[ofs].buflen to 0, we used ecalloc */
423 				stmt->result.buf[ofs].val = (char *)emalloc(sizeof(int));
424 				bind[ofs].buffer_type = MYSQL_TYPE_LONG;
425 				bind[ofs].buffer = stmt->result.buf[ofs].val;
426 				bind[ofs].is_null = &stmt->result.is_null[ofs];
427 				bind[ofs].is_unsigned = (stmt->stmt->fields[ofs].flags & UNSIGNED_FLAG) ? 1 : 0;
428 				break;
429 
430 			case MYSQL_TYPE_LONGLONG:
431 			case MYSQL_TYPE_BIT:
432 				stmt->result.buf[ofs].type = IS_STRING;
433 				stmt->result.buf[ofs].buflen = sizeof(my_ulonglong);
434 				stmt->result.buf[ofs].val = (char *)emalloc(stmt->result.buf[ofs].buflen);
435 				bind[ofs].buffer_type = col_type;
436 				bind[ofs].buffer = stmt->result.buf[ofs].val;
437 				bind[ofs].is_null = &stmt->result.is_null[ofs];
438 				bind[ofs].buffer_length = stmt->result.buf[ofs].buflen;
439 				bind[ofs].is_unsigned = (stmt->stmt->fields[ofs].flags & UNSIGNED_FLAG) ? 1 : 0;
440 				bind[ofs].length = &stmt->result.buf[ofs].output_len;
441 				break;
442 
443 			case MYSQL_TYPE_DATE:
444 			case MYSQL_TYPE_TIME:
445 			case MYSQL_TYPE_DATETIME:
446 			case MYSQL_TYPE_NEWDATE:
447 			case MYSQL_TYPE_VAR_STRING:
448 			case MYSQL_TYPE_STRING:
449 			case MYSQL_TYPE_TINY_BLOB:
450 			case MYSQL_TYPE_BLOB:
451 			case MYSQL_TYPE_MEDIUM_BLOB:
452 			case MYSQL_TYPE_LONG_BLOB:
453 			case MYSQL_TYPE_TIMESTAMP:
454 			case MYSQL_TYPE_DECIMAL:
455 			case MYSQL_TYPE_GEOMETRY:
456 #ifdef FIELD_TYPE_NEWDECIMAL
457 			case MYSQL_TYPE_NEWDECIMAL:
458 #endif
459 			{
460 				my_bool tmp;
461 				stmt->result.buf[ofs].type = IS_STRING;
462 				/*
463 					If the user has called $stmt->store_result() then we have asked
464 					max_length to be updated. this is done only for BLOBS because we don't want to allocate
465 					big chunkgs of memory 2^16 or 2^24
466 				*/
467 				if (stmt->stmt->fields[ofs].max_length == 0 &&
468 					!mysql_stmt_attr_get(stmt->stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &tmp) && !tmp)
469 				{
470 					/*
471 					  Allocate directly 256 because it's easier to allocate a bit more
472 					  than update max length even for text columns. Try SELECT UNION SELECT UNION with
473 					  different lengths and you will see that we get different lengths in stmt->stmt->fields[ofs].length
474 					  The just take 256 and saves us from realloc-ing.
475 					*/
476 					stmt->result.buf[ofs].buflen =
477 						(stmt->stmt->fields) ? (stmt->stmt->fields[ofs].length) ? stmt->stmt->fields[ofs].length + 1: 256: 256;
478 
479 				} else {
480 					/*
481 						the user has called store_result(). if he does not there is no way to determine the
482 						libmysql does not allow us to allocate 0 bytes for a buffer so we try 1
483 					*/
484 					if (!(stmt->result.buf[ofs].buflen = stmt->stmt->fields[ofs].max_length))
485 						++stmt->result.buf[ofs].buflen;
486 				}
487 				stmt->result.buf[ofs].val = (char *)emalloc(stmt->result.buf[ofs].buflen);
488 				bind[ofs].buffer_type = MYSQL_TYPE_STRING;
489 				bind[ofs].buffer = stmt->result.buf[ofs].val;
490 				bind[ofs].is_null = &stmt->result.is_null[ofs];
491 				bind[ofs].buffer_length = stmt->result.buf[ofs].buflen;
492 				bind[ofs].length = &stmt->result.buf[ofs].output_len;
493 				break;
494 			}
495 			default:
496 				php_error_docref(NULL, E_WARNING, "Server returned unknown type %ld. Probably your client library is incompatible with the server version you use!", col_type);
497 				break;
498 		}
499 	}
500 
501 	rc = mysql_stmt_bind_result(stmt->stmt, bind);
502 	MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
503 
504 	if (rc) {
505 		/* don't close the statement or subsequent usage (for example ->execute()) will lead to crash */
506 		for (i=0; i < var_cnt ; i++) {
507 			if (stmt->result.buf[i].val) {
508 				efree(stmt->result.buf[i].val);
509 			}
510 		}
511 		/* Don't free stmt->result.is_null because is_null & buf are one block of memory  */
512 		efree(stmt->result.buf);
513 	} else {
514 		stmt->result.var_cnt = var_cnt;
515 		stmt->result.vars = safe_emalloc((var_cnt), sizeof(zval), 0);
516 		for (i = 0; i < var_cnt; i++) {
517 			ZVAL_COPY(&stmt->result.vars[i], &args[i]);
518 		}
519 	}
520 	efree(bind);
521 
522 	return rc;
523 }
524 #else
525 static int
mysqli_stmt_bind_result_do_bind(MY_STMT * stmt,zval * args,unsigned int argc)526 mysqli_stmt_bind_result_do_bind(MY_STMT *stmt, zval *args, unsigned int argc)
527 {
528 	unsigned int i;
529 	MYSQLND_RESULT_BIND *params = mysqlnd_stmt_alloc_result_bind(stmt->stmt);
530 	if (params) {
531 		for (i = 0; i < argc; i++) {
532 			ZVAL_COPY_VALUE(&params[i].zv, &args[i]);
533 		}
534 		return mysqlnd_stmt_bind_result(stmt->stmt, params);
535 	}
536 	return FAIL;
537 }
538 #endif
539 /* }}} */
540 
541 /* {{{ Bind variables to a prepared statement for result storage */
PHP_FUNCTION(mysqli_stmt_bind_result)542 PHP_FUNCTION(mysqli_stmt_bind_result)
543 {
544 	zval		*args;
545 	int			argc;
546 	zend_ulong		rc;
547 	MY_STMT		*stmt;
548 	zval		*mysql_stmt;
549 
550 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O+", &mysql_stmt, mysqli_stmt_class_entry, &args, &argc) == FAILURE) {
551 		RETURN_THROWS();
552 	}
553 
554 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
555 
556 	if ((uint32_t)argc != mysql_stmt_field_count(stmt->stmt)) {
557 		zend_argument_count_error("Number of bind variables doesn't match number of fields in prepared statement");
558 		RETURN_THROWS();
559 	}
560 
561 	rc = mysqli_stmt_bind_result_do_bind(stmt, args, argc);
562 	RETURN_BOOL(!rc);
563 }
564 /* }}} */
565 
566 /* {{{ Change logged-in user of the active connection */
PHP_FUNCTION(mysqli_change_user)567 PHP_FUNCTION(mysqli_change_user)
568 {
569 	MY_MYSQL	*mysql;
570 	zval		*mysql_link = NULL;
571 	char		*user, *password, *dbname;
572 	size_t			user_len, password_len, dbname_len;
573 	zend_ulong		rc;
574 #ifndef MYSQLI_USE_MYSQLND
575 	MY_CHARSET_INFO old_charset;
576 #endif
577 
578 	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) {
579 		RETURN_THROWS();
580 	}
581 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
582 
583 #ifndef MYSQLI_USE_MYSQLND
584 	mysql_get_character_set_info(mysql->mysql, &old_charset);
585 #endif
586 
587 #ifdef MYSQLI_USE_MYSQLND
588 	rc = mysqlnd_change_user_ex(mysql->mysql, user, password, dbname, false, (size_t) password_len);
589 #else
590 	rc = mysql_change_user(mysql->mysql, user, password, dbname);
591 #endif
592 	MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
593 
594 	if (rc) {
595 		RETURN_FALSE;
596 	}
597 #ifndef MYSQLI_USE_MYSQLND
598 	if (mysql_get_server_version(mysql->mysql) < 50123L) {
599 		/*
600 		  Request the current charset, or it will be reset to the system one.
601 		  5.0 doesn't support it. Support added in 5.1.23 by fixing the following bug :
602 		  Bug #30472 libmysql doesn't reset charset, insert_id after succ. mysql_change_user() call
603 		*/
604 		rc = mysql_set_character_set(mysql->mysql, old_charset.csname);
605 	}
606 #endif
607 
608 	RETURN_TRUE;
609 }
610 /* }}} */
611 
612 /* {{{ Returns the name of the character set used for this connection */
PHP_FUNCTION(mysqli_character_set_name)613 PHP_FUNCTION(mysqli_character_set_name)
614 {
615 	MY_MYSQL	*mysql;
616 	zval		*mysql_link;
617 
618 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
619 		RETURN_THROWS();
620 	}
621 
622 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
623 	RETURN_STRING(mysql_character_set_name(mysql->mysql));
624 }
625 /* }}} */
626 
627 /* {{{ php_mysqli_close */
php_mysqli_close(MY_MYSQL * mysql,int close_type,int resource_status)628 void php_mysqli_close(MY_MYSQL * mysql, int close_type, int resource_status)
629 {
630 	if (resource_status > MYSQLI_STATUS_INITIALIZED) {
631 		MyG(num_links)--;
632 	}
633 
634 	if (!mysql->persistent) {
635 		mysqli_close(mysql->mysql, close_type);
636 	} else {
637 		zend_resource *le;
638 		if ((le = zend_hash_find_ptr(&EG(persistent_list), mysql->hash_key)) != NULL) {
639 			if (le->type == php_le_pmysqli()) {
640 				mysqli_plist_entry *plist = (mysqli_plist_entry *) le->ptr;
641 #ifdef MYSQLI_USE_MYSQLND
642 				mysqlnd_end_psession(mysql->mysql);
643 #endif
644 
645 				if (MyG(rollback_on_cached_plink) &&
646 #ifndef MYSQLI_USE_MYSQLND
647 					mysqli_commit_or_rollback_libmysql(mysql->mysql, false, TRANS_COR_NO_OPT, NULL))
648 #else
649 					FAIL == mysqlnd_rollback(mysql->mysql, TRANS_COR_NO_OPT, NULL))
650 #endif
651 				{
652 					mysqli_close(mysql->mysql, close_type);
653 				} else {
654 					zend_ptr_stack_push(&plist->free_links, mysql->mysql);
655 					MyG(num_inactive_persistent)++;
656 				}
657 				MyG(num_active_persistent)--;
658 			}
659 		}
660 		mysql->persistent = false;
661 	}
662 	mysql->mysql = NULL;
663 
664 	php_clear_mysql(mysql);
665 }
666 /* }}} */
667 
668 /* {{{ Close connection */
PHP_FUNCTION(mysqli_close)669 PHP_FUNCTION(mysqli_close)
670 {
671 	zval		*mysql_link;
672 	MY_MYSQL	*mysql;
673 
674 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
675 		RETURN_THROWS();
676 	}
677 
678 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_INITIALIZED);
679 
680 	php_mysqli_close(mysql, MYSQLI_CLOSE_EXPLICIT, ((MYSQLI_RESOURCE *)(Z_MYSQLI_P(mysql_link))->ptr)->status);
681 	((MYSQLI_RESOURCE *)(Z_MYSQLI_P(mysql_link))->ptr)->status = MYSQLI_STATUS_UNKNOWN;
682 
683 	MYSQLI_CLEAR_RESOURCE(mysql_link);
684 	efree(mysql);
685 	RETURN_TRUE;
686 }
687 /* }}} */
688 
689 /* {{{ Commit outstanding actions and close transaction */
PHP_FUNCTION(mysqli_commit)690 PHP_FUNCTION(mysqli_commit)
691 {
692 	MY_MYSQL	*mysql;
693 	zval		*mysql_link;
694 	zend_long		flags = TRANS_COR_NO_OPT;
695 	char *		name = NULL;
696 	size_t			name_len;
697 
698 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|ls!", &mysql_link, mysqli_link_class_entry, &flags, &name, &name_len) == FAILURE) {
699 		RETURN_THROWS();
700 	}
701 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
702 
703 #ifndef MYSQLI_USE_MYSQLND
704 	if (mysqli_commit_or_rollback_libmysql(mysql->mysql, true, flags, name)) {
705 #else
706 	if (FAIL == mysqlnd_commit(mysql->mysql, flags, name)) {
707 #endif
708 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
709 		RETURN_FALSE;
710 	}
711 	RETURN_TRUE;
712 }
713 /* }}} */
714 
715 /* {{{ Move internal result pointer */
716 PHP_FUNCTION(mysqli_data_seek)
717 {
718 	MYSQL_RES	*result;
719 	zval		*mysql_result;
720 	zend_long		offset;
721 
722 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_result, mysqli_result_class_entry, &offset) == FAILURE) {
723 		RETURN_THROWS();
724 	}
725 
726 	if (offset < 0) {
727 		zend_argument_value_error(ERROR_ARG_POS(2), "must be greater than or equal to 0");
728 		RETURN_THROWS();
729 	}
730 
731 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
732 
733 	if (mysqli_result_is_unbuffered(result)) {
734 		if (getThis()) {
735 			zend_throw_error(NULL, "mysqli_result::data_seek() cannot be used in MYSQLI_USE_RESULT mode");
736 		} else {
737 			zend_throw_error(NULL, "mysqli_data_seek() cannot be used in MYSQLI_USE_RESULT mode");
738 		}
739 		RETURN_THROWS();
740 	}
741 
742 	if ((uint64_t)offset >= mysql_num_rows(result)) {
743 		RETURN_FALSE;
744 	}
745 
746 	mysql_data_seek(result, offset);
747 	RETURN_TRUE;
748 }
749 /* }}} */
750 
751 /* {{{ */
752 PHP_FUNCTION(mysqli_debug)
753 {
754 	char	*debug;
755 	size_t		debug_len;
756 
757 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &debug, &debug_len) == FAILURE) {
758 		RETURN_THROWS();
759 	}
760 
761 	mysql_debug(debug);
762 	RETURN_TRUE;
763 }
764 /* }}} */
765 
766 /* {{{ */
767 PHP_FUNCTION(mysqli_dump_debug_info)
768 {
769 	MY_MYSQL	*mysql;
770 	zval		*mysql_link;
771 
772 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
773 		RETURN_THROWS();
774 	}
775 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
776 
777 	RETURN_BOOL(!mysql_dump_debug_info(mysql->mysql));
778 }
779 /* }}} */
780 
781 /* {{{ Returns the numerical value of the error message from previous MySQL operation */
782 PHP_FUNCTION(mysqli_errno)
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 	RETURN_LONG(mysql_errno(mysql->mysql));
792 }
793 /* }}} */
794 
795 /* {{{ Returns the text of the error message from previous MySQL operation */
796 PHP_FUNCTION(mysqli_error)
797 {
798 	MY_MYSQL	*mysql;
799 	zval		*mysql_link;
800 
801 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
802 		RETURN_THROWS();
803 	}
804 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
805 	RETURN_STRING(mysql_error(mysql->mysql));
806 }
807 /* }}} */
808 
809 /* {{{ Execute a prepared statement */
810 PHP_FUNCTION(mysqli_stmt_execute)
811 {
812 	MY_STMT		*stmt;
813 	zval		*mysql_stmt;
814 	HashTable	*input_params = NULL;
815 #ifndef MYSQLI_USE_MYSQLND
816 	unsigned int	i;
817 #endif
818 
819 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|h!", &mysql_stmt, mysqli_stmt_class_entry, &input_params) == FAILURE) {
820 		RETURN_THROWS();
821 	}
822 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
823 
824 	// bind-in-execute
825 	if (input_params) {
826 #if defined(MYSQLI_USE_MYSQLND)
827 		zval *tmp;
828 		unsigned int index;
829 		unsigned int hash_num_elements;
830 		unsigned int param_count;
831 		MYSQLND_PARAM_BIND	*params;
832 
833 		if (!zend_array_is_list(input_params)) {
834 			zend_argument_value_error(ERROR_ARG_POS(2), "must be a list array");
835 			RETURN_THROWS();
836 		}
837 
838 		hash_num_elements = zend_hash_num_elements(input_params);
839 		param_count = mysql_stmt_param_count(stmt->stmt);
840 		if (hash_num_elements != param_count) {
841 			zend_argument_value_error(ERROR_ARG_POS(2), "must consist of exactly %d elements, %d present", param_count, hash_num_elements);
842 			RETURN_THROWS();
843 		}
844 
845 		params = mysqlnd_stmt_alloc_param_bind(stmt->stmt);
846 		ZEND_ASSERT(params);
847 
848 		index = 0;
849 		ZEND_HASH_FOREACH_VAL(input_params, tmp) {
850 			ZVAL_COPY_VALUE(&params[index].zv, tmp);
851 			params[index].type = MYSQL_TYPE_VAR_STRING;
852 			index++;
853 		} ZEND_HASH_FOREACH_END();
854 
855 		if (mysqlnd_stmt_bind_param(stmt->stmt, params)) {
856 			MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
857 			RETVAL_FALSE;
858 		}
859 #else
860 		zend_argument_count_error("Binding parameters in execute is not supported with libmysqlclient");
861 		RETURN_THROWS();
862 #endif
863 	}
864 
865 #ifndef MYSQLI_USE_MYSQLND
866 	if (stmt->param.var_cnt) {
867 		int j;
868 		for (i = 0; i < stmt->param.var_cnt; i++) {
869 			if (!Z_ISREF(stmt->param.vars[i])) {
870 				continue;
871 			}
872 			for (j = i + 1; j < stmt->param.var_cnt; j++) {
873 				/* Oops, someone binding the same variable - clone */
874 				if (Z_ISREF(stmt->param.vars[j]) &&
875 					   	Z_REFVAL(stmt->param.vars[j]) == Z_REFVAL(stmt->param.vars[i])) {
876 					/*SEPARATE_ZVAL(&stmt->param.vars[j]);*/
877 					Z_DELREF_P(&stmt->param.vars[j]);
878 					ZVAL_COPY(&stmt->param.vars[j], Z_REFVAL(stmt->param.vars[j]));
879 					break;
880 				}
881 			}
882 		}
883 	}
884 	for (i = 0; i < stmt->param.var_cnt; i++) {
885 		if (!Z_ISUNDEF(stmt->param.vars[i])) {
886 			zval *param;
887 			if (Z_ISREF(stmt->param.vars[i])) {
888 				param = Z_REFVAL(stmt->param.vars[i]);
889 			} else {
890 				param = &stmt->param.vars[i];
891 			}
892 			if (!(stmt->param.is_null[i] = (Z_ISNULL_P(param)))) {
893 				switch (stmt->stmt->params[i].buffer_type) {
894 					case MYSQL_TYPE_VAR_STRING:
895 						if (!try_convert_to_string(param)) {
896 							RETURN_THROWS();
897 						}
898 
899 						stmt->stmt->params[i].buffer = Z_STRVAL_P(param);
900 						stmt->stmt->params[i].buffer_length = Z_STRLEN_P(param);
901 						break;
902 					case MYSQL_TYPE_DOUBLE:
903 						convert_to_double(param);
904 						stmt->stmt->params[i].buffer = &Z_DVAL_P(param);
905 						break;
906 					case MYSQL_TYPE_LONGLONG:
907 					case MYSQL_TYPE_LONG:
908 						convert_to_long(param);
909 						stmt->stmt->params[i].buffer = &Z_LVAL_P(param);
910 						break;
911 					default:
912 						break;
913 				}
914 			}
915 		}
916 	}
917 #endif
918 
919 	if (mysql_stmt_execute(stmt->stmt)) {
920 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
921 		RETVAL_FALSE;
922 	} else {
923 		RETVAL_TRUE;
924 	}
925 
926 	if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
927 		php_mysqli_report_index(stmt->query, mysqli_stmt_server_status(stmt->stmt));
928 	}
929 }
930 /* }}} */
931 
932 #ifndef MYSQLI_USE_MYSQLND
933 /* {{{ void mysqli_stmt_fetch_libmysql
934    Fetch results from a prepared statement into the bound variables */
935 void mysqli_stmt_fetch_libmysql(INTERNAL_FUNCTION_PARAMETERS)
936 {
937 	MY_STMT		*stmt;
938 	zval			*mysql_stmt;
939 	unsigned int	i;
940 	zend_ulong			ret;
941 	my_ulonglong	llval;
942 
943 
944 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
945 		RETURN_THROWS();
946 	}
947 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
948 
949 	/* reset buffers */
950 	for (i = 0; i < stmt->result.var_cnt; i++) {
951 		if (stmt->result.buf[i].type == IS_STRING) {
952 			memset(stmt->result.buf[i].val, 0, stmt->result.buf[i].buflen);
953 		}
954 	}
955 	ret = mysql_stmt_fetch(stmt->stmt);
956 #ifdef MYSQL_DATA_TRUNCATED
957 	if (!ret || ret == MYSQL_DATA_TRUNCATED) {
958 #else
959 	if (!ret) {
960 #endif
961 		for (i = 0; i < stmt->result.var_cnt; i++) {
962 			zval *result;
963 			/* it must be a reference, isn't it? */
964 			if (Z_ISREF(stmt->result.vars[i])) {
965 				result = &stmt->result.vars[i];
966 			} else {
967 				continue; // but be safe ...
968 			}
969 			/* Even if the string is of length zero there is one byte alloced so efree() in all cases */
970 			if (!stmt->result.is_null[i]) {
971 				switch (stmt->result.buf[i].type) {
972 					case IS_LONG:
973 						if ((stmt->stmt->fields[i].type == MYSQL_TYPE_LONG)
974 						    && (stmt->stmt->fields[i].flags & UNSIGNED_FLAG))
975 						{
976 							/* unsigned int (11) */
977 #if SIZEOF_ZEND_LONG == 4
978 							unsigned int uval = *(unsigned int *) stmt->result.buf[i].val;
979 							if (uval > INT_MAX) {
980 								char *tmp, *p;
981 								int j = 10;
982 								tmp = emalloc(11);
983 								p= &tmp[9];
984 								do {
985 									*p-- = (uval % 10) + 48;
986 									uval = uval / 10;
987 								} while (--j > 0);
988 								tmp[10]= '\0';
989 								/* unsigned int > INT_MAX is 10 digits - ALWAYS */
990 								ZEND_TRY_ASSIGN_REF_STRINGL(result, tmp, 10);
991 								efree(tmp);
992 								break;
993 							}
994 #endif
995 						}
996 						if (stmt->stmt->fields[i].flags & UNSIGNED_FLAG) {
997 							ZEND_TRY_ASSIGN_REF_LONG(result, *(unsigned int *)stmt->result.buf[i].val);
998 						} else {
999 							ZEND_TRY_ASSIGN_REF_LONG(result, *(int *)stmt->result.buf[i].val);
1000 						}
1001 						break;
1002 					case IS_DOUBLE:
1003 					{
1004 						double dval;
1005 						if (stmt->stmt->bind[i].buffer_type == MYSQL_TYPE_FLOAT) {
1006 #ifndef NOT_FIXED_DEC
1007 # define NOT_FIXED_DEC 31
1008 #endif
1009 							dval = mysql_float_to_double(*(float *)stmt->result.buf[i].val,
1010 										(stmt->stmt->fields[i].decimals >= NOT_FIXED_DEC) ? -1 :
1011 										stmt->stmt->fields[i].decimals);
1012 						} else {
1013 							dval = *((double *)stmt->result.buf[i].val);
1014 						}
1015 
1016 						ZEND_TRY_ASSIGN_REF_DOUBLE(result, dval);
1017 						break;
1018 					}
1019 					case IS_STRING:
1020 						if (stmt->stmt->bind[i].buffer_type == MYSQL_TYPE_LONGLONG
1021 						 || stmt->stmt->bind[i].buffer_type == MYSQL_TYPE_BIT
1022 						 ) {
1023 							my_bool uns = (stmt->stmt->fields[i].flags & UNSIGNED_FLAG)? 1:0;
1024 							if (stmt->stmt->bind[i].buffer_type == MYSQL_TYPE_BIT) {
1025 								switch (stmt->result.buf[i].output_len) {
1026 									case 8:llval = (my_ulonglong)  bit_uint8korr(stmt->result.buf[i].val);break;
1027 									case 7:llval = (my_ulonglong)  bit_uint7korr(stmt->result.buf[i].val);break;
1028 									case 6:llval = (my_ulonglong)  bit_uint6korr(stmt->result.buf[i].val);break;
1029 									case 5:llval = (my_ulonglong)  bit_uint5korr(stmt->result.buf[i].val);break;
1030 									case 4:llval = (my_ulonglong)  bit_uint4korr(stmt->result.buf[i].val);break;
1031 									case 3:llval = (my_ulonglong)  bit_uint3korr(stmt->result.buf[i].val);break;
1032 									case 2:llval = (my_ulonglong)  bit_uint2korr(stmt->result.buf[i].val);break;
1033 									case 1:llval = (my_ulonglong)  uint1korr(stmt->result.buf[i].val);break;
1034 								}
1035 							} else {
1036 								llval= *(my_ulonglong *) stmt->result.buf[i].val;
1037 							}
1038 #if SIZEOF_ZEND_LONG==8
1039 							if (uns && llval > 9223372036854775807L) {
1040 #elif SIZEOF_ZEND_LONG==4
1041 							if ((uns && llval > L64(2147483647)) ||
1042 								(!uns && (( L64(2147483647) < (my_longlong) llval) ||
1043 								(L64(-2147483648) > (my_longlong) llval))))
1044 							{
1045 #endif
1046 								char tmp[22];
1047 								/* even though lval is declared as unsigned, the value
1048 								 * may be negative. Therefore we cannot use MYSQLI_LLU_SPEC and must
1049 								 * use MYSQLI_LL_SPEC.
1050 								 */
1051 								snprintf(tmp, sizeof(tmp), (stmt->stmt->fields[i].flags & UNSIGNED_FLAG)? MYSQLI_LLU_SPEC : MYSQLI_LL_SPEC, llval);
1052 								ZEND_TRY_ASSIGN_REF_STRING(result, tmp);
1053 							} else {
1054 								ZEND_TRY_ASSIGN_REF_LONG(result, llval);
1055 							}
1056 						} else {
1057 							if (ret == MYSQL_DATA_TRUNCATED && *(stmt->stmt->bind[i].error) != 0) {
1058 								/* result was truncated */
1059 								ZEND_TRY_ASSIGN_REF_STRINGL(result, stmt->result.buf[i].val, stmt->stmt->bind[i].buffer_length);
1060 							} else {
1061 								ZEND_TRY_ASSIGN_REF_STRINGL(result, stmt->result.buf[i].val, stmt->result.buf[i].output_len);
1062 							}
1063 						}
1064 						break;
1065 					default:
1066 						break;
1067 				}
1068 			} else {
1069 				ZEND_TRY_ASSIGN_REF_NULL(result);
1070 			}
1071 		}
1072 	} else {
1073 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
1074 	}
1075 
1076 	switch (ret) {
1077 		case 0:
1078 #ifdef MYSQL_DATA_TRUNCATED
1079 		/* according to SQL standard truncation (e.g. loss of precision is
1080 		   not an error) - for detecting possible truncation you have to
1081 		   check mysqli_stmt_warning
1082 		*/
1083 		case MYSQL_DATA_TRUNCATED:
1084 #endif
1085 			RETURN_TRUE;
1086 		break;
1087 		case 1:
1088 			RETURN_FALSE;
1089 		break;
1090 		default:
1091 			RETURN_NULL();
1092 		break;
1093 	}
1094 }
1095 /* }}} */
1096 #else
1097 /* {{{ mixed mysqli_stmt_fetch_mysqlnd */
1098 void mysqli_stmt_fetch_mysqlnd(INTERNAL_FUNCTION_PARAMETERS)
1099 {
1100 	MY_STMT		*stmt;
1101 	zval		*mysql_stmt;
1102 	bool	fetched_anything;
1103 
1104 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
1105 		RETURN_THROWS();
1106 	}
1107 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1108 
1109 	if (FAIL == mysqlnd_stmt_fetch(stmt->stmt, &fetched_anything)) {
1110 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
1111 		RETURN_FALSE;
1112 	} else if (fetched_anything) {
1113 		RETURN_TRUE;
1114 	} else {
1115 		RETURN_NULL();
1116 	}
1117 }
1118 #endif
1119 /* }}} */
1120 
1121 /* {{{ Fetch results from a prepared statement into the bound variables */
1122 PHP_FUNCTION(mysqli_stmt_fetch)
1123 {
1124 #ifndef MYSQLI_USE_MYSQLND
1125 	mysqli_stmt_fetch_libmysql(INTERNAL_FUNCTION_PARAM_PASSTHRU);
1126 #else
1127 	mysqli_stmt_fetch_mysqlnd(INTERNAL_FUNCTION_PARAM_PASSTHRU);
1128 #endif
1129 }
1130 /* }}} */
1131 
1132 /* {{{  php_add_field_properties */
1133 static void php_add_field_properties(zval *value, const MYSQL_FIELD *field)
1134 {
1135 #ifdef MYSQLI_USE_MYSQLND
1136 	add_property_str(value, "name", zend_string_copy(field->sname));
1137 #else
1138 	add_property_stringl(value, "name",(field->name ? field->name : ""), field->name_length);
1139 #endif
1140 
1141 	add_property_stringl(value, "orgname", (field->org_name ? field->org_name : ""), field->org_name_length);
1142 	add_property_stringl(value, "table", (field->table ? field->table : ""), field->table_length);
1143 	add_property_stringl(value, "orgtable", (field->org_table ? field->org_table : ""), field->org_table_length);
1144 	add_property_stringl(value, "def", (field->def ? field->def : ""), field->def_length);
1145 	add_property_stringl(value, "db", (field->db ? field->db : ""), field->db_length);
1146 
1147 	/* FIXME: manually set the catalog to "def" due to bug in
1148 	 * libmysqlclient which does not initialize field->catalog
1149 	 * and in addition, the catalog is always be "def"
1150 	 */
1151 	add_property_string(value, "catalog", "def");
1152 
1153 	add_property_long(value, "max_length", 0);
1154 	add_property_long(value, "length", field->length);
1155 	add_property_long(value, "charsetnr", field->charsetnr);
1156 	add_property_long(value, "flags", field->flags);
1157 	add_property_long(value, "type", field->type);
1158 	add_property_long(value, "decimals", field->decimals);
1159 }
1160 /* }}} */
1161 
1162 /* {{{ Get column information from a result and return as an object */
1163 PHP_FUNCTION(mysqli_fetch_field)
1164 {
1165 	MYSQL_RES	*result;
1166 	zval		*mysql_result;
1167 	const MYSQL_FIELD	*field;
1168 
1169 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) {
1170 		RETURN_THROWS();
1171 	}
1172 
1173 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
1174 
1175 	if (!(field = mysql_fetch_field(result))) {
1176 		RETURN_FALSE;
1177 	}
1178 
1179 	object_init(return_value);
1180 	php_add_field_properties(return_value, field);
1181 }
1182 /* }}} */
1183 
1184 /* {{{ Return array of objects containing field meta-data */
1185 PHP_FUNCTION(mysqli_fetch_fields)
1186 {
1187 	MYSQL_RES	*result;
1188 	zval		*mysql_result;
1189 	zval		obj;
1190 
1191 	unsigned int i, num_fields;
1192 
1193 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) {
1194 		RETURN_THROWS();
1195 	}
1196 
1197 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
1198 
1199 	array_init(return_value);
1200 	num_fields = mysql_num_fields(result);
1201 
1202 	for (i = 0; i < num_fields; i++) {
1203 		const MYSQL_FIELD *field = mysql_fetch_field_direct(result, i);
1204 
1205 		object_init(&obj);
1206 
1207 		php_add_field_properties(&obj, field);
1208 		add_index_zval(return_value, i, &obj);
1209 	}
1210 }
1211 /* }}} */
1212 
1213 /* {{{ Fetch meta-data for a single field */
1214 PHP_FUNCTION(mysqli_fetch_field_direct)
1215 {
1216 	MYSQL_RES	*result;
1217 	zval		*mysql_result;
1218 	const MYSQL_FIELD	*field;
1219 	zend_long		offset;
1220 
1221 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_result, mysqli_result_class_entry, &offset) == FAILURE) {
1222 		RETURN_THROWS();
1223 	}
1224 
1225 	if (offset < 0) {
1226 		zend_argument_value_error(ERROR_ARG_POS(2), "must be greater than or equal to 0");
1227 		RETURN_THROWS();
1228 	}
1229 
1230 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
1231 
1232 	if (offset >= (zend_long) mysql_num_fields(result)) {
1233 		zend_argument_value_error(ERROR_ARG_POS(2), "must be less than the number of fields for this result set");
1234 		RETURN_THROWS();
1235 	}
1236 
1237 	if (!(field = mysql_fetch_field_direct(result,offset))) {
1238 		RETURN_FALSE;
1239 	}
1240 
1241 	object_init(return_value);
1242 	php_add_field_properties(return_value, field);
1243 }
1244 /* }}} */
1245 
1246 /* {{{ Get the length of each output in a result */
1247 PHP_FUNCTION(mysqli_fetch_lengths)
1248 {
1249 	MYSQL_RES		*result;
1250 	zval			*mysql_result;
1251 	unsigned int	i, num_fields;
1252 #ifdef MYSQLI_USE_MYSQLND
1253 	const size_t	*ret;
1254 #else
1255 	const unsigned long *ret;
1256 #endif
1257 
1258 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) {
1259 		RETURN_THROWS();
1260 	}
1261 
1262 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
1263 
1264 	// TODO Warning?
1265 	if (!(ret = mysql_fetch_lengths(result))) {
1266 		RETURN_FALSE;
1267 	}
1268 
1269 	array_init(return_value);
1270 	num_fields = mysql_num_fields(result);
1271 
1272 	for (i = 0; i < num_fields; i++) {
1273 		add_index_long(return_value, i, ret[i]);
1274 	}
1275 }
1276 /* }}} */
1277 
1278 /* {{{ Get a result row as an enumerated array */
1279 PHP_FUNCTION(mysqli_fetch_row)
1280 {
1281 	php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQLI_NUM, 0);
1282 }
1283 /* }}} */
1284 
1285 /* {{{ Fetch the number of fields returned by the last query for the given link */
1286 PHP_FUNCTION(mysqli_field_count)
1287 {
1288 	MY_MYSQL	*mysql;
1289 	zval		*mysql_link;
1290 
1291 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1292 		RETURN_THROWS();
1293 	}
1294 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1295 
1296 	RETURN_LONG(mysql_field_count(mysql->mysql));
1297 }
1298 /* }}} */
1299 
1300 /* {{{ Set result pointer to a specified field offset */
1301 PHP_FUNCTION(mysqli_field_seek)
1302 {
1303 	MYSQL_RES		*result;
1304 	zval			*mysql_result;
1305 	zend_long	fieldnr;
1306 
1307 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_result, mysqli_result_class_entry, &fieldnr) == FAILURE) {
1308 		RETURN_THROWS();
1309 	}
1310 
1311 	if (fieldnr < 0) {
1312 		zend_argument_value_error(ERROR_ARG_POS(2), "must be greater than or equal to 0");
1313 		RETURN_THROWS();
1314 	}
1315 
1316 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
1317 
1318 	if ((uint32_t)fieldnr >= mysql_num_fields(result)) {
1319 		zend_argument_value_error(ERROR_ARG_POS(2), "must be less than the number of fields for this result set");
1320 		RETURN_THROWS();
1321 	}
1322 
1323 	mysql_field_seek(result, fieldnr);
1324 	RETURN_TRUE;
1325 }
1326 /* }}} */
1327 
1328 /* {{{ Get current field offset of result pointer */
1329 PHP_FUNCTION(mysqli_field_tell)
1330 {
1331 	MYSQL_RES	*result;
1332 	zval		*mysql_result;
1333 
1334 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) {
1335 		RETURN_THROWS();
1336 	}
1337 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
1338 
1339 	RETURN_LONG(mysql_field_tell(result));
1340 }
1341 /* }}} */
1342 
1343 /* {{{ Free query result memory for the given result handle */
1344 PHP_FUNCTION(mysqli_free_result)
1345 {
1346 	MYSQL_RES	*result;
1347 	zval		*mysql_result;
1348 
1349 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) {
1350 		RETURN_THROWS();
1351 	}
1352 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
1353 
1354 	mysqli_free_result(result, false);
1355 	MYSQLI_CLEAR_RESOURCE(mysql_result);
1356 }
1357 /* }}} */
1358 
1359 /* {{{ Get MySQL client info */
1360 PHP_FUNCTION(mysqli_get_client_info)
1361 {
1362 	if (getThis()) {
1363 		if (zend_parse_parameters_none() == FAILURE) {
1364 			RETURN_THROWS();
1365 		}
1366 	} else {
1367 		zval *mysql_link;
1368 
1369 		if (zend_parse_parameters(ZEND_NUM_ARGS(), "|O!", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1370 			RETURN_THROWS();
1371 		}
1372 
1373 		if (ZEND_NUM_ARGS()) {
1374 			php_error_docref(NULL, E_DEPRECATED, "Passing connection object as an argument is deprecated");
1375 		}
1376 	}
1377 
1378 	RETURN_STRING(mysql_get_client_info());
1379 }
1380 /* }}} */
1381 
1382 /* {{{ Get MySQL client info */
1383 PHP_FUNCTION(mysqli_get_client_version)
1384 {
1385 	if (zend_parse_parameters_none() == FAILURE) {
1386 		RETURN_THROWS();
1387 	}
1388 
1389 	RETURN_LONG((zend_long)mysql_get_client_version());
1390 }
1391 /* }}} */
1392 
1393 /* {{{ Get MySQL host info */
1394 PHP_FUNCTION(mysqli_get_host_info)
1395 {
1396 	MY_MYSQL	*mysql;
1397 	zval		*mysql_link = NULL;
1398 
1399 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1400 		RETURN_THROWS();
1401 	}
1402 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1403 #ifndef MYSQLI_USE_MYSQLND
1404 	RETURN_STRING((mysql->mysql->host_info) ? mysql->mysql->host_info : "");
1405 #else
1406 	RETURN_STRING((mysql->mysql->data->host_info) ? mysql->mysql->data->host_info : "");
1407 #endif
1408 }
1409 /* }}} */
1410 
1411 /* {{{ Get MySQL protocol information */
1412 PHP_FUNCTION(mysqli_get_proto_info)
1413 {
1414 	MY_MYSQL	*mysql;
1415 	zval		*mysql_link = NULL;
1416 
1417 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1418 		RETURN_THROWS();
1419 	}
1420 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1421 	RETURN_LONG(mysql_get_proto_info(mysql->mysql));
1422 }
1423 /* }}} */
1424 
1425 /* {{{ Get MySQL server info */
1426 PHP_FUNCTION(mysqli_get_server_info)
1427 {
1428 	MY_MYSQL	*mysql;
1429 	zval		*mysql_link = NULL;
1430 
1431 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1432 		RETURN_THROWS();
1433 	}
1434 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1435 
1436 	RETURN_STRING(mysql_get_server_info(mysql->mysql));
1437 }
1438 /* }}} */
1439 
1440 /* {{{ Return the MySQL version for the server referenced by the given link */
1441 PHP_FUNCTION(mysqli_get_server_version)
1442 {
1443 	MY_MYSQL	*mysql;
1444 	zval		*mysql_link = NULL;
1445 
1446 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1447 		RETURN_THROWS();
1448 	}
1449 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1450 
1451 	RETURN_LONG(mysql_get_server_version(mysql->mysql));
1452 }
1453 /* }}} */
1454 
1455 /* {{{ Get information about the most recent query */
1456 PHP_FUNCTION(mysqli_info)
1457 {
1458 	MY_MYSQL	*mysql;
1459 	zval		*mysql_link = NULL;
1460 	const char	*info;
1461 
1462 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1463 		RETURN_THROWS();
1464 	}
1465 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1466 
1467 	info = mysql_info(mysql->mysql);
1468 	if (info) {
1469 		RETURN_STRING(info);
1470 	}
1471 }
1472 /* }}} */
1473 
1474 /* {{{ php_mysqli_init() */
1475 void php_mysqli_init(INTERNAL_FUNCTION_PARAMETERS, bool is_method)
1476 {
1477 	MYSQLI_RESOURCE *mysqli_resource;
1478 	MY_MYSQL *mysql;
1479 
1480 	if (zend_parse_parameters_none() == FAILURE) {
1481 		RETURN_THROWS();
1482 	}
1483 
1484 	if (is_method && (Z_MYSQLI_P(getThis()))->ptr) {
1485 		return;
1486 	}
1487 
1488 	mysql = (MY_MYSQL *)ecalloc(1, sizeof(MY_MYSQL));
1489 
1490 #ifndef MYSQLI_USE_MYSQLND
1491 	if (!(mysql->mysql = mysql_init(NULL)))
1492 #else
1493 	/*
1494 	  We create always persistent, as if the user want to connect
1495 	  to p:somehost, we can't convert the handle then
1496 	*/
1497 	if (!(mysql->mysql = mysqlnd_init(MYSQLND_CLIENT_NO_FLAG, true)))
1498 #endif
1499 	{
1500 		efree(mysql);
1501 		RETURN_FALSE;
1502 	}
1503 
1504 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
1505 	mysqli_resource->ptr = (void *)mysql;
1506 	mysqli_resource->status = MYSQLI_STATUS_INITIALIZED;
1507 
1508 	if (!is_method) {
1509 		MYSQLI_RETVAL_RESOURCE(mysqli_resource, mysqli_link_class_entry);
1510 	} else {
1511 		(Z_MYSQLI_P(getThis()))->ptr = mysqli_resource;
1512 	}
1513 }
1514 /* }}} */
1515 
1516 /* {{{ Initialize mysqli and return a resource for use with mysql_real_connect */
1517 PHP_FUNCTION(mysqli_init)
1518 {
1519 	php_mysqli_init(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
1520 }
1521 /* }}} */
1522 
1523 /* {{{ Get the ID generated from the previous INSERT operation */
1524 PHP_FUNCTION(mysqli_insert_id)
1525 {
1526 	MY_MYSQL		*mysql;
1527 	my_ulonglong	rc;
1528 	zval			*mysql_link;
1529 
1530 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1531 		RETURN_THROWS();
1532 	}
1533 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1534 	rc = mysql_insert_id(mysql->mysql);
1535 	MYSQLI_RETURN_LONG_INT(rc)
1536 }
1537 /* }}} */
1538 
1539 /* {{{ Kill a mysql process on the server */
1540 PHP_FUNCTION(mysqli_kill)
1541 {
1542 	MY_MYSQL	*mysql;
1543 	zval		*mysql_link;
1544 	zend_long		processid;
1545 
1546 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_link, mysqli_link_class_entry, &processid) == FAILURE) {
1547 		RETURN_THROWS();
1548 	}
1549 
1550 	if (processid <= 0) {
1551 		zend_argument_value_error(ERROR_ARG_POS(2), "must be greater than 0");
1552 		RETURN_THROWS();
1553 	}
1554 
1555 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1556 
1557 	if (mysql_kill(mysql->mysql, processid)) {
1558 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1559 		RETURN_FALSE;
1560 	}
1561 	RETURN_TRUE;
1562 }
1563 /* }}} */
1564 
1565 /* {{{ check if there any more query results from a multi query */
1566 PHP_FUNCTION(mysqli_more_results)
1567 {
1568 	MY_MYSQL	*mysql;
1569 	zval		*mysql_link;
1570 
1571 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1572 		RETURN_THROWS();
1573 	}
1574 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1575 
1576 	RETURN_BOOL(mysql_more_results(mysql->mysql));
1577 }
1578 /* }}} */
1579 
1580 /* {{{ read next result from multi_query */
1581 PHP_FUNCTION(mysqli_next_result) {
1582 	MY_MYSQL	*mysql;
1583 	zval		*mysql_link;
1584 
1585 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1586 		RETURN_THROWS();
1587 	}
1588 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1589 
1590 	if (mysql_next_result(mysql->mysql)) {
1591 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1592 		RETURN_FALSE;
1593 	}
1594 	RETURN_TRUE;
1595 }
1596 /* }}} */
1597 
1598 /* TODO: Make these available without mysqlnd */
1599 #if defined(MYSQLI_USE_MYSQLND)
1600 /* {{{ check if there any more query results from a multi query */
1601 PHP_FUNCTION(mysqli_stmt_more_results)
1602 {
1603 	MY_STMT		*stmt;
1604 	zval		*mysql_stmt;
1605 
1606 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
1607 		RETURN_THROWS();
1608 	}
1609 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1610 
1611 	RETURN_BOOL(mysqlnd_stmt_more_results(stmt->stmt));
1612 }
1613 /* }}} */
1614 #endif
1615 
1616 /* {{{ read next result from multi_query */
1617 PHP_FUNCTION(mysqli_stmt_next_result) {
1618 	MY_STMT		*stmt;
1619 	zval		*mysql_stmt;
1620 
1621 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
1622 		RETURN_THROWS();
1623 	}
1624 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1625 
1626 	if (mysql_stmt_next_result(stmt->stmt)) {
1627 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
1628 		RETURN_FALSE;
1629 	}
1630 	RETURN_TRUE;
1631 }
1632 /* }}} */
1633 
1634 /* {{{ Get number of fields in result */
1635 PHP_FUNCTION(mysqli_num_fields)
1636 {
1637 	MYSQL_RES	*result;
1638 	zval		*mysql_result;
1639 
1640 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) {
1641 		RETURN_THROWS();
1642 	}
1643 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
1644 
1645 	RETURN_LONG(mysql_num_fields(result));
1646 }
1647 /* }}} */
1648 
1649 /* {{{ Get number of rows in result */
1650 PHP_FUNCTION(mysqli_num_rows)
1651 {
1652 	MYSQL_RES	*result;
1653 	zval		*mysql_result;
1654 
1655 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) {
1656 		RETURN_THROWS();
1657 	}
1658 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
1659 
1660 	if (mysqli_result_is_unbuffered_and_not_everything_is_fetched(result)) {
1661 		zend_throw_error(NULL, "mysqli_num_rows() cannot be used in MYSQLI_USE_RESULT mode");
1662 		RETURN_THROWS();
1663 	}
1664 
1665 	MYSQLI_RETURN_LONG_INT(mysql_num_rows(result));
1666 }
1667 /* }}} */
1668 
1669 /* {{{ mysqli_options_get_option_zval_type */
1670 static int mysqli_options_get_option_zval_type(int option)
1671 {
1672 	switch (option) {
1673 #ifdef MYSQLI_USE_MYSQLND
1674 		case MYSQLND_OPT_NET_CMD_BUFFER_SIZE:
1675 		case MYSQLND_OPT_NET_READ_BUFFER_SIZE:
1676 		case MYSQLND_OPT_INT_AND_FLOAT_NATIVE:
1677 #endif /* MYSQLI_USE_MYSQLND */
1678 		case MYSQL_OPT_CONNECT_TIMEOUT:
1679 #ifdef MYSQL_REPORT_DATA_TRUNCATION
1680 		case MYSQL_REPORT_DATA_TRUNCATION:
1681 #endif
1682 		case MYSQL_OPT_LOCAL_INFILE:
1683 		case MYSQL_OPT_NAMED_PIPE:
1684 #ifdef MYSQL_OPT_PROTOCOL
1685 		case MYSQL_OPT_PROTOCOL:
1686 #endif /* MySQL 4.1.0 */
1687 		case MYSQL_OPT_READ_TIMEOUT:
1688 		case MYSQL_OPT_WRITE_TIMEOUT:
1689 #ifdef MYSQL_OPT_GUESS_CONNECTION /* removed in MySQL-8.0 */
1690 		case MYSQL_OPT_GUESS_CONNECTION:
1691 		case MYSQL_OPT_USE_EMBEDDED_CONNECTION:
1692 		case MYSQL_OPT_USE_REMOTE_CONNECTION:
1693 		case MYSQL_SECURE_AUTH:
1694 #endif
1695 #ifdef MYSQL_OPT_RECONNECT
1696 		case MYSQL_OPT_RECONNECT:
1697 #endif /* MySQL 5.0.13 */
1698 #ifdef MYSQL_OPT_SSL_VERIFY_SERVER_CERT
1699 		case MYSQL_OPT_SSL_VERIFY_SERVER_CERT:
1700 #endif /* MySQL 5.0.23 */
1701 #ifdef MYSQL_OPT_COMPRESS
1702 		case MYSQL_OPT_COMPRESS:
1703 #endif /* mysqlnd @ PHP 5.3.2 */
1704 #if (MYSQL_VERSION_ID >= 50611 && defined(CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS)) || defined(MYSQLI_USE_MYSQLND)
1705 		case MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS:
1706 #endif
1707 			return IS_LONG;
1708 
1709 #ifdef MYSQL_SHARED_MEMORY_BASE_NAME
1710 		case MYSQL_SHARED_MEMORY_BASE_NAME:
1711 #endif /* MySQL 4.1.0 */
1712 #ifdef MYSQL_SET_CLIENT_IP
1713 		case MYSQL_SET_CLIENT_IP:
1714 #endif /* MySQL 4.1.1 */
1715 		case MYSQL_READ_DEFAULT_FILE:
1716 		case MYSQL_READ_DEFAULT_GROUP:
1717 		case MYSQL_INIT_COMMAND:
1718 		case MYSQL_SET_CHARSET_NAME:
1719 		case MYSQL_SET_CHARSET_DIR:
1720 #if MYSQL_VERSION_ID > 50605 || defined(MYSQLI_USE_MYSQLND)
1721 		case MYSQL_SERVER_PUBLIC_KEY:
1722 #endif
1723 #if (MYSQL_VERSION_ID >= 80021 && !defined(MARIADB_BASE_VERSION)) || defined(MYSQLI_USE_MYSQLND)
1724 		case MYSQL_OPT_LOAD_DATA_LOCAL_DIR:
1725 #endif
1726 			return IS_STRING;
1727 
1728 		default:
1729 			return IS_NULL;
1730 	}
1731 }
1732 /* }}} */
1733 
1734 /* {{{ Set options */
1735 PHP_FUNCTION(mysqli_options)
1736 {
1737 	MY_MYSQL		*mysql;
1738 	zval			*mysql_link = NULL;
1739 	zval			*mysql_value;
1740 	zend_long			mysql_option;
1741 	unsigned int	l_value;
1742 	zend_long			ret;
1743 	int				expected_type;
1744 
1745 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Olz", &mysql_link, mysqli_link_class_entry, &mysql_option, &mysql_value) == FAILURE) {
1746 		RETURN_THROWS();
1747 	}
1748 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_INITIALIZED);
1749 
1750 #ifndef MYSQLI_USE_MYSQLND
1751 	if (PG(open_basedir) && PG(open_basedir)[0] != '\0') {
1752 		if(mysql_option == MYSQL_OPT_LOCAL_INFILE) {
1753 			RETURN_FALSE;
1754 		}
1755 	}
1756 #endif
1757 	expected_type = mysqli_options_get_option_zval_type(mysql_option);
1758 	if (expected_type != Z_TYPE_P(mysql_value)) {
1759 		switch (expected_type) {
1760 			case IS_STRING:
1761 				if (!try_convert_to_string(mysql_value)) {
1762 					RETURN_THROWS();
1763 				}
1764 				break;
1765 			case IS_LONG:
1766 				convert_to_long(mysql_value);
1767 				break;
1768 			default:
1769 				break;
1770 		}
1771 	}
1772 	switch (expected_type) {
1773 		case IS_STRING:
1774 			if ((ret = mysql_options(mysql->mysql, mysql_option, Z_STRVAL_P(mysql_value)))) {
1775 				MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1776 			}
1777 			break;
1778 		case IS_LONG:
1779 			l_value = Z_LVAL_P(mysql_value);
1780 			if ((ret = mysql_options(mysql->mysql, mysql_option, (char *)&l_value))) {
1781 				MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1782 			}
1783 			break;
1784 		default:
1785 			ret = 1;
1786 			break;
1787 	}
1788 
1789 	RETURN_BOOL(!ret);
1790 }
1791 /* }}} */
1792 
1793 /* {{{ Ping a server connection or reconnect if there is no connection */
1794 PHP_FUNCTION(mysqli_ping)
1795 {
1796 	MY_MYSQL	*mysql;
1797 	zval		*mysql_link;
1798 	zend_long		rc;
1799 
1800 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1801 		RETURN_THROWS();
1802 	}
1803 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1804 	rc = mysql_ping(mysql->mysql);
1805 	MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1806 
1807 	RETURN_BOOL(!rc);
1808 }
1809 /* }}} */
1810 
1811 /* {{{ Prepare a SQL statement for execution */
1812 PHP_FUNCTION(mysqli_prepare)
1813 {
1814 	MY_MYSQL		*mysql;
1815 	MY_STMT			*stmt;
1816 	char			*query = NULL;
1817 	size_t				query_len;
1818 	zval			*mysql_link;
1819 	MYSQLI_RESOURCE	*mysqli_resource;
1820 
1821 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os",&mysql_link, mysqli_link_class_entry, &query, &query_len) == FAILURE) {
1822 		RETURN_THROWS();
1823 	}
1824 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1825 
1826 #ifndef MYSQLI_USE_MYSQLND
1827 	if (mysql->mysql->status == MYSQL_STATUS_GET_RESULT) {
1828 		php_error_docref(NULL, E_WARNING, "All data must be fetched before a new statement prepare takes place");
1829 		RETURN_FALSE;
1830 	}
1831 #endif
1832 
1833 	stmt = (MY_STMT *)ecalloc(1,sizeof(MY_STMT));
1834 
1835 	if ((stmt->stmt = mysql_stmt_init(mysql->mysql))) {
1836 		if (mysql_stmt_prepare(stmt->stmt, query, query_len)) {
1837 			/* mysql_stmt_close() clears errors, so we have to store them temporarily */
1838 #ifndef MYSQLI_USE_MYSQLND
1839 			char  last_error[MYSQL_ERRMSG_SIZE];
1840 			char  sqlstate[SQLSTATE_LENGTH+1];
1841 			unsigned int last_errno;
1842 
1843 			last_errno = stmt->stmt->last_errno;
1844 			memcpy(last_error, stmt->stmt->last_error, MYSQL_ERRMSG_SIZE);
1845 			memcpy(sqlstate, mysql->mysql->net.sqlstate, SQLSTATE_LENGTH+1);
1846 #else
1847 			MYSQLND_ERROR_INFO error_info = *mysql->mysql->data->error_info;
1848 			mysql->mysql->data->error_info->error_list.head = NULL;
1849 			mysql->mysql->data->error_info->error_list.tail = NULL;
1850 			mysql->mysql->data->error_info->error_list.count = 0;
1851 #endif
1852 			mysqli_stmt_close(stmt->stmt, false);
1853 			stmt->stmt = NULL;
1854 
1855 			/* restore error messages */
1856 #ifndef MYSQLI_USE_MYSQLND
1857 			mysql->mysql->net.last_errno = last_errno;
1858 			memcpy(mysql->mysql->net.last_error, last_error, MYSQL_ERRMSG_SIZE);
1859 			memcpy(mysql->mysql->net.sqlstate, sqlstate, SQLSTATE_LENGTH+1);
1860 #else
1861 			zend_llist_clean(&mysql->mysql->data->error_info->error_list);
1862 			*mysql->mysql->data->error_info = error_info;
1863 #endif
1864 		}
1865 	}
1866 
1867 	/* don't initialize stmt->query with NULL, we ecalloc()-ed the memory */
1868 	/* Get performance boost if reporting is switched off */
1869 	if (stmt->stmt && query_len && (MyG(report_mode) & MYSQLI_REPORT_INDEX)) {
1870 		stmt->query = (char *)emalloc(query_len + 1);
1871 		memcpy(stmt->query, query, query_len);
1872 		stmt->query[query_len] = '\0';
1873 	}
1874 
1875 	/* don't join to the previous if because it won't work if mysql_stmt_prepare_fails */
1876 	if (!stmt->stmt) {
1877 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1878 		efree(stmt);
1879 		RETURN_FALSE;
1880 	}
1881 #ifndef MYSQLI_USE_MYSQLND
1882 	ZVAL_COPY(&stmt->link_handle, mysql_link);
1883 #endif
1884 
1885 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
1886 	mysqli_resource->ptr = (void *)stmt;
1887 
1888 	/* change status */
1889 	mysqli_resource->status = MYSQLI_STATUS_VALID;
1890 	MYSQLI_RETVAL_RESOURCE(mysqli_resource, mysqli_stmt_class_entry);
1891 }
1892 /* }}} */
1893 
1894 /* {{{ Open a connection to a mysql server */
1895 PHP_FUNCTION(mysqli_real_connect)
1896 {
1897 	mysqli_common_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, true, false);
1898 }
1899 /* }}} */
1900 
1901 /* {{{ Binary-safe version of mysql_query() */
1902 PHP_FUNCTION(mysqli_real_query)
1903 {
1904 	MY_MYSQL	*mysql;
1905 	zval		*mysql_link;
1906 	char		*query = NULL;
1907 	size_t		query_len;
1908 
1909 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_link, mysqli_link_class_entry, &query, &query_len) == FAILURE) {
1910 		RETURN_THROWS();
1911 	}
1912 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1913 
1914 	MYSQLI_DISABLE_MQ; /* disable multi statements/queries */
1915 
1916 	if (mysql_real_query(mysql->mysql, query, query_len)) {
1917 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1918 		RETURN_FALSE;
1919 	}
1920 
1921 	if (!mysql_field_count(mysql->mysql)) {
1922 		if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
1923 			php_mysqli_report_index(query, mysqli_server_status(mysql->mysql));
1924 		}
1925 	}
1926 
1927 	RETURN_TRUE;
1928 }
1929 /* }}} */
1930 
1931 #if defined(MYSQLI_USE_MYSQLND) || MYSQL_VERSION_ID < 50707 || defined(MARIADB_BASE_VERSION)
1932 # define mysql_real_escape_string_quote(mysql, to, from, length, quote) \
1933 	mysql_real_escape_string(mysql, to, from, length)
1934 #endif
1935 
1936 PHP_FUNCTION(mysqli_real_escape_string) {
1937 	MY_MYSQL	*mysql;
1938 	zval		*mysql_link = NULL;
1939 	char		*escapestr;
1940 	size_t			escapestr_len;
1941 	zend_string *newstr;
1942 
1943 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_link, mysqli_link_class_entry, &escapestr, &escapestr_len) == FAILURE) {
1944 		RETURN_THROWS();
1945 	}
1946 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1947 
1948 	newstr = zend_string_safe_alloc(2, escapestr_len, 0, 0);
1949 	ZSTR_LEN(newstr) = mysql_real_escape_string_quote(mysql->mysql, ZSTR_VAL(newstr), escapestr, escapestr_len, '\'');
1950 	newstr = zend_string_truncate(newstr, ZSTR_LEN(newstr), 0);
1951 
1952 	RETURN_NEW_STR(newstr);
1953 }
1954 
1955 /* {{{ Undo actions from current transaction */
1956 PHP_FUNCTION(mysqli_rollback)
1957 {
1958 	MY_MYSQL	*mysql;
1959 	zval		*mysql_link;
1960 	zend_long		flags = TRANS_COR_NO_OPT;
1961 	char *		name = NULL;
1962 	size_t			name_len = 0;
1963 
1964 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|ls!", &mysql_link, mysqli_link_class_entry, &flags, &name, &name_len) == FAILURE) {
1965 		RETURN_THROWS();
1966 	}
1967 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1968 
1969 #ifndef MYSQLI_USE_MYSQLND
1970 	if (mysqli_commit_or_rollback_libmysql(mysql->mysql, false, flags, name)) {
1971 #else
1972 	if (FAIL == mysqlnd_rollback(mysql->mysql, flags, name)) {
1973 #endif
1974 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1975 		RETURN_FALSE;
1976 	}
1977 	RETURN_TRUE;
1978 }
1979 /* }}} */
1980 
1981 /* {{{ */
1982 PHP_FUNCTION(mysqli_stmt_send_long_data)
1983 {
1984 	MY_STMT *stmt;
1985 	zval	*mysql_stmt;
1986 	char	*data;
1987 	zend_long	param_nr;
1988 	size_t		data_len;
1989 
1990 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ols", &mysql_stmt, mysqli_stmt_class_entry, &param_nr, &data, &data_len) == FAILURE) {
1991 		RETURN_THROWS();
1992 	}
1993 
1994 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1995 
1996 	if (param_nr < 0) {
1997 		zend_argument_value_error(ERROR_ARG_POS(2), "must be greater than or equal to 0");
1998 		RETURN_THROWS();
1999 	}
2000 
2001 	if (mysql_stmt_send_long_data(stmt->stmt, param_nr, data, data_len)) {
2002 		RETURN_FALSE;
2003 	}
2004 	RETURN_TRUE;
2005 }
2006 /* }}} */
2007 
2008 /* {{{ Return the number of rows affected in the last query for the given link. */
2009 PHP_FUNCTION(mysqli_stmt_affected_rows)
2010 {
2011 	MY_STMT			*stmt;
2012 	zval			*mysql_stmt;
2013 	my_ulonglong	rc;
2014 
2015 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2016 		RETURN_THROWS();
2017 	}
2018 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2019 
2020 	rc = mysql_stmt_affected_rows(stmt->stmt);
2021 	if (rc == (my_ulonglong) -1) {
2022 		RETURN_LONG(-1);
2023 	}
2024 	MYSQLI_RETURN_LONG_INT(rc)
2025 }
2026 /* }}} */
2027 
2028 /* {{{ Close statement */
2029 PHP_FUNCTION(mysqli_stmt_close)
2030 {
2031 	MY_STMT		*stmt;
2032 	zval		*mysql_stmt;
2033 
2034 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2035 		RETURN_THROWS();
2036 	}
2037 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2038 
2039 	mysqli_stmt_close(stmt->stmt, false);
2040 	stmt->stmt = NULL;
2041 	php_clear_stmt_bind(stmt);
2042 	MYSQLI_CLEAR_RESOURCE(mysql_stmt);
2043 	RETURN_TRUE;
2044 }
2045 /* }}} */
2046 
2047 /* {{{ Move internal result pointer */
2048 PHP_FUNCTION(mysqli_stmt_data_seek)
2049 {
2050 	MY_STMT		*stmt;
2051 	zval		*mysql_stmt;
2052 	zend_long		offset;
2053 
2054 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_stmt, mysqli_stmt_class_entry, &offset) == FAILURE) {
2055 		RETURN_THROWS();
2056 	}
2057 
2058 	if (offset < 0) {
2059 		zend_argument_value_error(ERROR_ARG_POS(2), "must be greater than or equal to 0");
2060 		RETURN_THROWS();
2061 	}
2062 
2063 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2064 
2065 	mysql_stmt_data_seek(stmt->stmt, offset);
2066 }
2067 /* }}} */
2068 
2069 /* {{{ Return the number of result columns for the given statement */
2070 PHP_FUNCTION(mysqli_stmt_field_count)
2071 {
2072 	MY_STMT		*stmt;
2073 	zval		*mysql_stmt;
2074 
2075 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2076 		RETURN_THROWS();
2077 	}
2078 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2079 
2080 	RETURN_LONG(mysql_stmt_field_count(stmt->stmt));
2081 }
2082 /* }}} */
2083 
2084 /* {{{ Free stored result memory for the given statement handle */
2085 PHP_FUNCTION(mysqli_stmt_free_result)
2086 {
2087 	MY_STMT		*stmt;
2088 	zval		*mysql_stmt;
2089 
2090 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2091 		RETURN_THROWS();
2092 	}
2093 
2094 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2095 
2096 	mysql_stmt_free_result(stmt->stmt);
2097 }
2098 /* }}} */
2099 
2100 /* {{{ Get the ID generated from the previous INSERT operation */
2101 PHP_FUNCTION(mysqli_stmt_insert_id)
2102 {
2103 	MY_STMT			*stmt;
2104 	my_ulonglong	rc;
2105 	zval			*mysql_stmt;
2106 
2107 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2108 		RETURN_THROWS();
2109 	}
2110 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2111 	rc = mysql_stmt_insert_id(stmt->stmt);
2112 	MYSQLI_RETURN_LONG_INT(rc)
2113 }
2114 /* }}} */
2115 
2116 /* {{{ Return the number of parameter for the given statement */
2117 PHP_FUNCTION(mysqli_stmt_param_count)
2118 {
2119 	MY_STMT		*stmt;
2120 	zval		*mysql_stmt;
2121 
2122 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2123 		RETURN_THROWS();
2124 	}
2125 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2126 
2127 	RETURN_LONG(mysql_stmt_param_count(stmt->stmt));
2128 }
2129 /* }}} */
2130 
2131 /* {{{ reset a prepared statement */
2132 PHP_FUNCTION(mysqli_stmt_reset)
2133 {
2134 	MY_STMT		*stmt;
2135 	zval		*mysql_stmt;
2136 
2137 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2138 		RETURN_THROWS();
2139 	}
2140 
2141 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2142 
2143 	if (mysql_stmt_reset(stmt->stmt)) {
2144 		RETURN_FALSE;
2145 	}
2146 	RETURN_TRUE;
2147 }
2148 /* }}} */
2149 
2150 /* {{{ Return the number of rows in statements result set */
2151 PHP_FUNCTION(mysqli_stmt_num_rows)
2152 {
2153 	MY_STMT			*stmt;
2154 	zval			*mysql_stmt;
2155 	my_ulonglong	rc;
2156 
2157 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2158 		RETURN_THROWS();
2159 	}
2160 
2161 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2162 
2163 	rc = mysql_stmt_num_rows(stmt->stmt);
2164 	MYSQLI_RETURN_LONG_INT(rc)
2165 }
2166 /* }}} */
2167 
2168 /* {{{ Select a MySQL database */
2169 PHP_FUNCTION(mysqli_select_db)
2170 {
2171 	MY_MYSQL	*mysql;
2172 	zval		*mysql_link;
2173 	char		*dbname;
2174 	size_t			dbname_len;
2175 
2176 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_link, mysqli_link_class_entry, &dbname, &dbname_len) == FAILURE) {
2177 		RETURN_THROWS();
2178 	}
2179 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
2180 
2181 	if (mysql_select_db(mysql->mysql, dbname)) {
2182 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
2183 		RETURN_FALSE;
2184 	}
2185 	RETURN_TRUE;
2186 }
2187 /* }}} */
2188 
2189 /* {{{ Returns the SQLSTATE error from previous MySQL operation */
2190 PHP_FUNCTION(mysqli_sqlstate)
2191 {
2192 	MY_MYSQL	*mysql;
2193 	zval		*mysql_link;
2194 
2195 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
2196 		RETURN_THROWS();
2197 	}
2198 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
2199 	RETURN_STRING(mysql_sqlstate(mysql->mysql));
2200 }
2201 /* }}} */
2202 
2203 /* {{{ */
2204 PHP_FUNCTION(mysqli_ssl_set)
2205 {
2206 	MY_MYSQL	*mysql;
2207 	zval		*mysql_link;
2208 	char		*ssl_parm[5];
2209 	size_t			ssl_parm_len[5], i;
2210 
2211 	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) {
2212 		RETURN_THROWS();
2213 	}
2214 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_INITIALIZED);
2215 
2216 	for (i = 0; i < 5; i++) {
2217 		if (!ssl_parm_len[i]) {
2218 			ssl_parm[i] = NULL;
2219 		}
2220 	}
2221 
2222 	mysql_ssl_set(mysql->mysql, ssl_parm[0], ssl_parm[1], ssl_parm[2], ssl_parm[3], ssl_parm[4]);
2223 
2224 	RETURN_TRUE;
2225 }
2226 /* }}} */
2227 
2228 /* {{{ Get current system status */
2229 PHP_FUNCTION(mysqli_stat)
2230 {
2231 	MY_MYSQL	*mysql;
2232 	zval		*mysql_link;
2233 #ifdef MYSQLI_USE_MYSQLND
2234 	zend_string *stat;
2235 #else
2236 	char		*stat;
2237 #endif
2238 
2239 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
2240 		RETURN_THROWS();
2241 	}
2242 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
2243 
2244 #ifndef MYSQLI_USE_MYSQLND
2245 	if ((stat = (char *)mysql_stat(mysql->mysql)))
2246 	{
2247 		RETURN_STRING(stat);
2248 #else
2249 	if (mysqlnd_stat(mysql->mysql, &stat) == PASS)
2250 	{
2251 		RETURN_STR(stat);
2252 #endif
2253 	} else {
2254 		RETURN_FALSE;
2255 	}
2256 }
2257 
2258 /* }}} */
2259 
2260 /* {{{ Flush tables or caches, or reset replication server information */
2261 PHP_FUNCTION(mysqli_refresh)
2262 {
2263 	MY_MYSQL *mysql;
2264 	zval *mysql_link = NULL;
2265 	zend_long options;
2266 
2267 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_link, mysqli_link_class_entry, &options) == FAILURE) {
2268 		RETURN_THROWS();
2269 	}
2270 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_INITIALIZED);
2271 #ifdef MYSQLI_USE_MYSQLND
2272 	RETURN_BOOL(!mysql_refresh(mysql->mysql, (uint8_t) options));
2273 #else
2274 	RETURN_BOOL(!mysql_refresh(mysql->mysql, options));
2275 #endif
2276 }
2277 /* }}} */
2278 
2279 /* {{{ */
2280 PHP_FUNCTION(mysqli_stmt_attr_set)
2281 {
2282 	MY_STMT	*stmt;
2283 	zval	*mysql_stmt;
2284 	zend_long	mode_in;
2285 	my_bool mode_b;
2286 	unsigned long	mode;
2287 	zend_long	attr;
2288 	void	*mode_p;
2289 
2290 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oll", &mysql_stmt, mysqli_stmt_class_entry, &attr, &mode_in) == FAILURE) {
2291 		RETURN_THROWS();
2292 	}
2293 
2294 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2295 
2296 	switch (attr) {
2297 	case STMT_ATTR_UPDATE_MAX_LENGTH:
2298 		if (mode_in != 0 && mode_in != 1) {
2299 			zend_argument_value_error(ERROR_ARG_POS(3), "must be 0 or 1 for attribute MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH");
2300 			RETURN_THROWS();
2301 		}
2302 		mode_b = (my_bool) mode_in;
2303 		mode_p = &mode_b;
2304 		break;
2305 	case STMT_ATTR_CURSOR_TYPE:
2306 		switch (mode_in) {
2307 			case CURSOR_TYPE_NO_CURSOR:
2308 			case CURSOR_TYPE_READ_ONLY:
2309 			case CURSOR_TYPE_FOR_UPDATE:
2310 			case CURSOR_TYPE_SCROLLABLE:
2311 				break;
2312 			default:
2313 				zend_argument_value_error(ERROR_ARG_POS(3), "must be one of the MYSQLI_CURSOR_TYPE_* constants "
2314 					"for attribute MYSQLI_STMT_ATTR_CURSOR_TYPE");
2315 				RETURN_THROWS();
2316 		}
2317 		mode = mode_in;
2318 		mode_p = &mode;
2319 		break;
2320 	case STMT_ATTR_PREFETCH_ROWS:
2321 		if (mode_in < 1) {
2322 			zend_argument_value_error(ERROR_ARG_POS(3), "must be greater than 0 for attribute MYSQLI_STMT_ATTR_PREFETCH_ROWS");
2323 			RETURN_THROWS();
2324 		}
2325 		mode = mode_in;
2326 		mode_p = &mode;
2327 		break;
2328 	default:
2329 		zend_argument_value_error(ERROR_ARG_POS(2), "must be one of "
2330 			"MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH, "
2331 			"MYSQLI_STMT_ATTR_PREFETCH_ROWS, or STMT_ATTR_CURSOR_TYPE");
2332 		RETURN_THROWS();
2333 	}
2334 
2335 // TODO Can unify this?
2336 #ifndef MYSQLI_USE_MYSQLND
2337 	if (mysql_stmt_attr_set(stmt->stmt, attr, mode_p)) {
2338 #else
2339 	if (FAIL == mysql_stmt_attr_set(stmt->stmt, attr, mode_p)) {
2340 #endif
2341 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
2342 		RETURN_FALSE;
2343 	}
2344 	RETURN_TRUE;
2345 }
2346 /* }}} */
2347 
2348 /* {{{ */
2349 PHP_FUNCTION(mysqli_stmt_attr_get)
2350 {
2351 	MY_STMT	*stmt;
2352 	zval	*mysql_stmt;
2353 	unsigned long	value = 0;
2354 	zend_long	attr;
2355 	int		rc;
2356 
2357 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_stmt, mysqli_stmt_class_entry, &attr) == FAILURE) {
2358 		RETURN_THROWS();
2359 	}
2360 
2361 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2362 
2363 	if ((rc = mysql_stmt_attr_get(stmt->stmt, attr, &value))) {
2364 		/* Success corresponds to 0 return value and a non-zero value
2365 		 * should only happen if the attr/option is unknown */
2366 		zend_argument_value_error(ERROR_ARG_POS(2), "must be one of "
2367 			"MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH, "
2368 			"MYSQLI_STMT_ATTR_PREFETCH_ROWS, or STMT_ATTR_CURSOR_TYPE");
2369 		RETURN_THROWS();
2370     }
2371 
2372 
2373 	if (attr == STMT_ATTR_UPDATE_MAX_LENGTH)
2374 		value = *((my_bool *)&value);
2375 	RETURN_LONG((unsigned long)value);
2376 }
2377 /* }}} */
2378 
2379 /* {{{ */
2380 PHP_FUNCTION(mysqli_stmt_errno)
2381 {
2382 	MY_STMT	*stmt;
2383 	zval	*mysql_stmt;
2384 
2385 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2386 		RETURN_THROWS();
2387 	}
2388 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_INITIALIZED);
2389 
2390 	RETURN_LONG(mysql_stmt_errno(stmt->stmt));
2391 }
2392 /* }}} */
2393 
2394 /* {{{ */
2395 PHP_FUNCTION(mysqli_stmt_error)
2396 {
2397 	MY_STMT	*stmt;
2398 	zval 	*mysql_stmt;
2399 
2400 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2401 		RETURN_THROWS();
2402 	}
2403 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_INITIALIZED);
2404 
2405 	RETURN_STRING(mysql_stmt_error(stmt->stmt));
2406 }
2407 /* }}} */
2408 
2409 /* {{{ Initialize statement object */
2410 PHP_FUNCTION(mysqli_stmt_init)
2411 {
2412 	MY_MYSQL		*mysql;
2413 	MY_STMT			*stmt;
2414 	zval			*mysql_link;
2415 	MYSQLI_RESOURCE	*mysqli_resource;
2416 
2417 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",&mysql_link, mysqli_link_class_entry) == FAILURE) {
2418 		RETURN_THROWS();
2419 	}
2420 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
2421 
2422 	stmt = (MY_STMT *)ecalloc(1,sizeof(MY_STMT));
2423 
2424 	if (!(stmt->stmt = mysql_stmt_init(mysql->mysql))) {
2425 		efree(stmt);
2426 		RETURN_FALSE;
2427 	}
2428 #ifndef MYSQLI_USE_MYSQLND
2429 	ZVAL_COPY(&stmt->link_handle, mysql_link);
2430 #endif
2431 
2432 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
2433 	mysqli_resource->status = MYSQLI_STATUS_INITIALIZED;
2434 	mysqli_resource->ptr = (void *)stmt;
2435 	MYSQLI_RETVAL_RESOURCE(mysqli_resource, mysqli_stmt_class_entry);
2436 }
2437 /* }}} */
2438 
2439 /* {{{ prepare server side statement with query */
2440 PHP_FUNCTION(mysqli_stmt_prepare)
2441 {
2442 	MY_STMT	*stmt;
2443 	zval 	*mysql_stmt;
2444 	char	*query;
2445 	size_t		query_len;
2446 
2447 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_stmt, mysqli_stmt_class_entry, &query, &query_len) == FAILURE) {
2448 		RETURN_THROWS();
2449 	}
2450 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_INITIALIZED);
2451 
2452 	if (mysql_stmt_prepare(stmt->stmt, query, query_len)) {
2453 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
2454 		RETURN_FALSE;
2455 	}
2456 	/* change status */
2457 	MYSQLI_SET_STATUS(mysql_stmt, MYSQLI_STATUS_VALID);
2458 	RETURN_TRUE;
2459 }
2460 /* }}} */
2461 
2462 /* {{{ return result set from statement */
2463 PHP_FUNCTION(mysqli_stmt_result_metadata)
2464 {
2465 	MY_STMT			*stmt;
2466 	MYSQL_RES		*result;
2467 	zval			*mysql_stmt;
2468 	MYSQLI_RESOURCE	*mysqli_resource;
2469 
2470 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2471 		RETURN_THROWS();
2472 	}
2473 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2474 
2475 	if (!(result = mysql_stmt_result_metadata(stmt->stmt))){
2476 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
2477 		RETURN_FALSE;
2478 	}
2479 
2480 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
2481 	mysqli_resource->ptr = (void *)result;
2482 	mysqli_resource->status = MYSQLI_STATUS_VALID;
2483 	MYSQLI_RETVAL_RESOURCE(mysqli_resource, mysqli_result_class_entry);
2484 }
2485 /* }}} */
2486 
2487 /* {{{ */
2488 PHP_FUNCTION(mysqli_stmt_store_result)
2489 {
2490 	MY_STMT	*stmt;
2491 	zval	*mysql_stmt;
2492 
2493 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2494 		RETURN_THROWS();
2495 	}
2496 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2497 
2498 #ifndef MYSQLI_USE_MYSQLND
2499 	{
2500 		/*
2501 		  If the user wants to store the data and we have BLOBs/TEXTs we try to allocate
2502 		  not the maximal length of the type (which is 16MB even for LONGBLOB) but
2503 		  the maximal length of the field in the result set. If he/she has quite big
2504 		  BLOB/TEXT columns after calling store_result() the memory usage of PHP will
2505 		  double - but this is a known problem of the simple MySQL API ;)
2506 		*/
2507 		int	i = 0;
2508 
2509 		for (i = mysql_stmt_field_count(stmt->stmt) - 1; i >=0; --i) {
2510 			if (stmt->stmt->fields && (stmt->stmt->fields[i].type == MYSQL_TYPE_BLOB ||
2511 				stmt->stmt->fields[i].type == MYSQL_TYPE_MEDIUM_BLOB ||
2512 				stmt->stmt->fields[i].type == MYSQL_TYPE_LONG_BLOB ||
2513 				stmt->stmt->fields[i].type == MYSQL_TYPE_GEOMETRY))
2514 			{
2515 				my_bool	tmp = 1;
2516 				mysql_stmt_attr_set(stmt->stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &tmp);
2517 				break;
2518 			}
2519 		}
2520 	}
2521 #endif
2522 
2523 	if (mysql_stmt_store_result(stmt->stmt)){
2524 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
2525 		RETURN_FALSE;
2526 	}
2527 	RETURN_TRUE;
2528 }
2529 /* }}} */
2530 
2531 /* {{{ */
2532 PHP_FUNCTION(mysqli_stmt_sqlstate)
2533 {
2534 	MY_STMT	*stmt;
2535 	zval	*mysql_stmt;
2536 
2537 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2538 		RETURN_THROWS();
2539 	}
2540 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2541 
2542 	RETURN_STRING(mysql_stmt_sqlstate(stmt->stmt));
2543 }
2544 /* }}} */
2545 
2546 /* {{{ Buffer result set on client */
2547 PHP_FUNCTION(mysqli_store_result)
2548 {
2549 	MY_MYSQL		*mysql;
2550 	MYSQL_RES		*result;
2551 	zval			*mysql_link;
2552 	MYSQLI_RESOURCE	*mysqli_resource;
2553 	zend_long flags = 0;
2554 
2555 
2556 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|l", &mysql_link, mysqli_link_class_entry, &flags) == FAILURE) {
2557 		RETURN_THROWS();
2558 	}
2559 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
2560 	result = mysql_store_result(mysql->mysql);
2561 	if (!result) {
2562 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
2563 		RETURN_FALSE;
2564 	}
2565 	if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
2566 		php_mysqli_report_index("from previous query", mysqli_server_status(mysql->mysql));
2567 	}
2568 
2569 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
2570 	mysqli_resource->ptr = (void *)result;
2571 	mysqli_resource->status = MYSQLI_STATUS_VALID;
2572 	MYSQLI_RETVAL_RESOURCE(mysqli_resource, mysqli_result_class_entry);
2573 }
2574 /* }}} */
2575 
2576 /* {{{ Return the current thread ID */
2577 PHP_FUNCTION(mysqli_thread_id)
2578 {
2579 	MY_MYSQL	*mysql;
2580 	zval		*mysql_link;
2581 
2582 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
2583 		RETURN_THROWS();
2584 	}
2585 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
2586 
2587 	RETURN_LONG((zend_long) mysql_thread_id(mysql->mysql));
2588 }
2589 /* }}} */
2590 
2591 /* {{{ Return whether thread safety is given or not */
2592 PHP_FUNCTION(mysqli_thread_safe)
2593 {
2594 	if (zend_parse_parameters_none() == FAILURE) {
2595 		RETURN_THROWS();
2596 	}
2597 
2598 	RETURN_BOOL(mysql_thread_safe());
2599 }
2600 /* }}} */
2601 
2602 /* {{{ Directly retrieve query results - do not buffer results on client side */
2603 PHP_FUNCTION(mysqli_use_result)
2604 {
2605 	MY_MYSQL		*mysql;
2606 	MYSQL_RES		*result;
2607 	zval			*mysql_link;
2608 	MYSQLI_RESOURCE	*mysqli_resource;
2609 
2610 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
2611 		RETURN_THROWS();
2612 	}
2613 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
2614 
2615 	if (!(result = mysql_use_result(mysql->mysql))) {
2616 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
2617 		RETURN_FALSE;
2618 	}
2619 
2620 	if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
2621 		php_mysqli_report_index("from previous query", mysqli_server_status(mysql->mysql));
2622 	}
2623 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
2624 	mysqli_resource->ptr = (void *)result;
2625 	mysqli_resource->status = MYSQLI_STATUS_VALID;
2626 	MYSQLI_RETVAL_RESOURCE(mysqli_resource, mysqli_result_class_entry);
2627 }
2628 /* }}} */
2629 
2630 /* {{{ Return number of warnings from the last query for the given link */
2631 PHP_FUNCTION(mysqli_warning_count)
2632 {
2633 	MY_MYSQL	*mysql;
2634 	zval		*mysql_link;
2635 
2636 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
2637 		RETURN_THROWS();
2638 	}
2639 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
2640 
2641 	RETURN_LONG(mysql_warning_count(mysql->mysql));
2642 }
2643 /* }}} */
2644