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