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