xref: /PHP-8.0/ext/mysqli/mysqli_api.c (revision 5977610d)
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   | http://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 		zend_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 			register 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 == FALSE) {
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,zend_bool commit,const uint32_t mode,const char * const name)110 static int mysqli_commit_or_rollback_libmysql(MYSQL * conn, zend_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 	zend_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 #ifndef MYSQLI_USE_MYSQLND
815 	unsigned int	i;
816 #endif
817 
818 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
819 		RETURN_THROWS();
820 	}
821 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
822 
823 #ifndef MYSQLI_USE_MYSQLND
824 	if (stmt->param.var_cnt) {
825 		int j;
826 		for (i = 0; i < stmt->param.var_cnt; i++) {
827 			if (!Z_ISREF(stmt->param.vars[i])) {
828 				continue;
829 			}
830 			for (j = i + 1; j < stmt->param.var_cnt; j++) {
831 				/* Oops, someone binding the same variable - clone */
832 				if (Z_ISREF(stmt->param.vars[j]) &&
833 					   	Z_REFVAL(stmt->param.vars[j]) == Z_REFVAL(stmt->param.vars[i])) {
834 					/*SEPARATE_ZVAL(&stmt->param.vars[j]);*/
835 					Z_DELREF_P(&stmt->param.vars[j]);
836 					ZVAL_COPY(&stmt->param.vars[j], Z_REFVAL(stmt->param.vars[j]));
837 					break;
838 				}
839 			}
840 		}
841 	}
842 	for (i = 0; i < stmt->param.var_cnt; i++) {
843 		if (!Z_ISUNDEF(stmt->param.vars[i])) {
844 			zval *param;
845 			if (Z_ISREF(stmt->param.vars[i])) {
846 				param = Z_REFVAL(stmt->param.vars[i]);
847 			} else {
848 				param = &stmt->param.vars[i];
849 			}
850 			if (!(stmt->param.is_null[i] = (Z_ISNULL_P(param)))) {
851 				switch (stmt->stmt->params[i].buffer_type) {
852 					case MYSQL_TYPE_VAR_STRING:
853 						if (!try_convert_to_string(param)) {
854 							RETURN_THROWS();
855 						}
856 
857 						stmt->stmt->params[i].buffer = Z_STRVAL_P(param);
858 						stmt->stmt->params[i].buffer_length = Z_STRLEN_P(param);
859 						break;
860 					case MYSQL_TYPE_DOUBLE:
861 						convert_to_double_ex(param);
862 						stmt->stmt->params[i].buffer = &Z_DVAL_P(param);
863 						break;
864 					case MYSQL_TYPE_LONGLONG:
865 					case MYSQL_TYPE_LONG:
866 						convert_to_long_ex(param);
867 						stmt->stmt->params[i].buffer = &Z_LVAL_P(param);
868 						break;
869 					default:
870 						break;
871 				}
872 			}
873 		}
874 	}
875 #endif
876 
877 	if (mysql_stmt_execute(stmt->stmt)) {
878 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
879 		RETVAL_FALSE;
880 	} else {
881 		RETVAL_TRUE;
882 	}
883 
884 	if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
885 		php_mysqli_report_index(stmt->query, mysqli_stmt_server_status(stmt->stmt));
886 	}
887 }
888 /* }}} */
889 
890 #ifndef MYSQLI_USE_MYSQLND
891 /* {{{ void mysqli_stmt_fetch_libmysql
892    Fetch results from a prepared statement into the bound variables */
893 void mysqli_stmt_fetch_libmysql(INTERNAL_FUNCTION_PARAMETERS)
894 {
895 	MY_STMT		*stmt;
896 	zval			*mysql_stmt;
897 	unsigned int	i;
898 	zend_ulong			ret;
899 	my_ulonglong	llval;
900 
901 
902 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
903 		RETURN_THROWS();
904 	}
905 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
906 
907 	/* reset buffers */
908 	for (i = 0; i < stmt->result.var_cnt; i++) {
909 		if (stmt->result.buf[i].type == IS_STRING) {
910 			memset(stmt->result.buf[i].val, 0, stmt->result.buf[i].buflen);
911 		}
912 	}
913 	ret = mysql_stmt_fetch(stmt->stmt);
914 #ifdef MYSQL_DATA_TRUNCATED
915 	if (!ret || ret == MYSQL_DATA_TRUNCATED) {
916 #else
917 	if (!ret) {
918 #endif
919 		for (i = 0; i < stmt->result.var_cnt; i++) {
920 			zval *result;
921 			/* it must be a reference, isn't it? */
922 			if (Z_ISREF(stmt->result.vars[i])) {
923 				result = &stmt->result.vars[i];
924 			} else {
925 				continue; // but be safe ...
926 			}
927 			/* Even if the string is of length zero there is one byte alloced so efree() in all cases */
928 			if (!stmt->result.is_null[i]) {
929 				switch (stmt->result.buf[i].type) {
930 					case IS_LONG:
931 						if ((stmt->stmt->fields[i].type == MYSQL_TYPE_LONG)
932 						    && (stmt->stmt->fields[i].flags & UNSIGNED_FLAG))
933 						{
934 							/* unsigned int (11) */
935 #if SIZEOF_ZEND_LONG == 4
936 							unsigned int uval = *(unsigned int *) stmt->result.buf[i].val;
937 							if (uval > INT_MAX) {
938 								char *tmp, *p;
939 								int j = 10;
940 								tmp = emalloc(11);
941 								p= &tmp[9];
942 								do {
943 									*p-- = (uval % 10) + 48;
944 									uval = uval / 10;
945 								} while (--j > 0);
946 								tmp[10]= '\0';
947 								/* unsigned int > INT_MAX is 10 digits - ALWAYS */
948 								ZEND_TRY_ASSIGN_REF_STRINGL(result, tmp, 10);
949 								efree(tmp);
950 								break;
951 							}
952 #endif
953 						}
954 						if (stmt->stmt->fields[i].flags & UNSIGNED_FLAG) {
955 							ZEND_TRY_ASSIGN_REF_LONG(result, *(unsigned int *)stmt->result.buf[i].val);
956 						} else {
957 							ZEND_TRY_ASSIGN_REF_LONG(result, *(int *)stmt->result.buf[i].val);
958 						}
959 						break;
960 					case IS_DOUBLE:
961 					{
962 						double dval;
963 						if (stmt->stmt->bind[i].buffer_type == MYSQL_TYPE_FLOAT) {
964 #ifndef NOT_FIXED_DEC
965 # define NOT_FIXED_DEC 31
966 #endif
967 							dval = mysql_float_to_double(*(float *)stmt->result.buf[i].val,
968 										(stmt->stmt->fields[i].decimals >= NOT_FIXED_DEC) ? -1 :
969 										stmt->stmt->fields[i].decimals);
970 						} else {
971 							dval = *((double *)stmt->result.buf[i].val);
972 						}
973 
974 						ZEND_TRY_ASSIGN_REF_DOUBLE(result, dval);
975 						break;
976 					}
977 					case IS_STRING:
978 						if (stmt->stmt->bind[i].buffer_type == MYSQL_TYPE_LONGLONG
979 						 || stmt->stmt->bind[i].buffer_type == MYSQL_TYPE_BIT
980 						 ) {
981 							my_bool uns = (stmt->stmt->fields[i].flags & UNSIGNED_FLAG)? 1:0;
982 							if (stmt->stmt->bind[i].buffer_type == MYSQL_TYPE_BIT) {
983 								switch (stmt->result.buf[i].output_len) {
984 									case 8:llval = (my_ulonglong)  bit_uint8korr(stmt->result.buf[i].val);break;
985 									case 7:llval = (my_ulonglong)  bit_uint7korr(stmt->result.buf[i].val);break;
986 									case 6:llval = (my_ulonglong)  bit_uint6korr(stmt->result.buf[i].val);break;
987 									case 5:llval = (my_ulonglong)  bit_uint5korr(stmt->result.buf[i].val);break;
988 									case 4:llval = (my_ulonglong)  bit_uint4korr(stmt->result.buf[i].val);break;
989 									case 3:llval = (my_ulonglong)  bit_uint3korr(stmt->result.buf[i].val);break;
990 									case 2:llval = (my_ulonglong)  bit_uint2korr(stmt->result.buf[i].val);break;
991 									case 1:llval = (my_ulonglong)  uint1korr(stmt->result.buf[i].val);break;
992 								}
993 							} else {
994 								llval= *(my_ulonglong *) stmt->result.buf[i].val;
995 							}
996 #if SIZEOF_ZEND_LONG==8
997 							if (uns && llval > 9223372036854775807L) {
998 #elif SIZEOF_ZEND_LONG==4
999 							if ((uns && llval > L64(2147483647)) ||
1000 								(!uns && (( L64(2147483647) < (my_longlong) llval) ||
1001 								(L64(-2147483648) > (my_longlong) llval))))
1002 							{
1003 #endif
1004 								char tmp[22];
1005 								/* even though lval is declared as unsigned, the value
1006 								 * may be negative. Therefor we cannot use MYSQLI_LLU_SPEC and must
1007 								 * use MYSQLI_LL_SPEC.
1008 								 */
1009 								snprintf(tmp, sizeof(tmp), (stmt->stmt->fields[i].flags & UNSIGNED_FLAG)? MYSQLI_LLU_SPEC : MYSQLI_LL_SPEC, llval);
1010 								ZEND_TRY_ASSIGN_REF_STRING(result, tmp);
1011 							} else {
1012 								ZEND_TRY_ASSIGN_REF_LONG(result, llval);
1013 							}
1014 						} else {
1015 							if (ret == MYSQL_DATA_TRUNCATED && *(stmt->stmt->bind[i].error) != 0) {
1016 								/* result was truncated */
1017 								ZEND_TRY_ASSIGN_REF_STRINGL(result, stmt->result.buf[i].val, stmt->stmt->bind[i].buffer_length);
1018 							} else {
1019 								ZEND_TRY_ASSIGN_REF_STRINGL(result, stmt->result.buf[i].val, stmt->result.buf[i].output_len);
1020 							}
1021 						}
1022 						break;
1023 					default:
1024 						break;
1025 				}
1026 			} else {
1027 				ZEND_TRY_ASSIGN_REF_NULL(result);
1028 			}
1029 		}
1030 	} else {
1031 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
1032 	}
1033 
1034 	switch (ret) {
1035 		case 0:
1036 #ifdef MYSQL_DATA_TRUNCATED
1037 		/* according to SQL standard truncation (e.g. loss of precision is
1038 		   not an error) - for detecting possible truncation you have to
1039 		   check mysqli_stmt_warning
1040 		*/
1041 		case MYSQL_DATA_TRUNCATED:
1042 #endif
1043 			RETURN_TRUE;
1044 		break;
1045 		case 1:
1046 			RETURN_FALSE;
1047 		break;
1048 		default:
1049 			RETURN_NULL();
1050 		break;
1051 	}
1052 }
1053 /* }}} */
1054 #else
1055 /* {{{ mixed mysqli_stmt_fetch_mysqlnd */
1056 void mysqli_stmt_fetch_mysqlnd(INTERNAL_FUNCTION_PARAMETERS)
1057 {
1058 	MY_STMT		*stmt;
1059 	zval		*mysql_stmt;
1060 	zend_bool	fetched_anything;
1061 
1062 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
1063 		RETURN_THROWS();
1064 	}
1065 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1066 
1067 	if (FAIL == mysqlnd_stmt_fetch(stmt->stmt, &fetched_anything)) {
1068 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
1069 		RETURN_BOOL(FALSE);
1070 	} else if (fetched_anything == TRUE) {
1071 		RETURN_BOOL(TRUE);
1072 	} else {
1073 		RETURN_NULL();
1074 	}
1075 }
1076 #endif
1077 /* }}} */
1078 
1079 /* {{{ Fetch results from a prepared statement into the bound variables */
1080 PHP_FUNCTION(mysqli_stmt_fetch)
1081 {
1082 #ifndef MYSQLI_USE_MYSQLND
1083 	mysqli_stmt_fetch_libmysql(INTERNAL_FUNCTION_PARAM_PASSTHRU);
1084 #else
1085 	mysqli_stmt_fetch_mysqlnd(INTERNAL_FUNCTION_PARAM_PASSTHRU);
1086 #endif
1087 }
1088 /* }}} */
1089 
1090 /* {{{  php_add_field_properties */
1091 static void php_add_field_properties(zval *value, const MYSQL_FIELD *field)
1092 {
1093 #ifdef MYSQLI_USE_MYSQLND
1094 	add_property_str(value, "name", zend_string_copy(field->sname));
1095 #else
1096 	add_property_stringl(value, "name",(field->name ? field->name : ""), field->name_length);
1097 #endif
1098 
1099 	add_property_stringl(value, "orgname", (field->org_name ? field->org_name : ""), field->org_name_length);
1100 	add_property_stringl(value, "table", (field->table ? field->table : ""), field->table_length);
1101 	add_property_stringl(value, "orgtable", (field->org_table ? field->org_table : ""), field->org_table_length);
1102 	add_property_stringl(value, "def", (field->def ? field->def : ""), field->def_length);
1103 	add_property_stringl(value, "db", (field->db ? field->db : ""), field->db_length);
1104 
1105 	/* FIXME: manually set the catalog to "def" due to bug in
1106 	 * libmysqlclient which does not initialize field->catalog
1107 	 * and in addition, the catalog is always be "def"
1108 	 */
1109 	add_property_string(value, "catalog", "def");
1110 
1111 	add_property_long(value, "max_length", field->max_length);
1112 	add_property_long(value, "length", field->length);
1113 	add_property_long(value, "charsetnr", field->charsetnr);
1114 	add_property_long(value, "flags", field->flags);
1115 	add_property_long(value, "type", field->type);
1116 	add_property_long(value, "decimals", field->decimals);
1117 }
1118 /* }}} */
1119 
1120 /* {{{ Get column information from a result and return as an object */
1121 PHP_FUNCTION(mysqli_fetch_field)
1122 {
1123 	MYSQL_RES	*result;
1124 	zval		*mysql_result;
1125 	const MYSQL_FIELD	*field;
1126 
1127 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) {
1128 		RETURN_THROWS();
1129 	}
1130 
1131 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
1132 
1133 	if (!(field = mysql_fetch_field(result))) {
1134 		RETURN_FALSE;
1135 	}
1136 
1137 	object_init(return_value);
1138 	php_add_field_properties(return_value, field);
1139 }
1140 /* }}} */
1141 
1142 /* {{{ Return array of objects containing field meta-data */
1143 PHP_FUNCTION(mysqli_fetch_fields)
1144 {
1145 	MYSQL_RES	*result;
1146 	zval		*mysql_result;
1147 	zval		obj;
1148 
1149 	unsigned int i, num_fields;
1150 
1151 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) {
1152 		RETURN_THROWS();
1153 	}
1154 
1155 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
1156 
1157 	array_init(return_value);
1158 	num_fields = mysql_num_fields(result);
1159 
1160 	for (i = 0; i < num_fields; i++) {
1161 		const MYSQL_FIELD *field = mysql_fetch_field_direct(result, i);
1162 
1163 		object_init(&obj);
1164 
1165 		php_add_field_properties(&obj, field);
1166 		add_index_zval(return_value, i, &obj);
1167 	}
1168 }
1169 /* }}} */
1170 
1171 /* {{{ Fetch meta-data for a single field */
1172 PHP_FUNCTION(mysqli_fetch_field_direct)
1173 {
1174 	MYSQL_RES	*result;
1175 	zval		*mysql_result;
1176 	const MYSQL_FIELD	*field;
1177 	zend_long		offset;
1178 
1179 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_result, mysqli_result_class_entry, &offset) == FAILURE) {
1180 		RETURN_THROWS();
1181 	}
1182 
1183 	if (offset < 0) {
1184 		zend_argument_value_error(ERROR_ARG_POS(2), "must be greater than or equal to 0");
1185 		RETURN_THROWS();
1186 	}
1187 
1188 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
1189 
1190 	if (offset >= (zend_long) mysql_num_fields(result)) {
1191 		zend_argument_value_error(ERROR_ARG_POS(2), "must be less than the number of fields for this result set");
1192 		RETURN_THROWS();
1193 	}
1194 
1195 	if (!(field = mysql_fetch_field_direct(result,offset))) {
1196 		RETURN_FALSE;
1197 	}
1198 
1199 	object_init(return_value);
1200 	php_add_field_properties(return_value, field);
1201 }
1202 /* }}} */
1203 
1204 /* {{{ Get the length of each output in a result */
1205 PHP_FUNCTION(mysqli_fetch_lengths)
1206 {
1207 	MYSQL_RES		*result;
1208 	zval			*mysql_result;
1209 	unsigned int	i, num_fields;
1210 #ifdef MYSQLI_USE_MYSQLND
1211 	const size_t	*ret;
1212 #else
1213 	const zend_ulong *ret;
1214 #endif
1215 
1216 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) {
1217 		RETURN_THROWS();
1218 	}
1219 
1220 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
1221 
1222 	// TODO Warning?
1223 	if (!(ret = mysql_fetch_lengths(result))) {
1224 		RETURN_FALSE;
1225 	}
1226 
1227 	array_init(return_value);
1228 	num_fields = mysql_num_fields(result);
1229 
1230 	for (i = 0; i < num_fields; i++) {
1231 		add_index_long(return_value, i, ret[i]);
1232 	}
1233 }
1234 /* }}} */
1235 
1236 /* {{{ Get a result row as an enumerated array */
1237 PHP_FUNCTION(mysqli_fetch_row)
1238 {
1239 	php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQLI_NUM, 0);
1240 }
1241 /* }}} */
1242 
1243 /* {{{ Fetch the number of fields returned by the last query for the given link */
1244 PHP_FUNCTION(mysqli_field_count)
1245 {
1246 	MY_MYSQL	*mysql;
1247 	zval		*mysql_link;
1248 
1249 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1250 		RETURN_THROWS();
1251 	}
1252 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1253 
1254 	RETURN_LONG(mysql_field_count(mysql->mysql));
1255 }
1256 /* }}} */
1257 
1258 /* {{{ Set result pointer to a specified field offset */
1259 PHP_FUNCTION(mysqli_field_seek)
1260 {
1261 	MYSQL_RES		*result;
1262 	zval			*mysql_result;
1263 	zend_long	fieldnr;
1264 
1265 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_result, mysqli_result_class_entry, &fieldnr) == FAILURE) {
1266 		RETURN_THROWS();
1267 	}
1268 
1269 	if (fieldnr < 0) {
1270 		zend_argument_value_error(ERROR_ARG_POS(2), "must be greater than or equal to 0");
1271 		RETURN_THROWS();
1272 	}
1273 
1274 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
1275 
1276 	if ((uint32_t)fieldnr >= mysql_num_fields(result)) {
1277 		zend_argument_value_error(ERROR_ARG_POS(2), "must be less than the number of fields for this result set");
1278 		RETURN_THROWS();
1279 	}
1280 
1281 	mysql_field_seek(result, fieldnr);
1282 	RETURN_TRUE;
1283 }
1284 /* }}} */
1285 
1286 /* {{{ Get current field offset of result pointer */
1287 PHP_FUNCTION(mysqli_field_tell)
1288 {
1289 	MYSQL_RES	*result;
1290 	zval		*mysql_result;
1291 
1292 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) {
1293 		RETURN_THROWS();
1294 	}
1295 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
1296 
1297 	RETURN_LONG(mysql_field_tell(result));
1298 }
1299 /* }}} */
1300 
1301 /* {{{ Free query result memory for the given result handle */
1302 PHP_FUNCTION(mysqli_free_result)
1303 {
1304 	MYSQL_RES	*result;
1305 	zval		*mysql_result;
1306 
1307 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) {
1308 		RETURN_THROWS();
1309 	}
1310 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
1311 
1312 	mysqli_free_result(result, FALSE);
1313 	MYSQLI_CLEAR_RESOURCE(mysql_result);
1314 }
1315 /* }}} */
1316 
1317 /* {{{ Get MySQL client info */
1318 PHP_FUNCTION(mysqli_get_client_info)
1319 {
1320 	if (getThis()) {
1321 		if (zend_parse_parameters_none() == FAILURE) {
1322 			RETURN_THROWS();
1323 		}
1324 	} else {
1325 		zval *mysql_link;
1326 
1327 		if (zend_parse_parameters(ZEND_NUM_ARGS(), "|O!", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1328 			RETURN_THROWS();
1329 		}
1330 	}
1331 
1332 	RETURN_STRING(mysql_get_client_info());
1333 }
1334 /* }}} */
1335 
1336 /* {{{ Get MySQL client info */
1337 PHP_FUNCTION(mysqli_get_client_version)
1338 {
1339 	if (zend_parse_parameters_none() == FAILURE) {
1340 		RETURN_THROWS();
1341 	}
1342 
1343 	RETURN_LONG((zend_long)mysql_get_client_version());
1344 }
1345 /* }}} */
1346 
1347 /* {{{ Get MySQL host info */
1348 PHP_FUNCTION(mysqli_get_host_info)
1349 {
1350 	MY_MYSQL	*mysql;
1351 	zval		*mysql_link = NULL;
1352 
1353 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1354 		RETURN_THROWS();
1355 	}
1356 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1357 #ifndef MYSQLI_USE_MYSQLND
1358 	RETURN_STRING((mysql->mysql->host_info) ? mysql->mysql->host_info : "");
1359 #else
1360 	RETURN_STRING((mysql->mysql->data->host_info) ? mysql->mysql->data->host_info : "");
1361 #endif
1362 }
1363 /* }}} */
1364 
1365 /* {{{ Get MySQL protocol information */
1366 PHP_FUNCTION(mysqli_get_proto_info)
1367 {
1368 	MY_MYSQL	*mysql;
1369 	zval		*mysql_link = NULL;
1370 
1371 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1372 		RETURN_THROWS();
1373 	}
1374 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1375 	RETURN_LONG(mysql_get_proto_info(mysql->mysql));
1376 }
1377 /* }}} */
1378 
1379 /* {{{ Get MySQL server info */
1380 PHP_FUNCTION(mysqli_get_server_info)
1381 {
1382 	MY_MYSQL	*mysql;
1383 	zval		*mysql_link = NULL;
1384 
1385 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1386 		RETURN_THROWS();
1387 	}
1388 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1389 
1390 	RETURN_STRING(mysql_get_server_info(mysql->mysql));
1391 }
1392 /* }}} */
1393 
1394 /* {{{ Return the MySQL version for the server referenced by the given link */
1395 PHP_FUNCTION(mysqli_get_server_version)
1396 {
1397 	MY_MYSQL	*mysql;
1398 	zval		*mysql_link = NULL;
1399 
1400 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1401 		RETURN_THROWS();
1402 	}
1403 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1404 
1405 	RETURN_LONG(mysql_get_server_version(mysql->mysql));
1406 }
1407 /* }}} */
1408 
1409 /* {{{ Get information about the most recent query */
1410 PHP_FUNCTION(mysqli_info)
1411 {
1412 	MY_MYSQL	*mysql;
1413 	zval		*mysql_link = NULL;
1414 	const char	*info;
1415 
1416 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1417 		RETURN_THROWS();
1418 	}
1419 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1420 
1421 	info = mysql_info(mysql->mysql);
1422 	if (info) {
1423 		RETURN_STRING(info);
1424 	}
1425 }
1426 /* }}} */
1427 
1428 /* {{{ php_mysqli_init() */
1429 void php_mysqli_init(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_method)
1430 {
1431 	MYSQLI_RESOURCE *mysqli_resource;
1432 	MY_MYSQL *mysql;
1433 
1434 	if (zend_parse_parameters_none() == FAILURE) {
1435 		RETURN_THROWS();
1436 	}
1437 
1438 	if (is_method && (Z_MYSQLI_P(getThis()))->ptr) {
1439 		return;
1440 	}
1441 
1442 	mysql = (MY_MYSQL *)ecalloc(1, sizeof(MY_MYSQL));
1443 
1444 #ifndef MYSQLI_USE_MYSQLND
1445 	if (!(mysql->mysql = mysql_init(NULL)))
1446 #else
1447 	/*
1448 	  We create always persistent, as if the user want to connect
1449 	  to p:somehost, we can't convert the handle then
1450 	*/
1451 	if (!(mysql->mysql = mysqlnd_init(MYSQLND_CLIENT_KNOWS_RSET_COPY_DATA, TRUE)))
1452 #endif
1453 	{
1454 		efree(mysql);
1455 		RETURN_FALSE;
1456 	}
1457 
1458 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
1459 	mysqli_resource->ptr = (void *)mysql;
1460 	mysqli_resource->status = MYSQLI_STATUS_INITIALIZED;
1461 
1462 	if (!is_method) {
1463 		MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_link_class_entry);
1464 	} else {
1465 		(Z_MYSQLI_P(getThis()))->ptr = mysqli_resource;
1466 	}
1467 }
1468 /* }}} */
1469 
1470 /* {{{ Initialize mysqli and return a resource for use with mysql_real_connect */
1471 PHP_FUNCTION(mysqli_init)
1472 {
1473 	php_mysqli_init(INTERNAL_FUNCTION_PARAM_PASSTHRU, FALSE);
1474 }
1475 /* }}} */
1476 
1477 /* {{{ Get the ID generated from the previous INSERT operation */
1478 PHP_FUNCTION(mysqli_insert_id)
1479 {
1480 	MY_MYSQL		*mysql;
1481 	my_ulonglong	rc;
1482 	zval			*mysql_link;
1483 
1484 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1485 		RETURN_THROWS();
1486 	}
1487 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1488 	rc = mysql_insert_id(mysql->mysql);
1489 	MYSQLI_RETURN_LONG_INT(rc)
1490 }
1491 /* }}} */
1492 
1493 /* {{{ Kill a mysql process on the server */
1494 PHP_FUNCTION(mysqli_kill)
1495 {
1496 	MY_MYSQL	*mysql;
1497 	zval		*mysql_link;
1498 	zend_long		processid;
1499 
1500 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_link, mysqli_link_class_entry, &processid) == FAILURE) {
1501 		RETURN_THROWS();
1502 	}
1503 
1504 	if (processid <= 0) {
1505 		zend_argument_value_error(ERROR_ARG_POS(2), "must be greater than 0");
1506 		RETURN_THROWS();
1507 	}
1508 
1509 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1510 
1511 	if (mysql_kill(mysql->mysql, processid)) {
1512 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1513 		RETURN_FALSE;
1514 	}
1515 	RETURN_TRUE;
1516 }
1517 /* }}} */
1518 
1519 /* {{{ check if there any more query results from a multi query */
1520 PHP_FUNCTION(mysqli_more_results)
1521 {
1522 	MY_MYSQL	*mysql;
1523 	zval		*mysql_link;
1524 
1525 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1526 		RETURN_THROWS();
1527 	}
1528 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1529 
1530 	RETURN_BOOL(mysql_more_results(mysql->mysql));
1531 }
1532 /* }}} */
1533 
1534 /* {{{ read next result from multi_query */
1535 PHP_FUNCTION(mysqli_next_result) {
1536 	MY_MYSQL	*mysql;
1537 	zval		*mysql_link;
1538 
1539 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1540 		RETURN_THROWS();
1541 	}
1542 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1543 
1544 	if (mysql_next_result(mysql->mysql)) {
1545 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1546 		RETURN_FALSE;
1547 	}
1548 	RETURN_TRUE;
1549 }
1550 /* }}} */
1551 
1552 /* TODO: Make these available without mysqlnd */
1553 #if defined(MYSQLI_USE_MYSQLND)
1554 /* {{{ check if there any more query results from a multi query */
1555 PHP_FUNCTION(mysqli_stmt_more_results)
1556 {
1557 	MY_STMT		*stmt;
1558 	zval		*mysql_stmt;
1559 
1560 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
1561 		RETURN_THROWS();
1562 	}
1563 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1564 
1565 	RETURN_BOOL(mysqlnd_stmt_more_results(stmt->stmt));
1566 }
1567 /* }}} */
1568 
1569 /* {{{ read next result from multi_query */
1570 PHP_FUNCTION(mysqli_stmt_next_result) {
1571 	MY_STMT		*stmt;
1572 	zval		*mysql_stmt;
1573 
1574 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
1575 		RETURN_THROWS();
1576 	}
1577 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1578 
1579 	if (mysql_stmt_next_result(stmt->stmt)) {
1580 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
1581 		RETURN_FALSE;
1582 	}
1583 	RETURN_TRUE;
1584 }
1585 /* }}} */
1586 #endif
1587 
1588 /* {{{ Get number of fields in result */
1589 PHP_FUNCTION(mysqli_num_fields)
1590 {
1591 	MYSQL_RES	*result;
1592 	zval		*mysql_result;
1593 
1594 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) {
1595 		RETURN_THROWS();
1596 	}
1597 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
1598 
1599 	RETURN_LONG(mysql_num_fields(result));
1600 }
1601 /* }}} */
1602 
1603 /* {{{ Get number of rows in result */
1604 PHP_FUNCTION(mysqli_num_rows)
1605 {
1606 	MYSQL_RES	*result;
1607 	zval		*mysql_result;
1608 
1609 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) {
1610 		RETURN_THROWS();
1611 	}
1612 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
1613 
1614 	if (mysqli_result_is_unbuffered_and_not_everything_is_fetched(result)) {
1615 		zend_throw_error(NULL, "mysqli_num_rows() cannot be used in MYSQLI_USE_RESULT mode");
1616 		RETURN_THROWS();
1617 	}
1618 
1619 	MYSQLI_RETURN_LONG_INT(mysql_num_rows(result));
1620 }
1621 /* }}} */
1622 
1623 /* {{{ mysqli_options_get_option_zval_type */
1624 static int mysqli_options_get_option_zval_type(int option)
1625 {
1626 	switch (option) {
1627 #ifdef MYSQLI_USE_MYSQLND
1628 		case MYSQLND_OPT_NET_CMD_BUFFER_SIZE:
1629 		case MYSQLND_OPT_NET_READ_BUFFER_SIZE:
1630 #ifdef MYSQLND_STRING_TO_INT_CONVERSION
1631 		case MYSQLND_OPT_INT_AND_FLOAT_NATIVE:
1632 #endif
1633 #endif /* MYSQLI_USE_MYSQLND */
1634 		case MYSQL_OPT_CONNECT_TIMEOUT:
1635 #ifdef MYSQL_REPORT_DATA_TRUNCATION
1636 		case MYSQL_REPORT_DATA_TRUNCATION:
1637 #endif
1638 		case MYSQL_OPT_LOCAL_INFILE:
1639 		case MYSQL_OPT_NAMED_PIPE:
1640 #ifdef MYSQL_OPT_PROTOCOL
1641 		case MYSQL_OPT_PROTOCOL:
1642 #endif /* MySQL 4.1.0 */
1643 		case MYSQL_OPT_READ_TIMEOUT:
1644 		case MYSQL_OPT_WRITE_TIMEOUT:
1645 #ifdef MYSQL_OPT_GUESS_CONNECTION /* removed in MySQL-8.0 */
1646 		case MYSQL_OPT_GUESS_CONNECTION:
1647 		case MYSQL_OPT_USE_EMBEDDED_CONNECTION:
1648 		case MYSQL_OPT_USE_REMOTE_CONNECTION:
1649 		case MYSQL_SECURE_AUTH:
1650 #endif
1651 #ifdef MYSQL_OPT_RECONNECT
1652 		case MYSQL_OPT_RECONNECT:
1653 #endif /* MySQL 5.0.13 */
1654 #ifdef MYSQL_OPT_SSL_VERIFY_SERVER_CERT
1655 		case MYSQL_OPT_SSL_VERIFY_SERVER_CERT:
1656 #endif /* MySQL 5.0.23 */
1657 #ifdef MYSQL_OPT_COMPRESS
1658 		case MYSQL_OPT_COMPRESS:
1659 #endif /* mysqlnd @ PHP 5.3.2 */
1660 #if (MYSQL_VERSION_ID >= 50611 && defined(CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS)) || defined(MYSQLI_USE_MYSQLND)
1661 		case MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS:
1662 #endif
1663 			return IS_LONG;
1664 
1665 #ifdef MYSQL_SHARED_MEMORY_BASE_NAME
1666 		case MYSQL_SHARED_MEMORY_BASE_NAME:
1667 #endif /* MySQL 4.1.0 */
1668 #ifdef MYSQL_SET_CLIENT_IP
1669 		case MYSQL_SET_CLIENT_IP:
1670 #endif /* MySQL 4.1.1 */
1671 		case MYSQL_READ_DEFAULT_FILE:
1672 		case MYSQL_READ_DEFAULT_GROUP:
1673 		case MYSQL_INIT_COMMAND:
1674 		case MYSQL_SET_CHARSET_NAME:
1675 		case MYSQL_SET_CHARSET_DIR:
1676 #if MYSQL_VERSION_ID > 50605 || defined(MYSQLI_USE_MYSQLND)
1677 		case MYSQL_SERVER_PUBLIC_KEY:
1678 #endif
1679 			return IS_STRING;
1680 
1681 		default:
1682 			return IS_NULL;
1683 	}
1684 }
1685 /* }}} */
1686 
1687 /* {{{ Set options */
1688 PHP_FUNCTION(mysqli_options)
1689 {
1690 	MY_MYSQL		*mysql;
1691 	zval			*mysql_link = NULL;
1692 	zval			*mysql_value;
1693 	zend_long			mysql_option;
1694 	unsigned int	l_value;
1695 	zend_long			ret;
1696 	int				expected_type;
1697 
1698 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Olz", &mysql_link, mysqli_link_class_entry, &mysql_option, &mysql_value) == FAILURE) {
1699 		RETURN_THROWS();
1700 	}
1701 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_INITIALIZED);
1702 
1703 #ifndef MYSQLI_USE_MYSQLND
1704 	if (PG(open_basedir) && PG(open_basedir)[0] != '\0') {
1705 		if(mysql_option == MYSQL_OPT_LOCAL_INFILE) {
1706 			RETURN_FALSE;
1707 		}
1708 	}
1709 #endif
1710 	expected_type = mysqli_options_get_option_zval_type(mysql_option);
1711 	if (expected_type != Z_TYPE_P(mysql_value)) {
1712 		switch (expected_type) {
1713 			case IS_STRING:
1714 				if (!try_convert_to_string(mysql_value)) {
1715 					RETURN_THROWS();
1716 				}
1717 				break;
1718 			case IS_LONG:
1719 				convert_to_long_ex(mysql_value);
1720 				break;
1721 			default:
1722 				break;
1723 		}
1724 	}
1725 	switch (expected_type) {
1726 		case IS_STRING:
1727 			ret = mysql_options(mysql->mysql, mysql_option, Z_STRVAL_P(mysql_value));
1728 			break;
1729 		case IS_LONG:
1730 			l_value = Z_LVAL_P(mysql_value);
1731 			ret = mysql_options(mysql->mysql, mysql_option, (char *)&l_value);
1732 			break;
1733 		default:
1734 			ret = 1;
1735 			break;
1736 	}
1737 
1738 	RETURN_BOOL(!ret);
1739 }
1740 /* }}} */
1741 
1742 /* {{{ Ping a server connection or reconnect if there is no connection */
1743 PHP_FUNCTION(mysqli_ping)
1744 {
1745 	MY_MYSQL	*mysql;
1746 	zval		*mysql_link;
1747 	zend_long		rc;
1748 
1749 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1750 		RETURN_THROWS();
1751 	}
1752 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1753 	rc = mysql_ping(mysql->mysql);
1754 	MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1755 
1756 	RETURN_BOOL(!rc);
1757 }
1758 /* }}} */
1759 
1760 /* {{{ Prepare a SQL statement for execution */
1761 PHP_FUNCTION(mysqli_prepare)
1762 {
1763 	MY_MYSQL		*mysql;
1764 	MY_STMT			*stmt;
1765 	char			*query = NULL;
1766 	size_t				query_len;
1767 	zval			*mysql_link;
1768 	MYSQLI_RESOURCE	*mysqli_resource;
1769 
1770 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os",&mysql_link, mysqli_link_class_entry, &query, &query_len) == FAILURE) {
1771 		RETURN_THROWS();
1772 	}
1773 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1774 
1775 #ifndef MYSQLI_USE_MYSQLND
1776 	if (mysql->mysql->status == MYSQL_STATUS_GET_RESULT) {
1777 		php_error_docref(NULL, E_WARNING, "All data must be fetched before a new statement prepare takes place");
1778 		RETURN_FALSE;
1779 	}
1780 #endif
1781 
1782 	stmt = (MY_STMT *)ecalloc(1,sizeof(MY_STMT));
1783 
1784 	if ((stmt->stmt = mysql_stmt_init(mysql->mysql))) {
1785 		if (mysql_stmt_prepare(stmt->stmt, query, query_len)) {
1786 			/* mysql_stmt_close() clears errors, so we have to store them temporarily */
1787 #ifndef MYSQLI_USE_MYSQLND
1788 			char  last_error[MYSQL_ERRMSG_SIZE];
1789 			char  sqlstate[SQLSTATE_LENGTH+1];
1790 			unsigned int last_errno;
1791 
1792 			last_errno = stmt->stmt->last_errno;
1793 			memcpy(last_error, stmt->stmt->last_error, MYSQL_ERRMSG_SIZE);
1794 			memcpy(sqlstate, mysql->mysql->net.sqlstate, SQLSTATE_LENGTH+1);
1795 #else
1796 			MYSQLND_ERROR_INFO error_info = *mysql->mysql->data->error_info;
1797 			mysql->mysql->data->error_info->error_list.head = NULL;
1798 			mysql->mysql->data->error_info->error_list.tail = NULL;
1799 			mysql->mysql->data->error_info->error_list.count = 0;
1800 #endif
1801 			mysqli_stmt_close(stmt->stmt, FALSE);
1802 			stmt->stmt = NULL;
1803 
1804 			/* restore error messages */
1805 #ifndef MYSQLI_USE_MYSQLND
1806 			mysql->mysql->net.last_errno = last_errno;
1807 			memcpy(mysql->mysql->net.last_error, last_error, MYSQL_ERRMSG_SIZE);
1808 			memcpy(mysql->mysql->net.sqlstate, sqlstate, SQLSTATE_LENGTH+1);
1809 #else
1810 			zend_llist_clean(&mysql->mysql->data->error_info->error_list);
1811 			*mysql->mysql->data->error_info = error_info;
1812 #endif
1813 		}
1814 	}
1815 
1816 	/* don't initialize stmt->query with NULL, we ecalloc()-ed the memory */
1817 	/* Get performance boost if reporting is switched off */
1818 	if (stmt->stmt && query_len && (MyG(report_mode) & MYSQLI_REPORT_INDEX)) {
1819 		stmt->query = (char *)emalloc(query_len + 1);
1820 		memcpy(stmt->query, query, query_len);
1821 		stmt->query[query_len] = '\0';
1822 	}
1823 
1824 	/* don't join to the previous if because it won't work if mysql_stmt_prepare_fails */
1825 	if (!stmt->stmt) {
1826 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1827 		efree(stmt);
1828 		RETURN_FALSE;
1829 	}
1830 #ifndef MYSQLI_USE_MYSQLND
1831 	ZVAL_COPY(&stmt->link_handle, mysql_link);
1832 #endif
1833 
1834 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
1835 	mysqli_resource->ptr = (void *)stmt;
1836 
1837 	/* change status */
1838 	mysqli_resource->status = MYSQLI_STATUS_VALID;
1839 	MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_stmt_class_entry);
1840 }
1841 /* }}} */
1842 
1843 /* {{{ Open a connection to a mysql server */
1844 PHP_FUNCTION(mysqli_real_connect)
1845 {
1846 	mysqli_common_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, TRUE, FALSE);
1847 }
1848 /* }}} */
1849 
1850 /* {{{ Binary-safe version of mysql_query() */
1851 PHP_FUNCTION(mysqli_real_query)
1852 {
1853 	MY_MYSQL	*mysql;
1854 	zval		*mysql_link;
1855 	char		*query = NULL;
1856 	size_t		query_len;
1857 
1858 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_link, mysqli_link_class_entry, &query, &query_len) == FAILURE) {
1859 		RETURN_THROWS();
1860 	}
1861 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1862 
1863 	MYSQLI_DISABLE_MQ; /* disable multi statements/queries */
1864 
1865 	if (mysql_real_query(mysql->mysql, query, query_len)) {
1866 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1867 		RETURN_FALSE;
1868 	}
1869 
1870 	if (!mysql_field_count(mysql->mysql)) {
1871 		if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
1872 			php_mysqli_report_index(query, mysqli_server_status(mysql->mysql));
1873 		}
1874 	}
1875 
1876 	RETURN_TRUE;
1877 }
1878 /* }}} */
1879 
1880 #if defined(MYSQLI_USE_MYSQLND) || MYSQL_VERSION_ID < 50707 || defined(MARIADB_BASE_VERSION)
1881 # define mysql_real_escape_string_quote(mysql, to, from, length, quote) \
1882 	mysql_real_escape_string(mysql, to, from, length)
1883 #endif
1884 
1885 PHP_FUNCTION(mysqli_real_escape_string) {
1886 	MY_MYSQL	*mysql;
1887 	zval		*mysql_link = NULL;
1888 	char		*escapestr;
1889 	size_t			escapestr_len;
1890 	zend_string *newstr;
1891 
1892 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_link, mysqli_link_class_entry, &escapestr, &escapestr_len) == FAILURE) {
1893 		RETURN_THROWS();
1894 	}
1895 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1896 
1897 	newstr = zend_string_safe_alloc(2, escapestr_len, 0, 0);
1898 	ZSTR_LEN(newstr) = mysql_real_escape_string_quote(mysql->mysql, ZSTR_VAL(newstr), escapestr, escapestr_len, '\'');
1899 	newstr = zend_string_truncate(newstr, ZSTR_LEN(newstr), 0);
1900 
1901 	RETURN_NEW_STR(newstr);
1902 }
1903 
1904 /* {{{ Undo actions from current transaction */
1905 PHP_FUNCTION(mysqli_rollback)
1906 {
1907 	MY_MYSQL	*mysql;
1908 	zval		*mysql_link;
1909 	zend_long		flags = TRANS_COR_NO_OPT;
1910 	char *		name = NULL;
1911 	size_t			name_len = 0;
1912 
1913 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|ls!", &mysql_link, mysqli_link_class_entry, &flags, &name, &name_len) == FAILURE) {
1914 		RETURN_THROWS();
1915 	}
1916 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1917 
1918 #ifndef MYSQLI_USE_MYSQLND
1919 	if (mysqli_commit_or_rollback_libmysql(mysql->mysql, FALSE, flags, name)) {
1920 #else
1921 	if (FAIL == mysqlnd_rollback(mysql->mysql, flags, name)) {
1922 #endif
1923 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1924 		RETURN_FALSE;
1925 	}
1926 	RETURN_TRUE;
1927 }
1928 /* }}} */
1929 
1930 /* {{{ */
1931 PHP_FUNCTION(mysqli_stmt_send_long_data)
1932 {
1933 	MY_STMT *stmt;
1934 	zval	*mysql_stmt;
1935 	char	*data;
1936 	zend_long	param_nr;
1937 	size_t		data_len;
1938 
1939 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ols", &mysql_stmt, mysqli_stmt_class_entry, &param_nr, &data, &data_len) == FAILURE) {
1940 		RETURN_THROWS();
1941 	}
1942 
1943 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1944 
1945 	if (param_nr < 0) {
1946 		zend_argument_value_error(ERROR_ARG_POS(2), "must be greater than or equal to 0");
1947 		RETURN_THROWS();
1948 	}
1949 
1950 	if (mysql_stmt_send_long_data(stmt->stmt, param_nr, data, data_len)) {
1951 		RETURN_FALSE;
1952 	}
1953 	RETURN_TRUE;
1954 }
1955 /* }}} */
1956 
1957 /* {{{ Return the number of rows affected in the last query for the given link. */
1958 PHP_FUNCTION(mysqli_stmt_affected_rows)
1959 {
1960 	MY_STMT			*stmt;
1961 	zval			*mysql_stmt;
1962 	my_ulonglong	rc;
1963 
1964 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
1965 		RETURN_THROWS();
1966 	}
1967 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1968 
1969 	rc = mysql_stmt_affected_rows(stmt->stmt);
1970 	if (rc == (my_ulonglong) -1) {
1971 		RETURN_LONG(-1);
1972 	}
1973 	MYSQLI_RETURN_LONG_INT(rc)
1974 }
1975 /* }}} */
1976 
1977 /* {{{ Close statement */
1978 PHP_FUNCTION(mysqli_stmt_close)
1979 {
1980 	MY_STMT		*stmt;
1981 	zval		*mysql_stmt;
1982 
1983 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
1984 		RETURN_THROWS();
1985 	}
1986 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1987 
1988 	mysqli_stmt_close(stmt->stmt, FALSE);
1989 	stmt->stmt = NULL;
1990 	php_clear_stmt_bind(stmt);
1991 	MYSQLI_CLEAR_RESOURCE(mysql_stmt);
1992 	RETURN_TRUE;
1993 }
1994 /* }}} */
1995 
1996 /* {{{ Move internal result pointer */
1997 PHP_FUNCTION(mysqli_stmt_data_seek)
1998 {
1999 	MY_STMT		*stmt;
2000 	zval		*mysql_stmt;
2001 	zend_long		offset;
2002 
2003 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_stmt, mysqli_stmt_class_entry, &offset) == FAILURE) {
2004 		RETURN_THROWS();
2005 	}
2006 
2007 	if (offset < 0) {
2008 		zend_argument_value_error(ERROR_ARG_POS(2), "must be greater than or equal to 0");
2009 		RETURN_THROWS();
2010 	}
2011 
2012 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2013 
2014 	mysql_stmt_data_seek(stmt->stmt, offset);
2015 }
2016 /* }}} */
2017 
2018 /* {{{ Return the number of result columns for the given statement */
2019 PHP_FUNCTION(mysqli_stmt_field_count)
2020 {
2021 	MY_STMT		*stmt;
2022 	zval		*mysql_stmt;
2023 
2024 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2025 		RETURN_THROWS();
2026 	}
2027 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2028 
2029 	RETURN_LONG(mysql_stmt_field_count(stmt->stmt));
2030 }
2031 /* }}} */
2032 
2033 /* {{{ Free stored result memory for the given statement handle */
2034 PHP_FUNCTION(mysqli_stmt_free_result)
2035 {
2036 	MY_STMT		*stmt;
2037 	zval		*mysql_stmt;
2038 
2039 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2040 		RETURN_THROWS();
2041 	}
2042 
2043 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2044 
2045 	mysql_stmt_free_result(stmt->stmt);
2046 }
2047 /* }}} */
2048 
2049 /* {{{ Get the ID generated from the previous INSERT operation */
2050 PHP_FUNCTION(mysqli_stmt_insert_id)
2051 {
2052 	MY_STMT			*stmt;
2053 	my_ulonglong	rc;
2054 	zval			*mysql_stmt;
2055 
2056 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2057 		RETURN_THROWS();
2058 	}
2059 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2060 	rc = mysql_stmt_insert_id(stmt->stmt);
2061 	MYSQLI_RETURN_LONG_INT(rc)
2062 }
2063 /* }}} */
2064 
2065 /* {{{ Return the number of parameter for the given statement */
2066 PHP_FUNCTION(mysqli_stmt_param_count)
2067 {
2068 	MY_STMT		*stmt;
2069 	zval		*mysql_stmt;
2070 
2071 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2072 		RETURN_THROWS();
2073 	}
2074 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2075 
2076 	RETURN_LONG(mysql_stmt_param_count(stmt->stmt));
2077 }
2078 /* }}} */
2079 
2080 /* {{{ reset a prepared statement */
2081 PHP_FUNCTION(mysqli_stmt_reset)
2082 {
2083 	MY_STMT		*stmt;
2084 	zval		*mysql_stmt;
2085 
2086 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2087 		RETURN_THROWS();
2088 	}
2089 
2090 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2091 
2092 	if (mysql_stmt_reset(stmt->stmt)) {
2093 		RETURN_FALSE;
2094 	}
2095 	RETURN_TRUE;
2096 }
2097 /* }}} */
2098 
2099 /* {{{ Return the number of rows in statements result set */
2100 PHP_FUNCTION(mysqli_stmt_num_rows)
2101 {
2102 	MY_STMT			*stmt;
2103 	zval			*mysql_stmt;
2104 	my_ulonglong	rc;
2105 
2106 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2107 		RETURN_THROWS();
2108 	}
2109 
2110 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2111 
2112 	rc = mysql_stmt_num_rows(stmt->stmt);
2113 	MYSQLI_RETURN_LONG_INT(rc)
2114 }
2115 /* }}} */
2116 
2117 /* {{{ Select a MySQL database */
2118 PHP_FUNCTION(mysqli_select_db)
2119 {
2120 	MY_MYSQL	*mysql;
2121 	zval		*mysql_link;
2122 	char		*dbname;
2123 	size_t			dbname_len;
2124 
2125 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_link, mysqli_link_class_entry, &dbname, &dbname_len) == FAILURE) {
2126 		RETURN_THROWS();
2127 	}
2128 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
2129 
2130 	if (mysql_select_db(mysql->mysql, dbname)) {
2131 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
2132 		RETURN_FALSE;
2133 	}
2134 	RETURN_TRUE;
2135 }
2136 /* }}} */
2137 
2138 /* {{{ Returns the SQLSTATE error from previous MySQL operation */
2139 PHP_FUNCTION(mysqli_sqlstate)
2140 {
2141 	MY_MYSQL	*mysql;
2142 	zval		*mysql_link;
2143 
2144 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
2145 		RETURN_THROWS();
2146 	}
2147 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
2148 	RETURN_STRING(mysql_sqlstate(mysql->mysql));
2149 }
2150 /* }}} */
2151 
2152 /* {{{ */
2153 PHP_FUNCTION(mysqli_ssl_set)
2154 {
2155 	MY_MYSQL	*mysql;
2156 	zval		*mysql_link;
2157 	char		*ssl_parm[5];
2158 	size_t			ssl_parm_len[5], i;
2159 
2160 	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) {
2161 		RETURN_THROWS();
2162 	}
2163 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_INITIALIZED);
2164 
2165 	for (i = 0; i < 5; i++) {
2166 		if (!ssl_parm_len[i]) {
2167 			ssl_parm[i] = NULL;
2168 		}
2169 	}
2170 
2171 	mysql_ssl_set(mysql->mysql, ssl_parm[0], ssl_parm[1], ssl_parm[2], ssl_parm[3], ssl_parm[4]);
2172 
2173 	RETURN_TRUE;
2174 }
2175 /* }}} */
2176 
2177 /* {{{ Get current system status */
2178 PHP_FUNCTION(mysqli_stat)
2179 {
2180 	MY_MYSQL	*mysql;
2181 	zval		*mysql_link;
2182 #ifdef MYSQLI_USE_MYSQLND
2183 	zend_string *stat;
2184 #else
2185 	char		*stat;
2186 #endif
2187 
2188 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
2189 		RETURN_THROWS();
2190 	}
2191 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
2192 
2193 #ifndef MYSQLI_USE_MYSQLND
2194 	if ((stat = (char *)mysql_stat(mysql->mysql)))
2195 	{
2196 		RETURN_STRING(stat);
2197 #else
2198 	if (mysqlnd_stat(mysql->mysql, &stat) == PASS)
2199 	{
2200 		RETURN_STR(stat);
2201 #endif
2202 	} else {
2203 		RETURN_FALSE;
2204 	}
2205 }
2206 
2207 /* }}} */
2208 
2209 /* {{{ Flush tables or caches, or reset replication server information */
2210 PHP_FUNCTION(mysqli_refresh)
2211 {
2212 	MY_MYSQL *mysql;
2213 	zval *mysql_link = NULL;
2214 	zend_long options;
2215 
2216 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_link, mysqli_link_class_entry, &options) == FAILURE) {
2217 		RETURN_THROWS();
2218 	}
2219 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_INITIALIZED);
2220 #ifdef MYSQLI_USE_MYSQLND
2221 	RETURN_BOOL(!mysql_refresh(mysql->mysql, (uint8_t) options));
2222 #else
2223 	RETURN_BOOL(!mysql_refresh(mysql->mysql, options));
2224 #endif
2225 }
2226 /* }}} */
2227 
2228 /* {{{ */
2229 PHP_FUNCTION(mysqli_stmt_attr_set)
2230 {
2231 	MY_STMT	*stmt;
2232 	zval	*mysql_stmt;
2233 	zend_long	mode_in;
2234 	my_bool mode_b;
2235 	unsigned long	mode;
2236 	zend_long	attr;
2237 	void	*mode_p;
2238 
2239 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oll", &mysql_stmt, mysqli_stmt_class_entry, &attr, &mode_in) == FAILURE) {
2240 		RETURN_THROWS();
2241 	}
2242 
2243 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2244 
2245 	switch (attr) {
2246 	case STMT_ATTR_UPDATE_MAX_LENGTH:
2247 		if (mode_in != 0 && mode_in != 1) {
2248 			zend_argument_value_error(ERROR_ARG_POS(3), "must be 0 or 1 for attribute MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH");
2249 			RETURN_THROWS();
2250 		}
2251 		mode_b = (my_bool) mode_in;
2252 		mode_p = &mode_b;
2253 		break;
2254 	case STMT_ATTR_CURSOR_TYPE:
2255 		switch (mode_in) {
2256 			case CURSOR_TYPE_NO_CURSOR:
2257 			case CURSOR_TYPE_READ_ONLY:
2258 			case CURSOR_TYPE_FOR_UPDATE:
2259 			case CURSOR_TYPE_SCROLLABLE:
2260 				break;
2261 			default:
2262 				zend_argument_value_error(ERROR_ARG_POS(3), "must be one of the MYSQLI_CURSOR_TYPE_* constants "
2263 					"for attribute MYSQLI_STMT_ATTR_CURSOR_TYPE");
2264 				RETURN_THROWS();
2265 		}
2266 		mode = mode_in;
2267 		mode_p = &mode;
2268 		break;
2269 	case STMT_ATTR_PREFETCH_ROWS:
2270 		if (mode_in < 1) {
2271 			zend_argument_value_error(ERROR_ARG_POS(3), "must be greater than 0 for attribute MYSQLI_STMT_ATTR_PREFETCH_ROWS");
2272 			RETURN_THROWS();
2273 		}
2274 		mode = mode_in;
2275 		mode_p = &mode;
2276 		break;
2277 	default:
2278 		zend_argument_value_error(ERROR_ARG_POS(2), "must be one of "
2279 			"MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH, "
2280 			"MYSQLI_STMT_ATTR_PREFETCH_ROWS, or STMT_ATTR_CURSOR_TYPE");
2281 		RETURN_THROWS();
2282 	}
2283 
2284 // TODO Can unify this?
2285 #ifndef MYSQLI_USE_MYSQLND
2286 	if (mysql_stmt_attr_set(stmt->stmt, attr, mode_p)) {
2287 #else
2288 	if (FAIL == mysql_stmt_attr_set(stmt->stmt, attr, mode_p)) {
2289 #endif
2290 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
2291 		RETURN_FALSE;
2292 	}
2293 	RETURN_TRUE;
2294 }
2295 /* }}} */
2296 
2297 /* {{{ */
2298 PHP_FUNCTION(mysqli_stmt_attr_get)
2299 {
2300 	MY_STMT	*stmt;
2301 	zval	*mysql_stmt;
2302 	unsigned long	value = 0;
2303 	zend_long	attr;
2304 	int		rc;
2305 
2306 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_stmt, mysqli_stmt_class_entry, &attr) == FAILURE) {
2307 		RETURN_THROWS();
2308 	}
2309 
2310 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2311 
2312 	if ((rc = mysql_stmt_attr_get(stmt->stmt, attr, &value))) {
2313 		/* Success corresponds to 0 return value and a non-zero value
2314 		 * should only happen if the attr/option is unknown */
2315 		zend_argument_value_error(ERROR_ARG_POS(2), "must be one of "
2316 			"MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH, "
2317 			"MYSQLI_STMT_ATTR_PREFETCH_ROWS, or STMT_ATTR_CURSOR_TYPE");
2318 		RETURN_THROWS();
2319     }
2320 
2321 
2322 	if (attr == STMT_ATTR_UPDATE_MAX_LENGTH)
2323 		value = *((my_bool *)&value);
2324 	RETURN_LONG((unsigned long)value);
2325 }
2326 /* }}} */
2327 
2328 /* {{{ */
2329 PHP_FUNCTION(mysqli_stmt_errno)
2330 {
2331 	MY_STMT	*stmt;
2332 	zval	*mysql_stmt;
2333 
2334 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2335 		RETURN_THROWS();
2336 	}
2337 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_INITIALIZED);
2338 
2339 	RETURN_LONG(mysql_stmt_errno(stmt->stmt));
2340 }
2341 /* }}} */
2342 
2343 /* {{{ */
2344 PHP_FUNCTION(mysqli_stmt_error)
2345 {
2346 	MY_STMT	*stmt;
2347 	zval 	*mysql_stmt;
2348 
2349 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2350 		RETURN_THROWS();
2351 	}
2352 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_INITIALIZED);
2353 
2354 	RETURN_STRING(mysql_stmt_error(stmt->stmt));
2355 }
2356 /* }}} */
2357 
2358 /* {{{ Initialize statement object */
2359 PHP_FUNCTION(mysqli_stmt_init)
2360 {
2361 	MY_MYSQL		*mysql;
2362 	MY_STMT			*stmt;
2363 	zval			*mysql_link;
2364 	MYSQLI_RESOURCE	*mysqli_resource;
2365 
2366 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",&mysql_link, mysqli_link_class_entry) == FAILURE) {
2367 		RETURN_THROWS();
2368 	}
2369 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
2370 
2371 	stmt = (MY_STMT *)ecalloc(1,sizeof(MY_STMT));
2372 
2373 	if (!(stmt->stmt = mysql_stmt_init(mysql->mysql))) {
2374 		efree(stmt);
2375 		RETURN_FALSE;
2376 	}
2377 #ifndef MYSQLI_USE_MYSQLND
2378 	ZVAL_COPY(&stmt->link_handle, mysql_link);
2379 #endif
2380 
2381 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
2382 	mysqli_resource->status = MYSQLI_STATUS_INITIALIZED;
2383 	mysqli_resource->ptr = (void *)stmt;
2384 	MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_stmt_class_entry);
2385 }
2386 /* }}} */
2387 
2388 /* {{{ prepare server side statement with query */
2389 PHP_FUNCTION(mysqli_stmt_prepare)
2390 {
2391 	MY_STMT	*stmt;
2392 	zval 	*mysql_stmt;
2393 	char	*query;
2394 	size_t		query_len;
2395 
2396 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_stmt, mysqli_stmt_class_entry, &query, &query_len) == FAILURE) {
2397 		RETURN_THROWS();
2398 	}
2399 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_INITIALIZED);
2400 
2401 	if (mysql_stmt_prepare(stmt->stmt, query, query_len)) {
2402 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
2403 		RETURN_FALSE;
2404 	}
2405 	/* change status */
2406 	MYSQLI_SET_STATUS(mysql_stmt, MYSQLI_STATUS_VALID);
2407 	RETURN_TRUE;
2408 }
2409 /* }}} */
2410 
2411 /* {{{ return result set from statement */
2412 PHP_FUNCTION(mysqli_stmt_result_metadata)
2413 {
2414 	MY_STMT			*stmt;
2415 	MYSQL_RES		*result;
2416 	zval			*mysql_stmt;
2417 	MYSQLI_RESOURCE	*mysqli_resource;
2418 
2419 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2420 		RETURN_THROWS();
2421 	}
2422 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2423 
2424 	if (!(result = mysql_stmt_result_metadata(stmt->stmt))){
2425 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
2426 		RETURN_FALSE;
2427 	}
2428 
2429 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
2430 	mysqli_resource->ptr = (void *)result;
2431 	mysqli_resource->status = MYSQLI_STATUS_VALID;
2432 	MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_result_class_entry);
2433 }
2434 /* }}} */
2435 
2436 /* {{{ */
2437 PHP_FUNCTION(mysqli_stmt_store_result)
2438 {
2439 	MY_STMT	*stmt;
2440 	zval	*mysql_stmt;
2441 
2442 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2443 		RETURN_THROWS();
2444 	}
2445 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2446 
2447 #ifndef MYSQLI_USE_MYSQLND
2448 	{
2449 		/*
2450 		  If the user wants to store the data and we have BLOBs/TEXTs we try to allocate
2451 		  not the maximal length of the type (which is 16MB even for LONGBLOB) but
2452 		  the maximal length of the field in the result set. If he/she has quite big
2453 		  BLOB/TEXT columns after calling store_result() the memory usage of PHP will
2454 		  double - but this is a known problem of the simple MySQL API ;)
2455 		*/
2456 		int	i = 0;
2457 
2458 		for (i = mysql_stmt_field_count(stmt->stmt) - 1; i >=0; --i) {
2459 			if (stmt->stmt->fields && (stmt->stmt->fields[i].type == MYSQL_TYPE_BLOB ||
2460 				stmt->stmt->fields[i].type == MYSQL_TYPE_MEDIUM_BLOB ||
2461 				stmt->stmt->fields[i].type == MYSQL_TYPE_LONG_BLOB ||
2462 				stmt->stmt->fields[i].type == MYSQL_TYPE_GEOMETRY))
2463 			{
2464 				my_bool	tmp = 1;
2465 				mysql_stmt_attr_set(stmt->stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &tmp);
2466 				break;
2467 			}
2468 		}
2469 	}
2470 #endif
2471 
2472 	if (mysql_stmt_store_result(stmt->stmt)){
2473 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
2474 		RETURN_FALSE;
2475 	}
2476 	RETURN_TRUE;
2477 }
2478 /* }}} */
2479 
2480 /* {{{ */
2481 PHP_FUNCTION(mysqli_stmt_sqlstate)
2482 {
2483 	MY_STMT	*stmt;
2484 	zval	*mysql_stmt;
2485 
2486 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2487 		RETURN_THROWS();
2488 	}
2489 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2490 
2491 	RETURN_STRING(mysql_stmt_sqlstate(stmt->stmt));
2492 }
2493 /* }}} */
2494 
2495 /* {{{ Buffer result set on client */
2496 PHP_FUNCTION(mysqli_store_result)
2497 {
2498 	MY_MYSQL		*mysql;
2499 	MYSQL_RES		*result;
2500 	zval			*mysql_link;
2501 	MYSQLI_RESOURCE	*mysqli_resource;
2502 	zend_long flags = 0;
2503 
2504 
2505 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|l", &mysql_link, mysqli_link_class_entry, &flags) == FAILURE) {
2506 		RETURN_THROWS();
2507 	}
2508 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
2509 #ifdef MYSQLI_USE_MYSQLND
2510 	result = flags & MYSQLI_STORE_RESULT_COPY_DATA? mysqlnd_store_result_ofs(mysql->mysql) : mysqlnd_store_result(mysql->mysql);
2511 #else
2512 	result = mysql_store_result(mysql->mysql);
2513 #endif
2514 	if (!result) {
2515 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
2516 		RETURN_FALSE;
2517 	}
2518 	if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
2519 		php_mysqli_report_index("from previous query", mysqli_server_status(mysql->mysql));
2520 	}
2521 
2522 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
2523 	mysqli_resource->ptr = (void *)result;
2524 	mysqli_resource->status = MYSQLI_STATUS_VALID;
2525 	MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_result_class_entry);
2526 }
2527 /* }}} */
2528 
2529 /* {{{ Return the current thread ID */
2530 PHP_FUNCTION(mysqli_thread_id)
2531 {
2532 	MY_MYSQL	*mysql;
2533 	zval		*mysql_link;
2534 
2535 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
2536 		RETURN_THROWS();
2537 	}
2538 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
2539 
2540 	RETURN_LONG((zend_long) mysql_thread_id(mysql->mysql));
2541 }
2542 /* }}} */
2543 
2544 /* {{{ Return whether thread safety is given or not */
2545 PHP_FUNCTION(mysqli_thread_safe)
2546 {
2547 	if (zend_parse_parameters_none() == FAILURE) {
2548 		RETURN_THROWS();
2549 	}
2550 
2551 	RETURN_BOOL(mysql_thread_safe());
2552 }
2553 /* }}} */
2554 
2555 /* {{{ Directly retrieve query results - do not buffer results on client side */
2556 PHP_FUNCTION(mysqli_use_result)
2557 {
2558 	MY_MYSQL		*mysql;
2559 	MYSQL_RES		*result;
2560 	zval			*mysql_link;
2561 	MYSQLI_RESOURCE	*mysqli_resource;
2562 
2563 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
2564 		RETURN_THROWS();
2565 	}
2566 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
2567 
2568 	if (!(result = mysql_use_result(mysql->mysql))) {
2569 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
2570 		RETURN_FALSE;
2571 	}
2572 
2573 	if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
2574 		php_mysqli_report_index("from previous query", mysqli_server_status(mysql->mysql));
2575 	}
2576 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
2577 	mysqli_resource->ptr = (void *)result;
2578 	mysqli_resource->status = MYSQLI_STATUS_VALID;
2579 	MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_result_class_entry);
2580 }
2581 /* }}} */
2582 
2583 /* {{{ Return number of warnings from the last query for the given link */
2584 PHP_FUNCTION(mysqli_warning_count)
2585 {
2586 	MY_MYSQL	*mysql;
2587 	zval		*mysql_link;
2588 
2589 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
2590 		RETURN_THROWS();
2591 	}
2592 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
2593 
2594 	RETURN_LONG(mysql_warning_count(mysql->mysql));
2595 }
2596 /* }}} */
2597