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 "ext/standard/info.h"
28 #include "zend_smart_str.h"
29 #if defined(MYSQLI_USE_MYSQLND)
30 #include "php_mysqli_structs.h"
31 #endif
32 #include "mysqli_priv.h"
33 #define ERROR_ARG_POS(arg_num) (getThis() ? (arg_num-1) : (arg_num))
34
35 #define SAFE_STR(a) ((a)?a:"")
36
37 /* {{{ php_mysqli_set_error */
php_mysqli_set_error(zend_long mysql_errno,char * mysql_err)38 static void php_mysqli_set_error(zend_long mysql_errno, char *mysql_err)
39 {
40 MyG(error_no) = mysql_errno;
41 if (MyG(error_msg)) {
42 efree(MyG(error_msg));
43 }
44 if(mysql_err && *mysql_err) {
45 MyG(error_msg) = estrdup(mysql_err);
46 } else {
47 MyG(error_msg) = NULL;
48 }
49 }
50 /* }}} */
51
mysqli_common_connect(INTERNAL_FUNCTION_PARAMETERS,zend_bool is_real_connect,zend_bool in_ctor)52 void mysqli_common_connect(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_real_connect, zend_bool in_ctor) /* {{{ */
53 {
54 MY_MYSQL *mysql = NULL;
55 MYSQLI_RESOURCE *mysqli_resource = NULL;
56 zval *object = getThis();
57 char *hostname = NULL, *username=NULL, *passwd=NULL, *dbname=NULL, *socket=NULL,
58 *ssl_key = NULL, *ssl_cert = NULL, *ssl_ca = NULL, *ssl_capath = NULL,
59 *ssl_cipher = NULL;
60 size_t hostname_len = 0, username_len = 0, passwd_len = 0, dbname_len = 0, socket_len = 0;
61 zend_bool persistent = FALSE, ssl = FALSE;
62 zend_long port = 0, flags = 0;
63 zend_bool port_is_null = 1;
64 zend_string *hash_key = NULL;
65 zend_bool new_connection = FALSE;
66 zend_resource *le;
67 mysqli_plist_entry *plist = NULL;
68 zend_bool self_alloced = 0;
69
70
71 #if !defined(MYSQL_USE_MYSQLND)
72 if ((MYSQL_VERSION_ID / 100) != (mysql_get_client_version() / 100)) {
73 php_error_docref(NULL, E_WARNING,
74 "Headers and client library minor version mismatch. Headers:%d Library:%ld",
75 MYSQL_VERSION_ID, mysql_get_client_version());
76 }
77 #endif
78
79 if (getThis() && !ZEND_NUM_ARGS() && in_ctor) {
80 php_mysqli_init(INTERNAL_FUNCTION_PARAM_PASSTHRU, in_ctor);
81 return;
82 }
83 hostname = username = dbname = passwd = socket = NULL;
84
85 if (!is_real_connect) {
86 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s!s!s!s!l!s!", &hostname, &hostname_len, &username, &username_len,
87 &passwd, &passwd_len, &dbname, &dbname_len, &port, &port_is_null, &socket, &socket_len) == FAILURE) {
88 RETURN_THROWS();
89 }
90
91 if (object && instanceof_function(Z_OBJCE_P(object), mysqli_link_class_entry)) {
92 mysqli_resource = (Z_MYSQLI_P(object))->ptr;
93 if (mysqli_resource && mysqli_resource->ptr) {
94 mysql = (MY_MYSQL*) mysqli_resource->ptr;
95 }
96 }
97 if (!mysql) {
98 mysql = (MY_MYSQL *) ecalloc(1, sizeof(MY_MYSQL));
99 self_alloced = 1;
100 }
101 flags |= CLIENT_MULTI_RESULTS; /* needed for mysql_multi_query() */
102 } else {
103 /* We have flags too */
104 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|s!s!s!s!l!s!l", &object, mysqli_link_class_entry,
105 &hostname, &hostname_len, &username, &username_len, &passwd, &passwd_len, &dbname, &dbname_len, &port, &port_is_null, &socket, &socket_len, &flags) == FAILURE) {
106 RETURN_THROWS();
107 }
108
109 mysqli_resource = (Z_MYSQLI_P(object))->ptr;
110 MYSQLI_FETCH_RESOURCE_CONN(mysql, object, MYSQLI_STATUS_INITIALIZED);
111
112 /* set some required options */
113 flags |= CLIENT_MULTI_RESULTS; /* needed for mysql_multi_query() */
114 /* remove some insecure options */
115 flags &= ~CLIENT_MULTI_STATEMENTS; /* don't allow multi_queries via connect parameter */
116 #ifndef MYSQLI_USE_MYSQLND
117 if (PG(open_basedir) && PG(open_basedir)[0] != '\0') {
118 flags &= ~CLIENT_LOCAL_FILES;
119 }
120 #endif
121 }
122
123 if (!socket_len || !socket) {
124 socket = MyG(default_socket);
125 }
126 if (port_is_null || !port) {
127 port = MyG(default_port);
128 }
129 if (!passwd) {
130 passwd = MyG(default_pw);
131 passwd_len = strlen(SAFE_STR(passwd));
132 }
133 if (!username){
134 username = MyG(default_user);
135 }
136 if (!hostname || !hostname_len) {
137 hostname = MyG(default_host);
138 }
139
140 if (mysql->mysql && mysqli_resource &&
141 (mysqli_resource->status > MYSQLI_STATUS_INITIALIZED))
142 {
143 /* already connected, we should close the connection */
144 php_mysqli_close(mysql, MYSQLI_CLOSE_IMPLICIT, mysqli_resource->status);
145 }
146
147 if (strlen(SAFE_STR(hostname)) > 2 && !strncasecmp(hostname, "p:", 2)) {
148 hostname += 2;
149 if (!MyG(allow_persistent)) {
150 php_error_docref(NULL, E_WARNING, "Persistent connections are disabled. Downgrading to normal");
151 } else {
152 mysql->persistent = persistent = TRUE;
153
154 hash_key = strpprintf(0, "mysqli_%s_%s" ZEND_LONG_FMT "%s%s%s", SAFE_STR(hostname), SAFE_STR(socket),
155 port, SAFE_STR(username), SAFE_STR(dbname),
156 SAFE_STR(passwd));
157
158 mysql->hash_key = hash_key;
159
160 /* check if we can reuse existing connection ... */
161 if ((le = zend_hash_find_ptr(&EG(persistent_list), hash_key)) != NULL) {
162 if (le->type == php_le_pmysqli()) {
163 plist = (mysqli_plist_entry *) le->ptr;
164
165 do {
166 if (zend_ptr_stack_num_elements(&plist->free_links)) {
167 /* If we have an initialized (but unconnected) mysql resource,
168 * close it before we reuse an existing persistent resource. */
169 if (mysql->mysql) {
170 mysqli_close(mysql->mysql, MYSQLI_CLOSE_IMPLICIT);
171 }
172
173 mysql->mysql = zend_ptr_stack_pop(&plist->free_links);
174
175 MyG(num_inactive_persistent)--;
176 /* reset variables */
177
178 #ifndef MYSQLI_NO_CHANGE_USER_ON_PCONNECT
179 if (!mysqli_change_user_silent(mysql->mysql, username, passwd, dbname, passwd_len)) {
180 #else
181 if (!mysql_ping(mysql->mysql)) {
182 #endif
183 #ifdef MYSQLI_USE_MYSQLND
184 mysqlnd_restart_psession(mysql->mysql);
185 #endif
186 MyG(num_active_persistent)++;
187
188 /* clear error */
189 php_mysqli_set_error(mysql_errno(mysql->mysql), (char *) mysql_error(mysql->mysql));
190
191 goto end;
192 } else {
193 #ifdef MYSQLI_USE_MYSQLND
194 if (mysql->mysql->data->vio->data->ssl) {
195 /* copy over pre-existing ssl settings so we can reuse them when reconnecting */
196 ssl = TRUE;
197
198 ssl_key = mysql->mysql->data->vio->data->options.ssl_key ? estrdup(mysql->mysql->data->vio->data->options.ssl_key) : NULL;
199 ssl_cert = mysql->mysql->data->vio->data->options.ssl_cert ? estrdup(mysql->mysql->data->vio->data->options.ssl_cert) : NULL;
200 ssl_ca = mysql->mysql->data->vio->data->options.ssl_ca ? estrdup(mysql->mysql->data->vio->data->options.ssl_ca) : NULL;
201 ssl_capath = mysql->mysql->data->vio->data->options.ssl_capath ? estrdup(mysql->mysql->data->vio->data->options.ssl_capath) : NULL;
202 ssl_cipher = mysql->mysql->data->vio->data->options.ssl_cipher ? estrdup(mysql->mysql->data->vio->data->options.ssl_cipher) : NULL;
203 }
204 #else
205 if (mysql->mysql->options.ssl_key
206 || mysql->mysql->options.ssl_cert
207 || mysql->mysql->options.ssl_ca
208 || mysql->mysql->options.ssl_capath
209 || mysql->mysql->options.ssl_cipher) {
210 /* copy over pre-existing ssl settings so we can reuse them when reconnecting */
211 ssl = TRUE;
212
213 ssl_key = mysql->mysql->options.ssl_key ? estrdup(mysql->mysql->options.ssl_key) : NULL;
214 ssl_cert = mysql->mysql->options.ssl_cert ? estrdup(mysql->mysql->options.ssl_cert) : NULL;
215 ssl_ca = mysql->mysql->options.ssl_ca ? estrdup(mysql->mysql->options.ssl_ca) : NULL;
216 ssl_capath = mysql->mysql->options.ssl_capath ? estrdup(mysql->mysql->options.ssl_capath) : NULL;
217 ssl_cipher = mysql->mysql->options.ssl_cipher ? estrdup(mysql->mysql->options.ssl_cipher) : NULL;
218 }
219 #endif
220 mysqli_close(mysql->mysql, MYSQLI_CLOSE_IMPLICIT);
221 mysql->mysql = NULL;
222 }
223 }
224 } while (0);
225 }
226 } else {
227 plist = calloc(1, sizeof(mysqli_plist_entry));
228
229 zend_ptr_stack_init_ex(&plist->free_links, 1);
230 zend_register_persistent_resource(ZSTR_VAL(hash_key), ZSTR_LEN(hash_key), plist, php_le_pmysqli());
231 }
232 }
233 }
234 if (MyG(max_links) != -1 && MyG(num_links) >= MyG(max_links)) {
235 php_error_docref(NULL, E_WARNING, "Too many open links (" ZEND_LONG_FMT ")", MyG(num_links));
236 goto err;
237 }
238
239 if (persistent && MyG(max_persistent) != -1 &&
240 (MyG(num_active_persistent) + MyG(num_inactive_persistent))>= MyG(max_persistent))
241 {
242 php_error_docref(NULL, E_WARNING, "Too many open persistent links (" ZEND_LONG_FMT ")",
243 MyG(num_active_persistent) + MyG(num_inactive_persistent));
244 goto err;
245 }
246 if (!mysql->mysql) {
247 #ifndef MYSQLI_USE_MYSQLND
248 if (!(mysql->mysql = mysql_init(NULL))) {
249 #else
250 if (!(mysql->mysql = mysqlnd_init(MYSQLND_CLIENT_KNOWS_RSET_COPY_DATA, persistent))) {
251 #endif
252 goto err;
253 }
254 new_connection = TRUE;
255 }
256
257 #ifndef MYSQLI_USE_MYSQLND
258 /* BC for prior to bug fix #53425 */
259 flags |= CLIENT_MULTI_RESULTS;
260
261 if (ssl) {
262 /* if we're here, this means previous conn was ssl, repopulate settings */
263 mysql_ssl_set(mysql->mysql, ssl_key, ssl_cert, ssl_ca, ssl_capath, ssl_cipher);
264
265 if (ssl_key) {
266 efree(ssl_key);
267 }
268
269 if (ssl_cert) {
270 efree(ssl_cert);
271 }
272
273 if (ssl_ca) {
274 efree(ssl_ca);
275 }
276
277 if (ssl_capath) {
278 efree(ssl_capath);
279 }
280
281 if (ssl_cipher) {
282 efree(ssl_cipher);
283 }
284 }
285 if (mysql_real_connect(mysql->mysql, hostname, username, passwd, dbname, port, socket, flags) == NULL)
286 #else
287 if (ssl) {
288 /* if we're here, this means previous conn was ssl, repopulate settings */
289 mysql_ssl_set(mysql->mysql, ssl_key, ssl_cert, ssl_ca, ssl_capath, ssl_cipher);
290
291 if (ssl_key) {
292 efree(ssl_key);
293 }
294
295 if (ssl_cert) {
296 efree(ssl_cert);
297 }
298
299 if (ssl_ca) {
300 efree(ssl_ca);
301 }
302
303 if (ssl_capath) {
304 efree(ssl_capath);
305 }
306
307 if (ssl_cipher) {
308 efree(ssl_cipher);
309 }
310 }
311 if (mysqlnd_connect(mysql->mysql, hostname, username, passwd, passwd_len, dbname, dbname_len,
312 port, socket, flags, MYSQLND_CLIENT_KNOWS_RSET_COPY_DATA) == NULL)
313 #endif
314 {
315 /* Save error messages - for mysqli_connect_error() & mysqli_connect_errno() */
316 php_mysqli_set_error(mysql_errno(mysql->mysql), (char *) mysql_error(mysql->mysql));
317 php_mysqli_throw_sql_exception((char *)mysql_sqlstate(mysql->mysql), mysql_errno(mysql->mysql),
318 "%s", mysql_error(mysql->mysql));
319 if (!is_real_connect) {
320 /* free mysql structure */
321 mysqli_close(mysql->mysql, MYSQLI_CLOSE_DISCONNECTED);
322 mysql->mysql = NULL;
323 }
324 goto err;
325 }
326
327 /* clear error */
328 php_mysqli_set_error(mysql_errno(mysql->mysql), (char *) mysql_error(mysql->mysql));
329
330 #ifndef MYSQLI_USE_MYSQLND
331 char reconnect = MyG(reconnect);
332 mysql_options(mysql->mysql, MYSQL_OPT_RECONNECT, (char *)&reconnect);
333 #endif
334 unsigned int allow_local_infile = MyG(allow_local_infile);
335 mysql_options(mysql->mysql, MYSQL_OPT_LOCAL_INFILE, (char *)&allow_local_infile);
336
337 end:
338 if (!mysqli_resource) {
339 mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
340 mysqli_resource->ptr = (void *)mysql;
341 }
342 mysqli_resource->status = MYSQLI_STATUS_VALID;
343
344 /* store persistent connection */
345 if (persistent && (new_connection || is_real_connect)) {
346 MyG(num_active_persistent)++;
347 }
348
349 MyG(num_links)++;
350
351 mysql->multi_query = 0;
352
353 if (!object || !instanceof_function(Z_OBJCE_P(object), mysqli_link_class_entry)) {
354 MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_link_class_entry);
355 } else {
356 (Z_MYSQLI_P(object))->ptr = mysqli_resource;
357 }
358 if (!is_real_connect) {
359 return;
360 } else {
361 RETURN_TRUE;
362 }
363
364 err:
365 if (mysql->hash_key) {
366 zend_string_release_ex(mysql->hash_key, 0);
367 mysql->hash_key = NULL;
368 mysql->persistent = FALSE;
369 }
370 if (!is_real_connect && self_alloced) {
371 efree(mysql);
372 }
373 RETVAL_FALSE;
374 } /* }}} */
375
376 /* {{{ Open a connection to a mysql server */
377 PHP_FUNCTION(mysqli_connect)
378 {
379 mysqli_common_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, FALSE, FALSE);
380 }
381 /* }}} */
382
383 PHP_METHOD(mysqli, __construct)
384 {
385 mysqli_common_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, FALSE, TRUE);
386 }
387
388 /* {{{ Initialize mysqli and return a resource for use with mysql_real_connect */
389 PHP_METHOD(mysqli, init)
390 {
391 php_mysqli_init(INTERNAL_FUNCTION_PARAM_PASSTHRU, TRUE);
392 }
393 /* }}} */
394
395 /* {{{ Returns the numerical value of the error message from last connect command */
396 PHP_FUNCTION(mysqli_connect_errno)
397 {
398 if (zend_parse_parameters_none() == FAILURE) {
399 RETURN_THROWS();
400 }
401
402 RETURN_LONG(MyG(error_no));
403 }
404 /* }}} */
405
406 /* {{{ Returns the text of the error message from previous MySQL operation */
407 PHP_FUNCTION(mysqli_connect_error)
408 {
409 if (zend_parse_parameters_none() == FAILURE) {
410 RETURN_THROWS();
411 }
412
413 if (MyG(error_msg)) {
414 RETURN_STRING(MyG(error_msg));
415 } else {
416 RETURN_NULL();
417 }
418 }
419 /* }}} */
420
421 /* {{{ Fetch a result row as an associative array, a numeric array, or both */
422 PHP_FUNCTION(mysqli_fetch_array)
423 {
424 php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0);
425 }
426 /* }}} */
427
428 /* {{{ Fetch a result row as an associative array */
429 PHP_FUNCTION(mysqli_fetch_assoc)
430 {
431 php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQLI_ASSOC, 0);
432 }
433 /* }}} */
434
435 /* {{{ Fetches all result rows as an associative array, a numeric array, or both */
436 #ifdef MYSQLI_USE_MYSQLND
437 PHP_FUNCTION(mysqli_fetch_all)
438 {
439 MYSQL_RES *result;
440 zval *mysql_result;
441 zend_long mode = MYSQLND_FETCH_NUM;
442
443 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|l", &mysql_result, mysqli_result_class_entry, &mode) == FAILURE) {
444 RETURN_THROWS();
445 }
446 MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
447
448 if (!mode || (mode & ~MYSQLND_FETCH_BOTH)) {
449 zend_argument_value_error(ERROR_ARG_POS(2), "must be one of MYSQLI_FETCH_NUM, "
450 "MYSQLI_FETCH_ASSOC, or MYSQLI_FETCH_BOTH");
451 RETURN_THROWS();
452 }
453
454 mysqlnd_fetch_all(result, mode, return_value);
455 }
456 /* }}} */
457
458 /* {{{ Returns statistics about the zval cache */
459 PHP_FUNCTION(mysqli_get_client_stats)
460 {
461 if (zend_parse_parameters_none() == FAILURE) {
462 RETURN_THROWS();
463 }
464 mysqlnd_get_client_stats(return_value);
465 }
466 /* }}} */
467
468 /* {{{ Returns statistics about the zval cache */
469 PHP_FUNCTION(mysqli_get_connection_stats)
470 {
471 MY_MYSQL *mysql;
472 zval *mysql_link;
473
474 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
475 &mysql_link, mysqli_link_class_entry) == FAILURE) {
476 RETURN_THROWS();
477 }
478 MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
479
480 mysqlnd_get_connection_stats(mysql->mysql, return_value);
481 }
482 #endif
483 /* }}} */
484
485 /* {{{ Fetches all client errors */
486 PHP_FUNCTION(mysqli_error_list)
487 {
488 MY_MYSQL *mysql;
489 zval *mysql_link;
490
491 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
492 RETURN_THROWS();
493 }
494 MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
495 #ifdef MYSQLI_USE_MYSQLND
496 if (1) {
497 MYSQLND_ERROR_LIST_ELEMENT * message;
498 zend_llist_position pos;
499 array_init(return_value);
500 for (message = (MYSQLND_ERROR_LIST_ELEMENT *) zend_llist_get_first_ex(&mysql->mysql->data->error_info->error_list, &pos);
501 message;
502 message = (MYSQLND_ERROR_LIST_ELEMENT *) zend_llist_get_next_ex(&mysql->mysql->data->error_info->error_list, &pos))
503 {
504 zval single_error;
505 array_init(&single_error);
506 add_assoc_long_ex(&single_error, "errno", sizeof("errno") - 1, message->error_no);
507 add_assoc_string_ex(&single_error, "sqlstate", sizeof("sqlstate") - 1, message->sqlstate);
508 add_assoc_string_ex(&single_error, "error", sizeof("error") - 1, message->error);
509 add_next_index_zval(return_value, &single_error);
510 }
511 } else {
512 RETURN_EMPTY_ARRAY();
513 }
514 #else
515 if (mysql_errno(mysql->mysql)) {
516 zval single_error;
517 array_init(return_value);
518 array_init(&single_error);
519 add_assoc_long_ex(&single_error, "errno", sizeof("errno") - 1, mysql_errno(mysql->mysql));
520 add_assoc_string_ex(&single_error, "sqlstate", sizeof("sqlstate") - 1, mysql_sqlstate(mysql->mysql));
521 add_assoc_string_ex(&single_error, "error", sizeof("error") - 1, mysql_error(mysql->mysql));
522 add_next_index_zval(return_value, &single_error);
523 } else {
524 RETURN_EMPTY_ARRAY();
525 }
526 #endif
527 }
528 /* }}} */
529
530 /* {{{ */
531 PHP_FUNCTION(mysqli_stmt_error_list)
532 {
533 MY_STMT *stmt;
534 zval *mysql_stmt;
535
536 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
537 RETURN_THROWS();
538 }
539 MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_INITIALIZED);
540 #ifdef MYSQLI_USE_MYSQLND
541 if (stmt->stmt && stmt->stmt->data && stmt->stmt->data->error_info) {
542 MYSQLND_ERROR_LIST_ELEMENT * message;
543 zend_llist_position pos;
544 array_init(return_value);
545 for (message = (MYSQLND_ERROR_LIST_ELEMENT *) zend_llist_get_first_ex(&stmt->stmt->data->error_info->error_list, &pos);
546 message;
547 message = (MYSQLND_ERROR_LIST_ELEMENT *) zend_llist_get_next_ex(&stmt->stmt->data->error_info->error_list, &pos))
548 {
549 zval single_error;
550 array_init(&single_error);
551 add_assoc_long_ex(&single_error, "errno", sizeof("errno") - 1, message->error_no);
552 add_assoc_string_ex(&single_error, "sqlstate", sizeof("sqlstate") - 1, message->sqlstate);
553 add_assoc_string_ex(&single_error, "error", sizeof("error") - 1, message->error);
554 add_next_index_zval(return_value, &single_error);
555 }
556 } else {
557 RETURN_EMPTY_ARRAY();
558 }
559 #else
560 if (mysql_stmt_errno(stmt->stmt)) {
561 zval single_error;
562 array_init(return_value);
563 array_init(&single_error);
564 add_assoc_long_ex(&single_error, "errno", sizeof("errno") - 1, mysql_stmt_errno(stmt->stmt));
565 add_assoc_string_ex(&single_error, "sqlstate", sizeof("sqlstate") - 1, mysql_stmt_sqlstate(stmt->stmt));
566 add_assoc_string_ex(&single_error, "error", sizeof("error") - 1, mysql_stmt_error(stmt->stmt));
567 add_next_index_zval(return_value, &single_error);
568 } else {
569 RETURN_EMPTY_ARRAY();
570 }
571 #endif
572 }
573 /* }}} */
574
575 /* {{{ Fetch a result row as an object */
576 PHP_FUNCTION(mysqli_fetch_object)
577 {
578 php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQLI_ASSOC, 1);
579 }
580 /* }}} */
581
582 /* {{{ allows to execute multiple queries */
583 PHP_FUNCTION(mysqli_multi_query)
584 {
585 MY_MYSQL *mysql;
586 zval *mysql_link;
587 char *query = NULL;
588 size_t query_len;
589
590 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_link, mysqli_link_class_entry, &query, &query_len) == FAILURE) {
591 RETURN_THROWS();
592 }
593 MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
594
595 MYSQLI_ENABLE_MQ;
596 if (mysql_real_query(mysql->mysql, query, query_len)) {
597 #ifndef MYSQLI_USE_MYSQLND
598 char s_error[MYSQL_ERRMSG_SIZE], s_sqlstate[SQLSTATE_LENGTH+1];
599 unsigned int s_errno;
600 /* we have to save error information, cause
601 MYSQLI_DISABLE_MQ will reset error information */
602 strcpy(s_error, mysql_error(mysql->mysql));
603 strcpy(s_sqlstate, mysql_sqlstate(mysql->mysql));
604 s_errno = mysql_errno(mysql->mysql);
605 #else
606 MYSQLND_ERROR_INFO error_info = *mysql->mysql->data->error_info;
607 mysql->mysql->data->error_info->error_list.head = NULL;
608 mysql->mysql->data->error_info->error_list.tail = NULL;
609 mysql->mysql->data->error_info->error_list.count = 0;
610 #endif
611 MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
612 MYSQLI_DISABLE_MQ;
613
614 #ifndef MYSQLI_USE_MYSQLND
615 /* restore error information */
616 strcpy(mysql->mysql->net.last_error, s_error);
617 strcpy(mysql->mysql->net.sqlstate, s_sqlstate);
618 mysql->mysql->net.last_errno = s_errno;
619 #else
620 zend_llist_clean(&mysql->mysql->data->error_info->error_list);
621 *mysql->mysql->data->error_info = error_info;
622 #endif
623 RETURN_FALSE;
624 }
625 RETURN_TRUE;
626 }
627 /* }}} */
628
629 /* {{{ */
630 PHP_FUNCTION(mysqli_query)
631 {
632 MY_MYSQL *mysql;
633 zval *mysql_link;
634 MYSQLI_RESOURCE *mysqli_resource;
635 MYSQL_RES *result = NULL;
636 char *query = NULL;
637 size_t query_len;
638 zend_long resultmode = MYSQLI_STORE_RESULT;
639
640 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os|l", &mysql_link, mysqli_link_class_entry, &query, &query_len, &resultmode) == FAILURE) {
641 RETURN_THROWS();
642 }
643
644 if (!query_len) {
645 zend_argument_value_error(ERROR_ARG_POS(2), "cannot be empty");
646 RETURN_THROWS();
647 }
648 if ((resultmode & ~MYSQLI_ASYNC) != MYSQLI_USE_RESULT &&
649 MYSQLI_STORE_RESULT != (resultmode & ~(MYSQLI_ASYNC | MYSQLI_STORE_RESULT_COPY_DATA))
650 ) {
651 zend_argument_value_error(ERROR_ARG_POS(3), "must be either MYSQLI_USE_RESULT or MYSQLI_STORE_RESULT"
652 #ifdef MYSQLI_USE_MYSQLND
653 " with MYSQLI_ASYNC as an optional bitmask flag"
654 #endif
655 );
656 RETURN_THROWS();
657 }
658
659 MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
660
661 MYSQLI_DISABLE_MQ;
662
663
664 #ifdef MYSQLI_USE_MYSQLND
665 if (resultmode & MYSQLI_ASYNC) {
666 if (mysqli_async_query(mysql->mysql, query, query_len)) {
667 MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
668 RETURN_FALSE;
669 }
670 mysql->async_result_fetch_type = resultmode & ~MYSQLI_ASYNC;
671 RETURN_TRUE;
672 }
673 #endif
674
675 if (mysql_real_query(mysql->mysql, query, query_len)) {
676 MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
677 RETURN_FALSE;
678 }
679
680 if (!mysql_field_count(mysql->mysql)) {
681 /* no result set - not a SELECT */
682 if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
683 php_mysqli_report_index(query, mysqli_server_status(mysql->mysql));
684 }
685 RETURN_TRUE;
686 }
687
688 #ifdef MYSQLI_USE_MYSQLND
689 switch (resultmode & ~(MYSQLI_ASYNC | MYSQLI_STORE_RESULT_COPY_DATA)) {
690 #else
691 switch (resultmode & ~MYSQLI_ASYNC) {
692 #endif
693 case MYSQLI_STORE_RESULT:
694 #ifdef MYSQLI_USE_MYSQLND
695 if (resultmode & MYSQLI_STORE_RESULT_COPY_DATA) {
696 result = mysqlnd_store_result_ofs(mysql->mysql);
697 } else
698 #endif
699 result = mysql_store_result(mysql->mysql);
700 break;
701 case MYSQLI_USE_RESULT:
702 result = mysql_use_result(mysql->mysql);
703 break;
704 }
705 if (!result) {
706 php_mysqli_throw_sql_exception((char *)mysql_sqlstate(mysql->mysql), mysql_errno(mysql->mysql),
707 "%s", mysql_error(mysql->mysql));
708 RETURN_FALSE;
709 }
710
711 if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
712 php_mysqli_report_index(query, mysqli_server_status(mysql->mysql));
713 }
714
715 mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
716 mysqli_resource->ptr = (void *)result;
717 mysqli_resource->status = MYSQLI_STATUS_VALID;
718 MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_result_class_entry);
719 }
720 /* }}} */
721
722 #ifdef MYSQLI_USE_MYSQLND
723 #include "php_network.h"
724 /* {{{ mysqlnd_zval_array_to_mysqlnd_array functions */
725 static int mysqlnd_zval_array_to_mysqlnd_array(zval *in_array, MYSQLND ***out_array)
726 {
727 zval *elem;
728 int i = 0, current = 0;
729
730 if (Z_TYPE_P(in_array) != IS_ARRAY) {
731 return SUCCESS;
732 }
733 *out_array = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(in_array)) + 1, sizeof(MYSQLND *));
734 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(in_array), elem) {
735 i++;
736 if (Z_TYPE_P(elem) != IS_OBJECT ||
737 !instanceof_function(Z_OBJCE_P(elem), mysqli_link_class_entry)) {
738 zend_argument_type_error(i, "must be an instance of mysqli, %s given", zend_zval_type_name(elem));
739 return FAILURE;
740 } else {
741 MY_MYSQL *mysql;
742 MYSQLI_RESOURCE *my_res;
743 mysqli_object *intern = Z_MYSQLI_P(elem);
744 if (!(my_res = (MYSQLI_RESOURCE *)intern->ptr)) {
745 zend_throw_error(NULL, "%s object is already closed", ZSTR_VAL(intern->zo.ce->name));
746 return FAILURE;
747 }
748 mysql = (MY_MYSQL*) my_res->ptr;
749 if (my_res->status < MYSQLI_STATUS_VALID) {
750 zend_throw_error(NULL, "%s object is not fully initialized", ZSTR_VAL(intern->zo.ce->name));
751 return FAILURE;
752 }
753 (*out_array)[current++] = mysql->mysql;
754 }
755 } ZEND_HASH_FOREACH_END();
756 return SUCCESS;
757 }
758 /* }}} */
759
760 /* {{{ mysqlnd_zval_array_from_mysqlnd_array */
761 static int mysqlnd_zval_array_from_mysqlnd_array(MYSQLND **in_array, zval *out_array)
762 {
763 MYSQLND **p = in_array;
764 zval dest_array;
765 zval *elem, *dest_elem;
766 int ret = 0;
767
768 array_init_size(&dest_array, zend_hash_num_elements(Z_ARRVAL_P(out_array)));
769
770 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(out_array), elem) {
771 if (Z_TYPE_P(elem) != IS_OBJECT ||
772 !instanceof_function(Z_OBJCE_P(elem), mysqli_link_class_entry)) {
773 continue;
774 }
775 {
776 MY_MYSQL *mysql;
777 MYSQLI_RESOURCE *my_res;
778 mysqli_object *intern = Z_MYSQLI_P(elem);
779 if (!(my_res = (MYSQLI_RESOURCE *)intern->ptr)) {
780 zend_throw_error(NULL, "%s object is already closed", ZSTR_VAL(intern->zo.ce->name));
781 return FAILURE;
782 }
783 mysql = (MY_MYSQL *) my_res->ptr;
784 if (mysql->mysql == *p) {
785 dest_elem = zend_hash_next_index_insert(Z_ARRVAL(dest_array), elem);
786 if (dest_elem) {
787 zval_add_ref(dest_elem);
788 }
789 ret++;
790 p++;
791 }
792 }
793 } ZEND_HASH_FOREACH_END();
794
795 /* destroy old array and add new one */
796 zval_ptr_dtor(out_array);
797 ZVAL_COPY_VALUE(out_array, &dest_array);
798
799 return 0;
800 }
801 /* }}} */
802
803 /* {{{ mysqlnd_dont_poll_zval_array_from_mysqlnd_array */
804 static int mysqlnd_dont_poll_zval_array_from_mysqlnd_array(MYSQLND **in_array, zval *in_zval_array, zval *out_array)
805 {
806 MYSQLND **p = in_array;
807 zval proxy, *elem, *dest_elem;
808 int ret = 0;
809
810 array_init(&proxy);
811 if (in_array) {
812 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(in_zval_array), elem) {
813 MY_MYSQL *mysql;
814 mysqli_object *intern = Z_MYSQLI_P(elem);
815 mysql = (MY_MYSQL *)((MYSQLI_RESOURCE *)intern->ptr)->ptr;
816 if (mysql->mysql == *p) {
817 dest_elem = zend_hash_next_index_insert(Z_ARRVAL(proxy), elem);
818 if (dest_elem) {
819 zval_add_ref(dest_elem);
820 }
821 ret++;
822 p++;
823 }
824 } ZEND_HASH_FOREACH_END();
825 }
826
827 /* destroy old array and add new one */
828 zval_ptr_dtor(out_array);
829 ZVAL_COPY_VALUE(out_array, &proxy);
830
831 return 0;
832 }
833 /* }}} */
834
835 /* {{{ Poll connections */
836 PHP_FUNCTION(mysqli_poll)
837 {
838 zval *r_array, *e_array, *dont_poll_array;
839 MYSQLND **new_r_array = NULL, **new_e_array = NULL, **new_dont_poll_array = NULL;
840 zend_long sec = 0, usec = 0;
841 enum_func_status ret;
842 int desc_num;
843
844 if (zend_parse_parameters(ZEND_NUM_ARGS(), "a!a!al|l", &r_array, &e_array, &dont_poll_array, &sec, &usec) == FAILURE) {
845 RETURN_THROWS();
846 }
847 if (sec < 0) {
848 zend_argument_value_error(4, "must be greater than or equal to 0");
849 RETURN_THROWS();
850 }
851 if (usec < 0) {
852 zend_argument_value_error(5, "must be greater than or equal to 0");
853 RETURN_THROWS();
854 }
855
856 // TODO Error promotion
857 if (!r_array && !e_array) {
858 php_error_docref(NULL, E_WARNING, "No stream arrays were passed");
859 RETURN_FALSE;
860 }
861
862 if (r_array != NULL) {
863 if (mysqlnd_zval_array_to_mysqlnd_array(r_array, &new_r_array) == FAILURE) {
864 efree(new_r_array);
865 RETURN_THROWS();
866 }
867 }
868 if (e_array != NULL) {
869 if (mysqlnd_zval_array_to_mysqlnd_array(e_array, &new_e_array) == FAILURE) {
870 efree(new_e_array);
871 efree(new_r_array);
872 RETURN_THROWS();
873 }
874 }
875
876 ret = mysqlnd_poll(new_r_array, new_e_array, &new_dont_poll_array, sec, usec, &desc_num);
877
878 mysqlnd_dont_poll_zval_array_from_mysqlnd_array(r_array != NULL ? new_dont_poll_array:NULL, r_array, dont_poll_array);
879
880 if (r_array != NULL) {
881 mysqlnd_zval_array_from_mysqlnd_array(new_r_array, r_array);
882 }
883 if (e_array != NULL) {
884 mysqlnd_zval_array_from_mysqlnd_array(new_e_array, e_array);
885 }
886
887 if (new_dont_poll_array) {
888 efree(new_dont_poll_array);
889 }
890 if (new_r_array) {
891 efree(new_r_array);
892 }
893 if (new_e_array) {
894 efree(new_e_array);
895 }
896 if (ret == PASS) {
897 RETURN_LONG(desc_num);
898 } else {
899 RETURN_FALSE;
900 }
901 }
902 /* }}} */
903
904 /* {{{ Poll connections */
905 PHP_FUNCTION(mysqli_reap_async_query)
906 {
907 MY_MYSQL *mysql;
908 zval *mysql_link;
909 MYSQLI_RESOURCE *mysqli_resource;
910 MYSQL_RES *result = NULL;
911
912 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
913 RETURN_THROWS();
914 }
915
916 MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
917
918 if (FAIL == mysqlnd_reap_async_query(mysql->mysql)) {
919 RETURN_FALSE;
920 }
921
922 if (!mysql_field_count(mysql->mysql)) {
923 /* no result set - not a SELECT */
924 if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
925 /* php_mysqli_report_index("n/a", mysqli_server_status(mysql->mysql)); */
926 }
927 RETURN_TRUE;
928 }
929
930 switch (mysql->async_result_fetch_type) {
931 case MYSQLI_STORE_RESULT:
932 result = mysql_store_result(mysql->mysql);
933 break;
934 case MYSQLI_USE_RESULT:
935 result = mysql_use_result(mysql->mysql);
936 break;
937 }
938
939 if (!result) {
940 php_mysqli_throw_sql_exception((char *)mysql_sqlstate(mysql->mysql), mysql_errno(mysql->mysql),
941 "%s", mysql_error(mysql->mysql));
942 RETURN_FALSE;
943 }
944
945 if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
946 /* php_mysqli_report_index("n/a", mysqli_server_status(mysql->mysql)); */
947 }
948
949 mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
950 mysqli_resource->ptr = (void *)result;
951 mysqli_resource->status = MYSQLI_STATUS_VALID;
952 MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_result_class_entry);
953 }
954 /* }}} */
955
956 /* {{{ Buffer result set on client */
957 PHP_FUNCTION(mysqli_stmt_get_result)
958 {
959 MYSQL_RES *result;
960 MYSQLI_RESOURCE *mysqli_resource;
961 MY_STMT *stmt;
962 zval *mysql_stmt;
963
964 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
965 RETURN_THROWS();
966 }
967 MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
968
969 if (!(result = mysqlnd_stmt_get_result(stmt->stmt))) {
970 MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
971 RETURN_FALSE;
972 }
973
974 mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
975 mysqli_resource->ptr = (void *)result;
976 mysqli_resource->status = MYSQLI_STATUS_VALID;
977 MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_result_class_entry);
978 }
979 /* }}} */
980 #endif
981
982 /* {{{ */
983 PHP_FUNCTION(mysqli_get_warnings)
984 {
985 MY_MYSQL *mysql;
986 zval *mysql_link;
987 MYSQLI_RESOURCE *mysqli_resource;
988 MYSQLI_WARNING *w = NULL;
989
990 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
991 RETURN_THROWS();
992 }
993 MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
994
995 if (mysql_warning_count(mysql->mysql)) {
996 #ifdef MYSQLI_USE_MYSQLND
997 w = php_get_warnings(mysql->mysql->data);
998 #else
999 w = php_get_warnings(mysql->mysql);
1000 #endif
1001 }
1002 if (!w) {
1003 RETURN_FALSE;
1004 }
1005 mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
1006 mysqli_resource->ptr = mysqli_resource->info = (void *)w;
1007 mysqli_resource->status = MYSQLI_STATUS_VALID;
1008 MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_warning_class_entry);
1009 }
1010 /* }}} */
1011
1012 /* {{{ */
1013 PHP_FUNCTION(mysqli_stmt_get_warnings)
1014 {
1015 MY_STMT *stmt;
1016 zval *stmt_link;
1017 MYSQLI_RESOURCE *mysqli_resource;
1018 MYSQLI_WARNING *w = NULL;
1019
1020 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &stmt_link, mysqli_stmt_class_entry) == FAILURE) {
1021 RETURN_THROWS();
1022 }
1023 MYSQLI_FETCH_RESOURCE_STMT(stmt, stmt_link, MYSQLI_STATUS_VALID);
1024
1025 if (mysqli_stmt_warning_count(stmt->stmt)) {
1026 w = php_get_warnings(mysqli_stmt_get_connection(stmt->stmt));
1027 }
1028 if (!w) {
1029 RETURN_FALSE;
1030 }
1031 mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
1032 mysqli_resource->ptr = mysqli_resource->info = (void *)w;
1033 mysqli_resource->status = MYSQLI_STATUS_VALID;
1034 MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_warning_class_entry);
1035 }
1036 /* }}} */
1037
1038 /* {{{ sets client character set */
1039 PHP_FUNCTION(mysqli_set_charset)
1040 {
1041 MY_MYSQL *mysql;
1042 zval *mysql_link;
1043 char *cs_name;
1044 size_t csname_len;
1045
1046 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_link, mysqli_link_class_entry, &cs_name, &csname_len) == FAILURE) {
1047 RETURN_THROWS();
1048 }
1049 MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1050
1051 if (mysql_set_character_set(mysql->mysql, cs_name)) {
1052 MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
1053 RETURN_FALSE;
1054 }
1055 RETURN_TRUE;
1056 }
1057 /* }}} */
1058
1059 /* {{{ returns a character set object */
1060 PHP_FUNCTION(mysqli_get_charset)
1061 {
1062 MY_MYSQL *mysql;
1063 zval *mysql_link;
1064 const char *name = NULL, *collation = NULL, *dir = NULL, *comment = NULL;
1065 uint32_t minlength, maxlength, number, state;
1066 #ifndef MYSQLI_USE_MYSQLND
1067 MY_CHARSET_INFO cs;
1068 #else
1069 const MYSQLND_CHARSET *cs;
1070 #endif
1071
1072 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1073 RETURN_THROWS();
1074 }
1075 MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1076
1077
1078 #ifndef MYSQLI_USE_MYSQLND
1079 mysql_get_character_set_info(mysql->mysql, &cs);
1080 name = (char *)cs.csname;
1081 collation = (char *)cs.name;
1082 dir = (char *)cs.dir;
1083 minlength = cs.mbminlen;
1084 maxlength = cs.mbmaxlen;
1085 number = cs.number;
1086 state = cs.state;
1087 comment = cs.comment;
1088 #else
1089 cs = mysql->mysql->data->charset;
1090 if (!cs) {
1091 php_error_docref(NULL, E_WARNING, "The connection has no charset associated");
1092 RETURN_NULL();
1093 }
1094 name = cs->name;
1095 collation = cs->collation;
1096 minlength = cs->char_minlen;
1097 maxlength = cs->char_maxlen;
1098 number = cs->nr;
1099 comment = cs->comment;
1100 state = 1; /* all charsets are compiled in */
1101 #endif
1102 object_init(return_value);
1103
1104 add_property_string(return_value, "charset", (name) ? (char *)name : "");
1105 add_property_string(return_value, "collation",(collation) ? (char *)collation : "");
1106 add_property_string(return_value, "dir", (dir) ? (char *)dir : "");
1107 add_property_long(return_value, "min_length", minlength);
1108 add_property_long(return_value, "max_length", maxlength);
1109 add_property_long(return_value, "number", number);
1110 add_property_long(return_value, "state", state);
1111 add_property_string(return_value, "comment", (comment) ? (char *)comment : "");
1112 }
1113 /* }}} */
1114
1115 #ifndef MYSQLI_USE_MYSQLND
1116 extern char * mysqli_escape_string_for_tx_name_in_comment(const char * const name);
1117
1118 /* {{{ */
1119 static int mysqli_begin_transaction_libmysql(MYSQL * conn, const unsigned int mode, const char * const name)
1120 {
1121 int ret;
1122 smart_str tmp_str = {0};
1123 char * name_esc;
1124 char * query;
1125 unsigned int query_len;
1126 if (mode & TRANS_START_WITH_CONSISTENT_SNAPSHOT) {
1127 if (tmp_str.s) {
1128 smart_str_appendl(&tmp_str, ", ", sizeof(", ") - 1);
1129 }
1130 smart_str_appendl(&tmp_str, "WITH CONSISTENT SNAPSHOT", sizeof("WITH CONSISTENT SNAPSHOT") - 1);
1131 }
1132 if (mode & TRANS_START_READ_WRITE) {
1133 if (tmp_str.s) {
1134 smart_str_appendl(&tmp_str, ", ", sizeof(", ") - 1);
1135 }
1136 smart_str_appendl(&tmp_str, "READ WRITE", sizeof("READ WRITE") - 1);
1137 } else if (mode & TRANS_START_READ_ONLY) {
1138 if (tmp_str.s) {
1139 smart_str_appendl(&tmp_str, ", ", sizeof(", ") - 1);
1140 }
1141 smart_str_appendl(&tmp_str, "READ ONLY", sizeof("READ ONLY") - 1);
1142 }
1143 smart_str_0(&tmp_str);
1144
1145 name_esc = mysqli_escape_string_for_tx_name_in_comment(name);
1146 query_len = spprintf(&query, 0, "START TRANSACTION%s %s",
1147 name_esc? name_esc:"", tmp_str.s? ZSTR_VAL(tmp_str.s):"");
1148
1149 smart_str_free(&tmp_str);
1150 if (name_esc) {
1151 efree(name_esc);
1152 }
1153
1154 ret = mysql_real_query(conn, query, query_len);
1155 efree(query);
1156
1157 if (ret && mode & (TRANS_START_READ_WRITE | TRANS_START_READ_ONLY) && mysql_errno(conn) == 1064) {
1158 php_error_docref(NULL, E_WARNING, "This server version doesn't support 'READ WRITE' and 'READ ONLY'. Minimum 5.6.5 is required");
1159 }
1160 return ret;
1161 }
1162 /* }}} */
1163 #endif
1164
1165 /* {{{ Starts a transaction */
1166 PHP_FUNCTION(mysqli_begin_transaction)
1167 {
1168 MY_MYSQL *mysql;
1169 zval *mysql_link;
1170 zend_long flags = TRANS_START_NO_OPT;
1171 char * name = NULL;
1172 size_t name_len = 0;
1173
1174 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|ls!", &mysql_link, mysqli_link_class_entry, &flags, &name, &name_len) == FAILURE) {
1175 RETURN_THROWS();
1176 }
1177 MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1178 if (flags < 0) {
1179 zend_argument_value_error(ERROR_ARG_POS(2), "must be one of the MYSQLI_TRANS_* constants");
1180 RETURN_THROWS();
1181 }
1182 if (name && !name_len) {
1183 zend_argument_value_error(ERROR_ARG_POS(3), "cannot be empty");
1184 RETURN_THROWS();
1185 }
1186
1187 #ifndef MYSQLI_USE_MYSQLND
1188 if (mysqli_begin_transaction_libmysql(mysql->mysql, flags, name)) {
1189 RETURN_FALSE;
1190 }
1191 #else
1192 if (FAIL == mysqlnd_begin_transaction(mysql->mysql, flags, name)) {
1193 RETURN_FALSE;
1194 }
1195 #endif
1196 RETURN_TRUE;
1197 }
1198 /* }}} */
1199
1200 #ifndef MYSQLI_USE_MYSQLND
1201 /* {{{ */
1202 static int mysqli_savepoint_libmysql(MYSQL * conn, const char * const name, zend_bool release)
1203 {
1204 int ret;
1205 char * query;
1206 unsigned int query_len = spprintf(&query, 0, release? "RELEASE SAVEPOINT `%s`":"SAVEPOINT `%s`", name);
1207 ret = mysql_real_query(conn, query, query_len);
1208 efree(query);
1209 return ret;
1210 }
1211 /* }}} */
1212 #endif
1213
1214 /* {{{ Starts a transaction */
1215 PHP_FUNCTION(mysqli_savepoint)
1216 {
1217 MY_MYSQL *mysql;
1218 zval *mysql_link;
1219 char * name = NULL;
1220 size_t name_len;
1221
1222 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_link, mysqli_link_class_entry, &name, &name_len) == FAILURE) {
1223 RETURN_THROWS();
1224 }
1225 MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1226 if (name_len == 0) {
1227 zend_argument_value_error(ERROR_ARG_POS(2), "cannot be empty");
1228 RETURN_THROWS();
1229 }
1230
1231 #ifndef MYSQLI_USE_MYSQLND
1232 if (mysqli_savepoint_libmysql(mysql->mysql, name, FALSE)) {
1233 #else
1234 if (FAIL == mysqlnd_savepoint(mysql->mysql, name)) {
1235 #endif
1236 RETURN_FALSE;
1237 }
1238 RETURN_TRUE;
1239 }
1240 /* }}} */
1241
1242 /* {{{ Starts a transaction */
1243 PHP_FUNCTION(mysqli_release_savepoint)
1244 {
1245 MY_MYSQL *mysql;
1246 zval *mysql_link;
1247 char * name = NULL;
1248 size_t name_len;
1249
1250 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_link, mysqli_link_class_entry, &name, &name_len) == FAILURE) {
1251 RETURN_THROWS();
1252 }
1253 MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1254 if (name_len == 0) {
1255 zend_argument_value_error(ERROR_ARG_POS(2), "cannot be empty");
1256 RETURN_THROWS();
1257 }
1258 #ifndef MYSQLI_USE_MYSQLND
1259 if (mysqli_savepoint_libmysql(mysql->mysql, name, TRUE)) {
1260 #else
1261 if (FAIL == mysqlnd_release_savepoint(mysql->mysql, name)) {
1262 #endif
1263 RETURN_FALSE;
1264 }
1265 RETURN_TRUE;
1266 }
1267 /* }}} */
1268
1269 /* {{{ Returns information about open and cached links */
1270 PHP_FUNCTION(mysqli_get_links_stats)
1271 {
1272 if (zend_parse_parameters_none() == FAILURE) {
1273 RETURN_THROWS();
1274 }
1275
1276 array_init(return_value);
1277 add_assoc_long_ex(return_value, "total", sizeof("total") - 1, MyG(num_links));
1278 add_assoc_long_ex(return_value, "active_plinks", sizeof("active_plinks") - 1, MyG(num_active_persistent));
1279 add_assoc_long_ex(return_value, "cached_plinks", sizeof("cached_plinks") - 1, MyG(num_inactive_persistent));
1280 }
1281 /* }}} */
1282