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