xref: /PHP-7.2/ext/mysqli/mysqli_api.c (revision 82021ad9)
1 /*
2   +----------------------------------------------------------------------+
3   | PHP Version 7                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2018 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 != (size_t)(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 ((uint32_t)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) < 50123L) {
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 #if defined(MYSQLI_USE_MYSQLND)
1272 	const size_t	*ret;
1273 #else
1274 	const zend_ulong *ret;
1275 #endif
1276 
1277 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) {
1278 		return;
1279 	}
1280 
1281 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
1282 
1283 	if (!(ret = mysql_fetch_lengths(result))) {
1284 		RETURN_FALSE;
1285 	}
1286 
1287 	array_init(return_value);
1288 	num_fields = mysql_num_fields(result);
1289 
1290 	for (i = 0; i < num_fields; i++) {
1291 		add_index_long(return_value, i, ret[i]);
1292 	}
1293 }
1294 /* }}} */
1295 
1296 /* {{{ proto array mysqli_fetch_row (object result)
1297    Get a result row as an enumerated array */
1298 PHP_FUNCTION(mysqli_fetch_row)
1299 {
1300 	php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQLI_NUM, 0);
1301 }
1302 /* }}} */
1303 
1304 /* {{{ proto int mysqli_field_count(object link)
1305    Fetch the number of fields returned by the last query for the given link
1306 */
1307 PHP_FUNCTION(mysqli_field_count)
1308 {
1309 	MY_MYSQL	*mysql;
1310 	zval		*mysql_link;
1311 
1312 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1313 		return;
1314 	}
1315 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1316 
1317 	RETURN_LONG(mysql_field_count(mysql->mysql));
1318 }
1319 /* }}} */
1320 
1321 /* {{{ proto int mysqli_field_seek(object result, int fieldnr)
1322    Set result pointer to a specified field offset
1323 */
1324 PHP_FUNCTION(mysqli_field_seek)
1325 {
1326 	MYSQL_RES		*result;
1327 	zval			*mysql_result;
1328 	zend_long	fieldnr;
1329 
1330 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_result, mysqli_result_class_entry, &fieldnr) == FAILURE) {
1331 		return;
1332 	}
1333 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
1334 
1335 	if (fieldnr < 0 || (uint32_t)fieldnr >= mysql_num_fields(result)) {
1336 		php_error_docref(NULL, E_WARNING, "Invalid field offset");
1337 		RETURN_FALSE;
1338 	}
1339 
1340 	mysql_field_seek(result, fieldnr);
1341 	RETURN_TRUE;
1342 }
1343 /* }}} */
1344 
1345 /* {{{ proto int mysqli_field_tell(object result)
1346    Get current field offset of result pointer */
1347 PHP_FUNCTION(mysqli_field_tell)
1348 {
1349 	MYSQL_RES	*result;
1350 	zval		*mysql_result;
1351 
1352 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) {
1353 		return;
1354 	}
1355 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
1356 
1357 	RETURN_LONG(mysql_field_tell(result));
1358 }
1359 /* }}} */
1360 
1361 /* {{{ proto void mysqli_free_result(object result)
1362    Free query result memory for the given result handle */
1363 PHP_FUNCTION(mysqli_free_result)
1364 {
1365 	MYSQL_RES	*result;
1366 	zval		*mysql_result;
1367 
1368 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) {
1369 		return;
1370 	}
1371 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
1372 
1373 	mysqli_free_result(result, FALSE);
1374 	MYSQLI_CLEAR_RESOURCE(mysql_result);
1375 }
1376 /* }}} */
1377 
1378 /* {{{ proto string mysqli_get_client_info(void)
1379    Get MySQL client info */
1380 PHP_FUNCTION(mysqli_get_client_info)
1381 {
1382 	const char * info = mysql_get_client_info();
1383 	if (info) {
1384 		RETURN_STRING(info);
1385 	}
1386 }
1387 /* }}} */
1388 
1389 /* {{{ proto int mysqli_get_client_version(void)
1390    Get MySQL client info */
1391 PHP_FUNCTION(mysqli_get_client_version)
1392 {
1393 	RETURN_LONG((zend_long)mysql_get_client_version());
1394 }
1395 /* }}} */
1396 
1397 /* {{{ proto string mysqli_get_host_info (object link)
1398    Get MySQL host info */
1399 PHP_FUNCTION(mysqli_get_host_info)
1400 {
1401 	MY_MYSQL	*mysql;
1402 	zval		*mysql_link = NULL;
1403 
1404 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1405 		return;
1406 	}
1407 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1408 #if !defined(MYSQLI_USE_MYSQLND)
1409 	RETURN_STRING((mysql->mysql->host_info) ? mysql->mysql->host_info : "");
1410 #else
1411 	RETURN_STRING((mysql->mysql->data->host_info) ? mysql->mysql->data->host_info : "");
1412 #endif
1413 }
1414 /* }}} */
1415 
1416 /* {{{ proto int mysqli_get_proto_info(object link)
1417    Get MySQL protocol information */
1418 PHP_FUNCTION(mysqli_get_proto_info)
1419 {
1420 	MY_MYSQL	*mysql;
1421 	zval		*mysql_link = NULL;
1422 
1423 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1424 		return;
1425 	}
1426 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1427 	RETURN_LONG(mysql_get_proto_info(mysql->mysql));
1428 }
1429 /* }}} */
1430 
1431 /* {{{ proto string mysqli_get_server_info(object link)
1432    Get MySQL server info */
1433 PHP_FUNCTION(mysqli_get_server_info)
1434 {
1435 	MY_MYSQL	*mysql;
1436 	zval		*mysql_link = NULL;
1437 	const char	*info;
1438 
1439 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1440 		return;
1441 	}
1442 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1443 
1444 	info = mysql_get_server_info(mysql->mysql);
1445 	if (info) {
1446 		RETURN_STRING(info);
1447 	}
1448 }
1449 /* }}} */
1450 
1451 /* {{{ proto int mysqli_get_server_version(object link)
1452    Return the MySQL version for the server referenced by the given link */
1453 PHP_FUNCTION(mysqli_get_server_version)
1454 {
1455 	MY_MYSQL	*mysql;
1456 	zval		*mysql_link = NULL;
1457 
1458 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1459 		return;
1460 	}
1461 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1462 
1463 	RETURN_LONG(mysql_get_server_version(mysql->mysql));
1464 }
1465 /* }}} */
1466 
1467 /* {{{ proto string mysqli_info(object link)
1468    Get information about the most recent query */
1469 PHP_FUNCTION(mysqli_info)
1470 {
1471 	MY_MYSQL	*mysql;
1472 	zval		*mysql_link = NULL;
1473 	const char	*info;
1474 
1475 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1476 		return;
1477 	}
1478 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1479 
1480 	info = mysql_info(mysql->mysql);
1481 	if (info) {
1482 		RETURN_STRING(info);
1483 	}
1484 }
1485 /* }}} */
1486 
1487 /* {{{ php_mysqli_init() */
1488 void php_mysqli_init(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_method)
1489 {
1490 	MYSQLI_RESOURCE *mysqli_resource;
1491 	MY_MYSQL *mysql;
1492 
1493 	if (is_method && (Z_MYSQLI_P(getThis()))->ptr) {
1494 		return;
1495 	}
1496 
1497 	mysql = (MY_MYSQL *)ecalloc(1, sizeof(MY_MYSQL));
1498 
1499 #if !defined(MYSQLI_USE_MYSQLND)
1500 	if (!(mysql->mysql = mysql_init(NULL)))
1501 #else
1502 	/*
1503 	  We create always persistent, as if the user want to connecto
1504 	  to p:somehost, we can't convert the handle then
1505 	*/
1506 	if (!(mysql->mysql = mysqlnd_init(MYSQLND_CLIENT_KNOWS_RSET_COPY_DATA, TRUE)))
1507 #endif
1508 	{
1509 		efree(mysql);
1510 		RETURN_FALSE;
1511 	}
1512 
1513 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
1514 	mysqli_resource->ptr = (void *)mysql;
1515 	mysqli_resource->status = MYSQLI_STATUS_INITIALIZED;
1516 
1517 	if (!is_method) {
1518 		MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_link_class_entry);
1519 	} else {
1520 		(Z_MYSQLI_P(getThis()))->ptr = mysqli_resource;
1521 	}
1522 }
1523 /* }}} */
1524 
1525 /* {{{ proto resource mysqli_init(void)
1526    Initialize mysqli and return a resource for use with mysql_real_connect */
1527 PHP_FUNCTION(mysqli_init)
1528 {
1529 	php_mysqli_init(INTERNAL_FUNCTION_PARAM_PASSTHRU, FALSE);
1530 }
1531 /* }}} */
1532 
1533 /* {{{ proto resource mysqli::init(void)
1534    Initialize mysqli and return a resource for use with mysql_real_connect */
1535 PHP_FUNCTION(mysqli_init_method)
1536 {
1537 	php_mysqli_init(INTERNAL_FUNCTION_PARAM_PASSTHRU, TRUE);
1538 }
1539 /* }}} */
1540 
1541 /* {{{ proto mixed mysqli_insert_id(object link)
1542    Get the ID generated from the previous INSERT operation */
1543 PHP_FUNCTION(mysqli_insert_id)
1544 {
1545 	MY_MYSQL		*mysql;
1546 	my_ulonglong	rc;
1547 	zval			*mysql_link;
1548 
1549 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1550 		return;
1551 	}
1552 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1553 	rc = mysql_insert_id(mysql->mysql);
1554 	MYSQLI_RETURN_LONG_INT(rc)
1555 }
1556 /* }}} */
1557 
1558 /* {{{ proto bool mysqli_kill(object link, int processid)
1559    Kill a mysql process on the server */
1560 PHP_FUNCTION(mysqli_kill)
1561 {
1562 	MY_MYSQL	*mysql;
1563 	zval		*mysql_link;
1564 	zend_long		processid;
1565 
1566 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_link, mysqli_link_class_entry, &processid) == FAILURE) {
1567 		return;
1568 	}
1569 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1570 
1571 	if (processid <= 0) {
1572 		php_error_docref(NULL, E_WARNING, "processid should have positive value");
1573 		RETURN_FALSE;
1574 	}
1575 
1576 	if (mysql_kill(mysql->mysql, processid)) {
1577 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1578 		RETURN_FALSE;
1579 	}
1580 	RETURN_TRUE;
1581 }
1582 /* }}} */
1583 
1584 /* {{{ proto bool mysqli_more_results(object link)
1585    check if there any more query results from a multi query */
1586 PHP_FUNCTION(mysqli_more_results)
1587 {
1588 	MY_MYSQL	*mysql;
1589 	zval		*mysql_link;
1590 
1591 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1592 		return;
1593 	}
1594 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1595 
1596 	RETURN_BOOL(mysql_more_results(mysql->mysql));
1597 }
1598 /* }}} */
1599 
1600 /* {{{ proto bool mysqli_next_result(object link)
1601    read next result from multi_query */
1602 PHP_FUNCTION(mysqli_next_result) {
1603 	MY_MYSQL	*mysql;
1604 	zval		*mysql_link;
1605 
1606 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1607 		return;
1608 	}
1609 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1610 
1611 	if (!mysql_more_results(mysql->mysql)) {
1612 		php_error_docref(NULL, E_STRICT, "There is no next result set. "
1613 						"Please, call mysqli_more_results()/mysqli::more_results() to check "
1614 						"whether to call this function/method");
1615 	}
1616 
1617 	RETURN_BOOL(!mysql_next_result(mysql->mysql));
1618 }
1619 /* }}} */
1620 
1621 #if defined(HAVE_STMT_NEXT_RESULT) && defined(MYSQLI_USE_MYSQLND)
1622 /* {{{ proto bool mysqli_stmt_next_result(object link)
1623    check if there any more query results from a multi query */
1624 PHP_FUNCTION(mysqli_stmt_more_results)
1625 {
1626 	MY_STMT		*stmt;
1627 	zval		*mysql_stmt;
1628 
1629 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
1630 		return;
1631 	}
1632 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1633 
1634 	RETURN_BOOL(mysqlnd_stmt_more_results(stmt->stmt));
1635 }
1636 /* }}} */
1637 
1638 /* {{{ proto bool mysqli_stmt_next_result(object link)
1639    read next result from multi_query */
1640 PHP_FUNCTION(mysqli_stmt_next_result) {
1641 	MY_STMT		*stmt;
1642 	zval		*mysql_stmt;
1643 
1644 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
1645 		return;
1646 	}
1647 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
1648 
1649 	if (!mysqlnd_stmt_more_results(stmt->stmt)) {
1650 		php_error_docref(NULL, E_STRICT, "There is no next result set. "
1651 						"Please, call mysqli_stmt_more_results()/mysqli_stmt::more_results() to check "
1652 						"whether to call this function/method");
1653 	}
1654 
1655 	RETURN_BOOL(!mysql_stmt_next_result(stmt->stmt));
1656 }
1657 /* }}} */
1658 #endif
1659 
1660 /* {{{ proto int mysqli_num_fields(object result)
1661    Get number of fields in result */
1662 PHP_FUNCTION(mysqli_num_fields)
1663 {
1664 	MYSQL_RES	*result;
1665 	zval		*mysql_result;
1666 
1667 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) {
1668 		return;
1669 	}
1670 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
1671 
1672 	RETURN_LONG(mysql_num_fields(result));
1673 }
1674 /* }}} */
1675 
1676 /* {{{ proto mixed mysqli_num_rows(object result)
1677    Get number of rows in result */
1678 PHP_FUNCTION(mysqli_num_rows)
1679 {
1680 	MYSQL_RES	*result;
1681 	zval		*mysql_result;
1682 
1683 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) {
1684 		return;
1685 	}
1686 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
1687 
1688 	if (mysqli_result_is_unbuffered_and_not_everything_is_fetched(result)) {
1689 		php_error_docref(NULL, E_WARNING, "Function cannot be used with MYSQL_USE_RESULT");
1690 		RETURN_LONG(0);
1691 	}
1692 
1693 	MYSQLI_RETURN_LONG_INT(mysql_num_rows(result));
1694 }
1695 /* }}} */
1696 
1697 /* {{{ mysqli_options_get_option_zval_type */
1698 static int mysqli_options_get_option_zval_type(int option)
1699 {
1700 	switch (option) {
1701 #ifdef MYSQLI_USE_MYSQLND
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 #if MYSQL_VERSION_ID > 40101 || defined(MYSQLI_USE_MYSQLND)
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
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 (PG(open_basedir) && PG(open_basedir)[0] != '\0') {
1783 		if(mysql_option == MYSQL_OPT_LOCAL_INFILE) {
1784 			RETURN_FALSE;
1785 		}
1786 	}
1787 #endif
1788 	expected_type = mysqli_options_get_option_zval_type(mysql_option);
1789 	if (expected_type != Z_TYPE_P(mysql_value)) {
1790 		switch (expected_type) {
1791 			case IS_STRING:
1792 				convert_to_string_ex(mysql_value);
1793 				break;
1794 			case IS_LONG:
1795 				convert_to_long_ex(mysql_value);
1796 				break;
1797 			default:
1798 				break;
1799 		}
1800 	}
1801 	switch (expected_type) {
1802 		case IS_STRING:
1803 			ret = mysql_options(mysql->mysql, mysql_option, Z_STRVAL_P(mysql_value));
1804 			break;
1805 		case IS_LONG:
1806 			l_value = Z_LVAL_P(mysql_value);
1807 			ret = mysql_options(mysql->mysql, mysql_option, (char *)&l_value);
1808 			break;
1809 		default:
1810 			ret = 1;
1811 			break;
1812 	}
1813 
1814 	RETURN_BOOL(!ret);
1815 }
1816 /* }}} */
1817 
1818 /* {{{ proto bool mysqli_ping(object link)
1819    Ping a server connection or reconnect if there is no connection */
1820 PHP_FUNCTION(mysqli_ping)
1821 {
1822 	MY_MYSQL	*mysql;
1823 	zval		*mysql_link;
1824 	zend_long		rc;
1825 
1826 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1827 		return;
1828 	}
1829 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1830 	rc = mysql_ping(mysql->mysql);
1831 	MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1832 
1833 	RETURN_BOOL(!rc);
1834 }
1835 /* }}} */
1836 
1837 /* {{{ proto mixed mysqli_prepare(object link, string query)
1838    Prepare a SQL statement for execution */
1839 PHP_FUNCTION(mysqli_prepare)
1840 {
1841 	MY_MYSQL		*mysql;
1842 	MY_STMT			*stmt;
1843 	char			*query = NULL;
1844 	size_t				query_len;
1845 	zval			*mysql_link;
1846 	MYSQLI_RESOURCE	*mysqli_resource;
1847 
1848 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os",&mysql_link, mysqli_link_class_entry, &query, &query_len) == FAILURE) {
1849 		return;
1850 	}
1851 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1852 
1853 #if !defined(MYSQLI_USE_MYSQLND)
1854 	if (mysql->mysql->status == MYSQL_STATUS_GET_RESULT) {
1855 		php_error_docref(NULL, E_WARNING, "All data must be fetched before a new statement prepare takes place");
1856 		RETURN_FALSE;
1857 	}
1858 #endif
1859 
1860 	stmt = (MY_STMT *)ecalloc(1,sizeof(MY_STMT));
1861 
1862 	if ((stmt->stmt = mysql_stmt_init(mysql->mysql))) {
1863 		if (mysql_stmt_prepare(stmt->stmt, query, query_len)) {
1864 			/* mysql_stmt_close() clears errors, so we have to store them temporarily */
1865 #if !defined(MYSQLI_USE_MYSQLND)
1866 			char  last_error[MYSQL_ERRMSG_SIZE];
1867 			char  sqlstate[SQLSTATE_LENGTH+1];
1868 			unsigned int last_errno;
1869 
1870 			last_errno = stmt->stmt->last_errno;
1871 			memcpy(last_error, stmt->stmt->last_error, MYSQL_ERRMSG_SIZE);
1872 			memcpy(sqlstate, mysql->mysql->net.sqlstate, SQLSTATE_LENGTH+1);
1873 #else
1874 			MYSQLND_ERROR_INFO error_info = *mysql->mysql->data->error_info;
1875 #endif
1876 			mysqli_stmt_close(stmt->stmt, FALSE);
1877 			stmt->stmt = NULL;
1878 
1879 			/* restore error messages */
1880 #if !defined(MYSQLI_USE_MYSQLND)
1881 			mysql->mysql->net.last_errno = last_errno;
1882 			memcpy(mysql->mysql->net.last_error, last_error, MYSQL_ERRMSG_SIZE);
1883 			memcpy(mysql->mysql->net.sqlstate, sqlstate, SQLSTATE_LENGTH+1);
1884 #else
1885 			*mysql->mysql->data->error_info = error_info;
1886 #endif
1887 		}
1888 	}
1889 
1890 	/* don't initialize stmt->query with NULL, we ecalloc()-ed the memory */
1891 	/* Get performance boost if reporting is switched off */
1892 	if (stmt->stmt && query_len && (MyG(report_mode) & MYSQLI_REPORT_INDEX)) {
1893 		stmt->query = (char *)emalloc(query_len + 1);
1894 		memcpy(stmt->query, query, query_len);
1895 		stmt->query[query_len] = '\0';
1896 	}
1897 
1898 	/* don't join to the previous if because it won't work if mysql_stmt_prepare_fails */
1899 	if (!stmt->stmt) {
1900 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1901 		efree(stmt);
1902 		RETURN_FALSE;
1903 	}
1904 #ifndef MYSQLI_USE_MYSQLND
1905 	ZVAL_COPY(&stmt->link_handle, mysql_link);
1906 #endif
1907 
1908 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
1909 	mysqli_resource->ptr = (void *)stmt;
1910 
1911 	/* change status */
1912 	mysqli_resource->status = MYSQLI_STATUS_VALID;
1913 	MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_stmt_class_entry);
1914 }
1915 /* }}} */
1916 
1917 /* {{{ proto bool mysqli_real_connect(object link [,string hostname [,string username [,string passwd [,string dbname [,int port [,string socket [,int flags]]]]]]])
1918    Open a connection to a mysql server */
1919 PHP_FUNCTION(mysqli_real_connect)
1920 {
1921 	mysqli_common_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, TRUE, FALSE);
1922 }
1923 /* }}} */
1924 
1925 /* {{{ proto bool mysqli_real_query(object link, string query)
1926    Binary-safe version of mysql_query() */
1927 PHP_FUNCTION(mysqli_real_query)
1928 {
1929 	MY_MYSQL	*mysql;
1930 	zval		*mysql_link;
1931 	char		*query = NULL;
1932 	size_t		query_len;
1933 
1934 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_link, mysqli_link_class_entry, &query, &query_len) == FAILURE) {
1935 		return;
1936 	}
1937 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1938 
1939 	MYSQLI_DISABLE_MQ; /* disable multi statements/queries */
1940 
1941 	if (mysql_real_query(mysql->mysql, query, query_len)) {
1942 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1943 		RETURN_FALSE;
1944 	}
1945 
1946 	if (!mysql_field_count(mysql->mysql)) {
1947 		if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
1948 			php_mysqli_report_index(query, mysqli_server_status(mysql->mysql));
1949 		}
1950 	}
1951 
1952 	RETURN_TRUE;
1953 }
1954 /* }}} */
1955 
1956 /* {{{ proto string mysqli_real_escape_string(object link, string escapestr)
1957    Escapes special characters in a string for use in a SQL statement, taking into account the current charset of the connection */
1958 PHP_FUNCTION(mysqli_real_escape_string) {
1959 	MY_MYSQL	*mysql;
1960 	zval		*mysql_link = NULL;
1961 	char		*escapestr;
1962 	size_t			escapestr_len;
1963 	zend_string *newstr;
1964 
1965 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_link, mysqli_link_class_entry, &escapestr, &escapestr_len) == FAILURE) {
1966 		return;
1967 	}
1968 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1969 
1970 	newstr = zend_string_alloc(2 * escapestr_len, 0);
1971 	ZSTR_LEN(newstr) = mysql_real_escape_string(mysql->mysql, ZSTR_VAL(newstr), escapestr, escapestr_len);
1972 	newstr = zend_string_truncate(newstr, ZSTR_LEN(newstr), 0);
1973 
1974 	RETURN_NEW_STR(newstr);
1975 }
1976 /* }}} */
1977 
1978 /* {{{ proto bool mysqli_rollback(object link)
1979    Undo actions from current transaction */
1980 PHP_FUNCTION(mysqli_rollback)
1981 {
1982 	MY_MYSQL	*mysql;
1983 	zval		*mysql_link;
1984 	zend_long		flags = TRANS_COR_NO_OPT;
1985 	char *		name = NULL;
1986 	size_t			name_len = 0;
1987 
1988 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|ls", &mysql_link, mysqli_link_class_entry, &flags, &name, &name_len) == FAILURE) {
1989 		return;
1990 	}
1991 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1992 
1993 #if !defined(MYSQLI_USE_MYSQLND)
1994 	if (mysqli_commit_or_rollback_libmysql(mysql->mysql, FALSE, flags, name)) {
1995 #else
1996 	if (FAIL == mysqlnd_rollback(mysql->mysql, flags, name)) {
1997 #endif
1998 		RETURN_FALSE;
1999 	}
2000 	RETURN_TRUE;
2001 }
2002 /* }}} */
2003 
2004 /* {{{ proto bool mysqli_stmt_send_long_data(object stmt, int param_nr, string data)
2005 */
2006 PHP_FUNCTION(mysqli_stmt_send_long_data)
2007 {
2008 	MY_STMT *stmt;
2009 	zval	*mysql_stmt;
2010 	char	*data;
2011 	zend_long	param_nr;
2012 	size_t		data_len;
2013 
2014 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ols", &mysql_stmt, mysqli_stmt_class_entry, &param_nr, &data, &data_len) == FAILURE) {
2015 		return;
2016 	}
2017 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2018 
2019 	if (param_nr < 0) {
2020 		php_error_docref(NULL, E_WARNING, "Invalid parameter number");
2021 		RETURN_FALSE;
2022 	}
2023 	if (mysql_stmt_send_long_data(stmt->stmt, param_nr, data, data_len)) {
2024 		RETURN_FALSE;
2025 	}
2026 	RETURN_TRUE;
2027 }
2028 /* }}} */
2029 
2030 /* {{{ proto mixed mysqli_stmt_affected_rows(object stmt)
2031    Return the number of rows affected in the last query for the given link */
2032 PHP_FUNCTION(mysqli_stmt_affected_rows)
2033 {
2034 	MY_STMT			*stmt;
2035 	zval			*mysql_stmt;
2036 	my_ulonglong	rc;
2037 
2038 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2039 		return;
2040 	}
2041 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2042 
2043 	rc = mysql_stmt_affected_rows(stmt->stmt);
2044 	if (rc == (my_ulonglong) -1) {
2045 		RETURN_LONG(-1);
2046 	}
2047 	MYSQLI_RETURN_LONG_INT(rc)
2048 }
2049 /* }}} */
2050 
2051 /* {{{ proto bool mysqli_stmt_close(object stmt)
2052    Close statement */
2053 PHP_FUNCTION(mysqli_stmt_close)
2054 {
2055 	MY_STMT		*stmt;
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;
2060 	}
2061 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2062 
2063 	mysqli_stmt_close(stmt->stmt, FALSE);
2064 	stmt->stmt = NULL;
2065 	php_clear_stmt_bind(stmt);
2066 	MYSQLI_CLEAR_RESOURCE(mysql_stmt);
2067 	RETURN_TRUE;
2068 }
2069 /* }}} */
2070 
2071 /* {{{ proto void mysqli_stmt_data_seek(object stmt, int offset)
2072    Move internal result pointer */
2073 PHP_FUNCTION(mysqli_stmt_data_seek)
2074 {
2075 	MY_STMT		*stmt;
2076 	zval		*mysql_stmt;
2077 	zend_long		offset;
2078 
2079 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_stmt, mysqli_stmt_class_entry, &offset) == FAILURE) {
2080 		return;
2081 	}
2082 	if (offset < 0) {
2083 		php_error_docref(NULL, E_WARNING, "Offset must be positive");
2084 		RETURN_FALSE;
2085 	}
2086 
2087 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2088 
2089 	mysql_stmt_data_seek(stmt->stmt, offset);
2090 }
2091 /* }}} */
2092 
2093 /* {{{ proto int mysqli_stmt_field_count(object stmt) {
2094    Return the number of result columns for the given statement */
2095 PHP_FUNCTION(mysqli_stmt_field_count)
2096 {
2097 	MY_STMT		*stmt;
2098 	zval		*mysql_stmt;
2099 
2100 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2101 		return;
2102 	}
2103 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2104 
2105 	RETURN_LONG(mysql_stmt_field_count(stmt->stmt));
2106 }
2107 /* }}} */
2108 
2109 /* {{{ proto void mysqli_stmt_free_result(object stmt)
2110    Free stored result memory for the given statement handle */
2111 PHP_FUNCTION(mysqli_stmt_free_result)
2112 {
2113 	MY_STMT		*stmt;
2114 	zval		*mysql_stmt;
2115 
2116 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2117 		return;
2118 	}
2119 
2120 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2121 
2122 	mysql_stmt_free_result(stmt->stmt);
2123 }
2124 /* }}} */
2125 
2126 /* {{{ proto mixed mysqli_stmt_insert_id(object stmt)
2127    Get the ID generated from the previous INSERT operation */
2128 PHP_FUNCTION(mysqli_stmt_insert_id)
2129 {
2130 	MY_STMT			*stmt;
2131 	my_ulonglong	rc;
2132 	zval			*mysql_stmt;
2133 
2134 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2135 		return;
2136 	}
2137 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2138 	rc = mysql_stmt_insert_id(stmt->stmt);
2139 	MYSQLI_RETURN_LONG_INT(rc)
2140 }
2141 /* }}} */
2142 
2143 /* {{{ proto int mysqli_stmt_param_count(object stmt)
2144    Return the number of parameter for the given statement */
2145 PHP_FUNCTION(mysqli_stmt_param_count)
2146 {
2147 	MY_STMT		*stmt;
2148 	zval		*mysql_stmt;
2149 
2150 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2151 		return;
2152 	}
2153 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2154 
2155 	RETURN_LONG(mysql_stmt_param_count(stmt->stmt));
2156 }
2157 /* }}} */
2158 
2159 /* {{{ proto bool mysqli_stmt_reset(object stmt)
2160    reset a prepared statement */
2161 PHP_FUNCTION(mysqli_stmt_reset)
2162 {
2163 	MY_STMT		*stmt;
2164 	zval		*mysql_stmt;
2165 
2166 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2167 		return;
2168 	}
2169 
2170 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2171 
2172 	if (mysql_stmt_reset(stmt->stmt)) {
2173 		RETURN_FALSE;
2174 	}
2175 	RETURN_TRUE;
2176 }
2177 /* }}} */
2178 
2179 /* {{{ proto mixed mysqli_stmt_num_rows(object stmt)
2180    Return the number of rows in statements result set */
2181 PHP_FUNCTION(mysqli_stmt_num_rows)
2182 {
2183 	MY_STMT			*stmt;
2184 	zval			*mysql_stmt;
2185 	my_ulonglong	rc;
2186 
2187 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2188 		return;
2189 	}
2190 
2191 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2192 
2193 	rc = mysql_stmt_num_rows(stmt->stmt);
2194 	MYSQLI_RETURN_LONG_INT(rc)
2195 }
2196 /* }}} */
2197 
2198 /* {{{ proto bool mysqli_select_db(object link, string dbname)
2199    Select a MySQL database */
2200 PHP_FUNCTION(mysqli_select_db)
2201 {
2202 	MY_MYSQL	*mysql;
2203 	zval		*mysql_link;
2204 	char		*dbname;
2205 	size_t			dbname_len;
2206 
2207 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_link, mysqli_link_class_entry, &dbname, &dbname_len) == FAILURE) {
2208 		return;
2209 	}
2210 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
2211 
2212 	if (mysql_select_db(mysql->mysql, dbname)) {
2213 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
2214 		RETURN_FALSE;
2215 	}
2216 	RETURN_TRUE;
2217 }
2218 /* }}} */
2219 
2220 /* {{{ proto string mysqli_sqlstate(object link)
2221    Returns the SQLSTATE error from previous MySQL operation */
2222 PHP_FUNCTION(mysqli_sqlstate)
2223 {
2224 	MY_MYSQL	*mysql;
2225 	zval		*mysql_link;
2226 	const char	*state;
2227 
2228 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
2229 		return;
2230 	}
2231 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
2232 	state = mysql_sqlstate(mysql->mysql);
2233 	if (state) {
2234 		RETURN_STRING(state);
2235 	}
2236 }
2237 /* }}} */
2238 
2239 /* {{{ proto bool mysqli_ssl_set(object link ,string key ,string cert ,string ca ,string capath ,string cipher])
2240 */
2241 PHP_FUNCTION(mysqli_ssl_set)
2242 {
2243 	MY_MYSQL	*mysql;
2244 	zval		*mysql_link;
2245 	char		*ssl_parm[5];
2246 	size_t			ssl_parm_len[5], i;
2247 
2248 	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) {
2249 		return;
2250 	}
2251 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_INITIALIZED);
2252 
2253 	for (i = 0; i < 5; i++) {
2254 		if (!ssl_parm_len[i]) {
2255 			ssl_parm[i] = NULL;
2256 		}
2257 	}
2258 
2259 	mysql_ssl_set(mysql->mysql, ssl_parm[0], ssl_parm[1], ssl_parm[2], ssl_parm[3], ssl_parm[4]);
2260 
2261 	RETURN_TRUE;
2262 }
2263 /* }}} */
2264 
2265 /* {{{ proto mixed mysqli_stat(object link)
2266    Get current system status */
2267 PHP_FUNCTION(mysqli_stat)
2268 {
2269 	MY_MYSQL	*mysql;
2270 	zval		*mysql_link;
2271 #if defined(MYSQLI_USE_MYSQLND)
2272 	zend_string *stat;
2273 #else
2274 	char		*stat;
2275 #endif
2276 
2277 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
2278 		return;
2279 	}
2280 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
2281 
2282 #if !defined(MYSQLI_USE_MYSQLND)
2283 	if ((stat = (char *)mysql_stat(mysql->mysql)))
2284 	{
2285 		RETURN_STRING(stat);
2286 #else
2287 	if (mysqlnd_stat(mysql->mysql, &stat) == PASS)
2288 	{
2289 		RETURN_STR(stat);
2290 #endif
2291 	} else {
2292 		RETURN_FALSE;
2293 	}
2294 }
2295 
2296 /* }}} */
2297 
2298 /* {{{ proto bool mysqli_refresh(object link, long options)
2299    Flush tables or caches, or reset replication server information */
2300 PHP_FUNCTION(mysqli_refresh)
2301 {
2302 	MY_MYSQL *mysql;
2303 	zval *mysql_link = NULL;
2304 	zend_long options;
2305 
2306 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_link, mysqli_link_class_entry, &options) == FAILURE) {
2307 		return;
2308 	}
2309 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_INITIALIZED);
2310 #ifdef MYSQLI_USE_MYSQLND
2311 	RETURN_BOOL(!mysql_refresh(mysql->mysql, (uint8_t) options));
2312 #else
2313 	RETURN_BOOL(!mysql_refresh(mysql->mysql, options));
2314 #endif
2315 }
2316 /* }}} */
2317 
2318 /* {{{ proto int mysqli_stmt_attr_set(object stmt, long attr, long mode)
2319 */
2320 PHP_FUNCTION(mysqli_stmt_attr_set)
2321 {
2322 	MY_STMT	*stmt;
2323 	zval	*mysql_stmt;
2324 	zend_long	mode_in;
2325 #if MYSQL_VERSION_ID >= 50107
2326 	my_bool	mode_b;
2327 #endif
2328 	zend_ulong	mode;
2329 	zend_long	attr;
2330 	void	*mode_p;
2331 
2332 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oll", &mysql_stmt, mysqli_stmt_class_entry, &attr, &mode_in) == FAILURE) {
2333 		return;
2334 	}
2335 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2336 
2337 	if (mode_in < 0) {
2338 		php_error_docref(NULL, E_WARNING, "mode should be non-negative, " ZEND_LONG_FMT " passed", mode_in);
2339 		RETURN_FALSE;
2340 	}
2341 
2342 	switch (attr) {
2343 #if MYSQL_VERSION_ID >= 50107
2344 	case STMT_ATTR_UPDATE_MAX_LENGTH:
2345 		mode_b = (my_bool) mode_in;
2346 		mode_p = &mode_b;
2347 		break;
2348 #endif
2349 	default:
2350 		mode = mode_in;
2351 		mode_p = &mode;
2352 		break;
2353 	}
2354 #if !defined(MYSQLI_USE_MYSQLND)
2355 	if (mysql_stmt_attr_set(stmt->stmt, attr, mode_p)) {
2356 #else
2357 	if (FAIL == mysql_stmt_attr_set(stmt->stmt, attr, mode_p)) {
2358 #endif
2359 		RETURN_FALSE;
2360 	}
2361 	RETURN_TRUE;
2362 }
2363 /* }}} */
2364 
2365 /* {{{ proto int mysqli_stmt_attr_get(object stmt, long attr)
2366 */
2367 PHP_FUNCTION(mysqli_stmt_attr_get)
2368 {
2369 	MY_STMT	*stmt;
2370 	zval	*mysql_stmt;
2371 	zend_ulong	value = 0;
2372 	zend_long	attr;
2373 	int		rc;
2374 
2375 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &mysql_stmt, mysqli_stmt_class_entry, &attr) == FAILURE) {
2376 		return;
2377 	}
2378 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2379 
2380 	if ((rc = mysql_stmt_attr_get(stmt->stmt, attr, &value))) {
2381 		RETURN_FALSE;
2382 	}
2383 
2384 #if MYSQL_VERSION_ID >= 50107
2385 	if (attr == STMT_ATTR_UPDATE_MAX_LENGTH)
2386 		value = *((my_bool *)&value);
2387 #endif
2388 	RETURN_LONG((zend_ulong)value);
2389 }
2390 /* }}} */
2391 
2392 /* {{{ proto int mysqli_stmt_errno(object stmt)
2393 */
2394 PHP_FUNCTION(mysqli_stmt_errno)
2395 {
2396 	MY_STMT	*stmt;
2397 	zval	*mysql_stmt;
2398 
2399 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2400 		return;
2401 	}
2402 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_INITIALIZED);
2403 
2404 	RETURN_LONG(mysql_stmt_errno(stmt->stmt));
2405 }
2406 /* }}} */
2407 
2408 /* {{{ proto string mysqli_stmt_error(object stmt)
2409 */
2410 PHP_FUNCTION(mysqli_stmt_error)
2411 {
2412 	MY_STMT	*stmt;
2413 	zval 	*mysql_stmt;
2414 	const char * err;
2415 
2416 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2417 		return;
2418 	}
2419 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_INITIALIZED);
2420 
2421 	err = mysql_stmt_error(stmt->stmt);
2422 	if (err) {
2423 		RETURN_STRING(err);
2424 	}
2425 }
2426 /* }}} */
2427 
2428 /* {{{ proto mixed mysqli_stmt_init(object link)
2429    Initialize statement object
2430 */
2431 PHP_FUNCTION(mysqli_stmt_init)
2432 {
2433 	MY_MYSQL		*mysql;
2434 	MY_STMT			*stmt;
2435 	zval			*mysql_link;
2436 	MYSQLI_RESOURCE	*mysqli_resource;
2437 
2438 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",&mysql_link, mysqli_link_class_entry) == FAILURE) {
2439 		return;
2440 	}
2441 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
2442 
2443 	stmt = (MY_STMT *)ecalloc(1,sizeof(MY_STMT));
2444 
2445 	if (!(stmt->stmt = mysql_stmt_init(mysql->mysql))) {
2446 		efree(stmt);
2447 		RETURN_FALSE;
2448 	}
2449 #ifndef MYSQLI_USE_MYSQLND
2450 	ZVAL_COPY(&stmt->link_handle, mysql_link);
2451 #endif
2452 
2453 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
2454 	mysqli_resource->status = MYSQLI_STATUS_INITIALIZED;
2455 	mysqli_resource->ptr = (void *)stmt;
2456 	MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_stmt_class_entry);
2457 }
2458 /* }}} */
2459 
2460 /* {{{ proto bool mysqli_stmt_prepare(object stmt, string query)
2461    prepare server side statement with query
2462 */
2463 PHP_FUNCTION(mysqli_stmt_prepare)
2464 {
2465 	MY_STMT	*stmt;
2466 	zval 	*mysql_stmt;
2467 	char	*query;
2468 	size_t		query_len;
2469 
2470 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_stmt, mysqli_stmt_class_entry, &query, &query_len) == FAILURE) {
2471 		return;
2472 	}
2473 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_INITIALIZED);
2474 
2475 	if (mysql_stmt_prepare(stmt->stmt, query, query_len)) {
2476 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
2477 		RETURN_FALSE;
2478 	}
2479 	/* change status */
2480 	MYSQLI_SET_STATUS(mysql_stmt, MYSQLI_STATUS_VALID);
2481 	RETURN_TRUE;
2482 }
2483 /* }}} */
2484 
2485 /* {{{ proto mixed mysqli_stmt_result_metadata(object stmt)
2486    return result set from statement */
2487 PHP_FUNCTION(mysqli_stmt_result_metadata)
2488 {
2489 	MY_STMT			*stmt;
2490 	MYSQL_RES		*result;
2491 	zval			*mysql_stmt;
2492 	MYSQLI_RESOURCE	*mysqli_resource;
2493 
2494 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2495 		return;
2496 	}
2497 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2498 
2499 	if (!(result = mysql_stmt_result_metadata(stmt->stmt))){
2500 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
2501 		RETURN_FALSE;
2502 	}
2503 
2504 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
2505 	mysqli_resource->ptr = (void *)result;
2506 	mysqli_resource->status = MYSQLI_STATUS_VALID;
2507 	MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_result_class_entry);
2508 }
2509 /* }}} */
2510 
2511 /* {{{ proto bool mysqli_stmt_store_result(object stmt)
2512 */
2513 PHP_FUNCTION(mysqli_stmt_store_result)
2514 {
2515 	MY_STMT	*stmt;
2516 	zval	*mysql_stmt;
2517 
2518 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2519 		return;
2520 	}
2521 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2522 
2523 #if !defined(MYSQLI_USE_MYSQLND)
2524 	{
2525 		/*
2526 		  If the user wants to store the data and we have BLOBs/TEXTs we try to allocate
2527 		  not the maximal length of the type (which is 16MB even for LONGBLOB) but
2528 		  the maximal length of the field in the result set. If he/she has quite big
2529 		  BLOB/TEXT columns after calling store_result() the memory usage of PHP will
2530 		  double - but this is a known problem of the simple MySQL API ;)
2531 		*/
2532 		int	i = 0;
2533 
2534 		for (i = mysql_stmt_field_count(stmt->stmt) - 1; i >=0; --i) {
2535 			if (stmt->stmt->fields && (stmt->stmt->fields[i].type == MYSQL_TYPE_BLOB ||
2536 				stmt->stmt->fields[i].type == MYSQL_TYPE_MEDIUM_BLOB ||
2537 				stmt->stmt->fields[i].type == MYSQL_TYPE_LONG_BLOB ||
2538 				stmt->stmt->fields[i].type == MYSQL_TYPE_GEOMETRY))
2539 			{
2540 #if MYSQL_VERSION_ID >= 50107
2541 				my_bool	tmp=1;
2542 #else
2543 				uint32_t tmp=1;
2544 #endif
2545 				mysql_stmt_attr_set(stmt->stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &tmp);
2546 				break;
2547 			}
2548 		}
2549 	}
2550 #endif
2551 
2552 	if (mysql_stmt_store_result(stmt->stmt)){
2553 		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
2554 		RETURN_FALSE;
2555 	}
2556 	RETURN_TRUE;
2557 }
2558 /* }}} */
2559 
2560 /* {{{ proto string mysqli_stmt_sqlstate(object stmt)
2561 */
2562 PHP_FUNCTION(mysqli_stmt_sqlstate)
2563 {
2564 	MY_STMT	*stmt;
2565 	zval	*mysql_stmt;
2566 	const char * state;
2567 
2568 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
2569 		return;
2570 	}
2571 	MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
2572 
2573 	state = mysql_stmt_sqlstate(stmt->stmt);
2574 	if (state) {
2575 		RETURN_STRING(state);
2576 	}
2577 }
2578 /* }}} */
2579 
2580 /* {{{ proto object mysqli_store_result(object link [, int flags])
2581    Buffer result set on client */
2582 PHP_FUNCTION(mysqli_store_result)
2583 {
2584 	MY_MYSQL		*mysql;
2585 	MYSQL_RES		*result;
2586 	zval			*mysql_link;
2587 	MYSQLI_RESOURCE	*mysqli_resource;
2588 	zend_long flags = 0;
2589 
2590 
2591 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|l", &mysql_link, mysqli_link_class_entry, &flags) == FAILURE) {
2592 		return;
2593 	}
2594 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
2595 #if MYSQLI_USE_MYSQLND
2596 	result = flags & MYSQLI_STORE_RESULT_COPY_DATA? mysqlnd_store_result_ofs(mysql->mysql) : mysqlnd_store_result(mysql->mysql);
2597 #else
2598 	result = mysql_store_result(mysql->mysql);
2599 #endif
2600 	if (!result) {
2601 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
2602 		RETURN_FALSE;
2603 	}
2604 	if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
2605 		php_mysqli_report_index("from previous query", mysqli_server_status(mysql->mysql));
2606 	}
2607 
2608 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
2609 	mysqli_resource->ptr = (void *)result;
2610 	mysqli_resource->status = MYSQLI_STATUS_VALID;
2611 	MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_result_class_entry);
2612 }
2613 /* }}} */
2614 
2615 /* {{{ proto int mysqli_thread_id(object link)
2616    Return the current thread ID */
2617 PHP_FUNCTION(mysqli_thread_id)
2618 {
2619 	MY_MYSQL	*mysql;
2620 	zval		*mysql_link;
2621 
2622 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
2623 		return;
2624 	}
2625 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
2626 
2627 	RETURN_LONG((zend_long) mysql_thread_id(mysql->mysql));
2628 }
2629 /* }}} */
2630 
2631 /* {{{ proto bool mysqli_thread_safe(void)
2632    Return whether thread safety is given or not */
2633 PHP_FUNCTION(mysqli_thread_safe)
2634 {
2635 	RETURN_BOOL(mysql_thread_safe());
2636 }
2637 /* }}} */
2638 
2639 /* {{{ proto mixed mysqli_use_result(object link)
2640    Directly retrieve query results - do not buffer results on client side */
2641 PHP_FUNCTION(mysqli_use_result)
2642 {
2643 	MY_MYSQL		*mysql;
2644 	MYSQL_RES		*result;
2645 	zval			*mysql_link;
2646 	MYSQLI_RESOURCE	*mysqli_resource;
2647 
2648 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
2649 		return;
2650 	}
2651 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
2652 
2653 	if (!(result = mysql_use_result(mysql->mysql))) {
2654 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
2655 		RETURN_FALSE;
2656 	}
2657 
2658 	if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
2659 		php_mysqli_report_index("from previous query", mysqli_server_status(mysql->mysql));
2660 	}
2661 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
2662 	mysqli_resource->ptr = (void *)result;
2663 	mysqli_resource->status = MYSQLI_STATUS_VALID;
2664 	MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_result_class_entry);
2665 }
2666 /* }}} */
2667 
2668 /* {{{ proto int mysqli_warning_count (object link)
2669    Return number of warnings from the last query for the given link */
2670 PHP_FUNCTION(mysqli_warning_count)
2671 {
2672 	MY_MYSQL	*mysql;
2673 	zval		*mysql_link;
2674 
2675 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
2676 		return;
2677 	}
2678 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
2679 
2680 	RETURN_LONG(mysql_warning_count(mysql->mysql));
2681 }
2682 /* }}} */
2683 
2684 /*
2685  * Local variables:
2686  * tab-width: 4
2687  * c-basic-offset: 4
2688  * End:
2689  * vim600: noet sw=4 ts=4 fdm=marker
2690  * vim<600: noet sw=4 ts=4
2691  */
2692