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