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