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