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