1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Georg Richter <georg@php.net> |
16 | Andrey Hristov <andrey@php.net> |
17 | Ulf Wendel <uw@php.net> |
18 +----------------------------------------------------------------------+
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <signal.h>
26
27 #include "php.h"
28 #include "php_ini.h"
29 #include "ext/standard/info.h"
30 #include "zend_smart_str.h"
31 #include "php_mysqli_structs.h"
32 #include "mysqli_priv.h"
33
34 #define SAFE_STR(a) ((a)?a:"")
35
36 /* {{{ php_mysqli_set_error
37 */
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;
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;
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 #if !defined(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 #if !defined(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 #if !defined(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 #if !defined(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 /* {{{ proto object mysqli_connect([string hostname [,string username [,string passwd [,string dbname [,int port [,string socket]]]]]])
377 Open a connection to a mysql server */
378 PHP_FUNCTION(mysqli_connect)
379 {
380 mysqli_common_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, FALSE, FALSE);
381 }
382 /* }}} */
383
384 /* {{{ proto object mysqli_link_construct()
385 */
386 PHP_FUNCTION(mysqli_link_construct)
387 {
388 mysqli_common_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, FALSE, TRUE);
389 }
390 /* }}} */
391
392 /* {{{ proto int mysqli_connect_errno(void)
393 Returns the numerical value of the error message from last connect command */
394 PHP_FUNCTION(mysqli_connect_errno)
395 {
396 RETURN_LONG(MyG(error_no));
397 }
398 /* }}} */
399
400 /* {{{ proto string mysqli_connect_error(void)
401 Returns the text of the error message from previous MySQL operation */
402 PHP_FUNCTION(mysqli_connect_error)
403 {
404 if (MyG(error_msg)) {
405 RETURN_STRING(MyG(error_msg));
406 } else {
407 RETURN_NULL();
408 }
409 }
410 /* }}} */
411
412 /* {{{ proto mixed mysqli_fetch_array(object result [,int resulttype])
413 Fetch a result row as an associative array, a numeric array, or both */
414 PHP_FUNCTION(mysqli_fetch_array)
415 {
416 php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0);
417 }
418 /* }}} */
419
420 /* {{{ proto mixed mysqli_fetch_assoc(object result)
421 Fetch a result row as an associative array */
422 PHP_FUNCTION(mysqli_fetch_assoc)
423 {
424 php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQLI_ASSOC, 0);
425 }
426 /* }}} */
427
428 /* {{{ proto mixed mysqli_fetch_all(object result [,int resulttype])
429 Fetches all result rows as an associative array, a numeric array, or both */
430 #if defined(MYSQLI_USE_MYSQLND)
431 PHP_FUNCTION(mysqli_fetch_all)
432 {
433 MYSQL_RES *result;
434 zval *mysql_result;
435 zend_long mode = MYSQLND_FETCH_NUM;
436
437 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|l", &mysql_result, mysqli_result_class_entry, &mode) == FAILURE) {
438 return;
439 }
440 MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
441
442 if (!mode || (mode & ~MYSQLND_FETCH_BOTH)) {
443 php_error_docref(NULL, E_WARNING, "Mode can be only MYSQLI_FETCH_NUM, "
444 "MYSQLI_FETCH_ASSOC or MYSQLI_FETCH_BOTH");
445 RETURN_FALSE;
446 }
447
448 mysqlnd_fetch_all(result, mode, return_value);
449 }
450 /* }}} */
451
452 /* {{{ proto array mysqli_get_client_stats(void)
453 Returns statistics about the zval cache */
454 PHP_FUNCTION(mysqli_get_client_stats)
455 {
456 if (zend_parse_parameters_none() == FAILURE) {
457 return;
458 }
459 mysqlnd_get_client_stats(return_value);
460 }
461 /* }}} */
462
463 /* {{{ proto array mysqli_get_connection_stats(void)
464 Returns statistics about the zval cache */
465 PHP_FUNCTION(mysqli_get_connection_stats)
466 {
467 MY_MYSQL *mysql;
468 zval *mysql_link;
469
470 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
471 &mysql_link, mysqli_link_class_entry) == FAILURE) {
472 return;
473 }
474 MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
475
476 mysqlnd_get_connection_stats(mysql->mysql, return_value);
477 }
478 #endif
479 /* }}} */
480
481 /* {{{ proto mixed mysqli_error_list(object connection)
482 Fetches all client errors */
483 PHP_FUNCTION(mysqli_error_list)
484 {
485 MY_MYSQL *mysql;
486 zval *mysql_link;
487
488 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
489 return;
490 }
491 MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
492 #if defined(MYSQLI_USE_MYSQLND)
493 if (1) {
494 MYSQLND_ERROR_LIST_ELEMENT * message;
495 zend_llist_position pos;
496 array_init(return_value);
497 for (message = (MYSQLND_ERROR_LIST_ELEMENT *) zend_llist_get_first_ex(&mysql->mysql->data->error_info->error_list, &pos);
498 message;
499 message = (MYSQLND_ERROR_LIST_ELEMENT *) zend_llist_get_next_ex(&mysql->mysql->data->error_info->error_list, &pos))
500 {
501 zval single_error;
502 array_init(&single_error);
503 add_assoc_long_ex(&single_error, "errno", sizeof("errno") - 1, message->error_no);
504 add_assoc_string_ex(&single_error, "sqlstate", sizeof("sqlstate") - 1, message->sqlstate);
505 add_assoc_string_ex(&single_error, "error", sizeof("error") - 1, message->error);
506 add_next_index_zval(return_value, &single_error);
507 }
508 } else {
509 RETURN_EMPTY_ARRAY();
510 }
511 #else
512 if (mysql_errno(mysql->mysql)) {
513 zval single_error;
514 array_init(return_value);
515 array_init(&single_error);
516 add_assoc_long_ex(&single_error, "errno", sizeof("errno") - 1, mysql_errno(mysql->mysql));
517 add_assoc_string_ex(&single_error, "sqlstate", sizeof("sqlstate") - 1, mysql_sqlstate(mysql->mysql));
518 add_assoc_string_ex(&single_error, "error", sizeof("error") - 1, mysql_error(mysql->mysql));
519 add_next_index_zval(return_value, &single_error);
520 } else {
521 RETURN_EMPTY_ARRAY();
522 }
523 #endif
524 }
525 /* }}} */
526
527 /* {{{ proto string mysqli_stmt_error_list(object stmt)
528 */
529 PHP_FUNCTION(mysqli_stmt_error_list)
530 {
531 MY_STMT *stmt;
532 zval *mysql_stmt;
533
534 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
535 return;
536 }
537 MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_INITIALIZED);
538 #if defined(MYSQLI_USE_MYSQLND)
539 if (stmt->stmt && stmt->stmt->data && stmt->stmt->data->error_info) {
540 MYSQLND_ERROR_LIST_ELEMENT * message;
541 zend_llist_position pos;
542 array_init(return_value);
543 for (message = (MYSQLND_ERROR_LIST_ELEMENT *) zend_llist_get_first_ex(&stmt->stmt->data->error_info->error_list, &pos);
544 message;
545 message = (MYSQLND_ERROR_LIST_ELEMENT *) zend_llist_get_next_ex(&stmt->stmt->data->error_info->error_list, &pos))
546 {
547 zval single_error;
548 array_init(&single_error);
549 add_assoc_long_ex(&single_error, "errno", sizeof("errno") - 1, message->error_no);
550 add_assoc_string_ex(&single_error, "sqlstate", sizeof("sqlstate") - 1, message->sqlstate);
551 add_assoc_string_ex(&single_error, "error", sizeof("error") - 1, message->error);
552 add_next_index_zval(return_value, &single_error);
553 }
554 } else {
555 RETURN_EMPTY_ARRAY();
556 }
557 #else
558 if (mysql_stmt_errno(stmt->stmt)) {
559 zval single_error;
560 array_init(return_value);
561 array_init(&single_error);
562 add_assoc_long_ex(&single_error, "errno", sizeof("errno") - 1, mysql_stmt_errno(stmt->stmt));
563 add_assoc_string_ex(&single_error, "sqlstate", sizeof("sqlstate") - 1, mysql_stmt_sqlstate(stmt->stmt));
564 add_assoc_string_ex(&single_error, "error", sizeof("error") - 1, mysql_stmt_error(stmt->stmt));
565 add_next_index_zval(return_value, &single_error);
566 } else {
567 RETURN_EMPTY_ARRAY();
568 }
569 #endif
570 }
571 /* }}} */
572
573 /* {{{ proto mixed mysqli_fetch_object(object result [, string class_name [, NULL|array ctor_params]])
574 Fetch a result row as an object */
575 PHP_FUNCTION(mysqli_fetch_object)
576 {
577 php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQLI_ASSOC, 1);
578 }
579 /* }}} */
580
581 /* {{{ proto bool mysqli_multi_query(object link, string query)
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;
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 /* {{{ proto mixed mysqli_query(object link, string query [,int resultmode]) */
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;
642 }
643
644 if (!query_len) {
645 php_error_docref(NULL, E_WARNING, "Empty query");
646 RETURN_FALSE;
647 }
648 #ifdef MYSQLI_USE_MYSQLND
649 if ((resultmode & ~MYSQLI_ASYNC) != MYSQLI_USE_RESULT && (resultmode & ~(MYSQLI_ASYNC | MYSQLI_STORE_RESULT_COPY_DATA)) != MYSQLI_STORE_RESULT) {
650 #else
651 if ((resultmode & ~MYSQLI_ASYNC) != MYSQLI_USE_RESULT && (resultmode & ~MYSQLI_ASYNC) != MYSQLI_STORE_RESULT) {
652 #endif
653 php_error_docref(NULL, E_WARNING, "Invalid value for resultmode");
654 RETURN_FALSE;
655 }
656
657 MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
658
659 MYSQLI_DISABLE_MQ;
660
661
662 #ifdef MYSQLI_USE_MYSQLND
663 if (resultmode & MYSQLI_ASYNC) {
664 if (mysqli_async_query(mysql->mysql, query, query_len)) {
665 MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
666 RETURN_FALSE;
667 }
668 mysql->async_result_fetch_type = resultmode & ~MYSQLI_ASYNC;
669 RETURN_TRUE;
670 }
671 #endif
672
673 if (mysql_real_query(mysql->mysql, query, query_len)) {
674 MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
675 RETURN_FALSE;
676 }
677
678 if (!mysql_field_count(mysql->mysql)) {
679 /* no result set - not a SELECT */
680 if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
681 php_mysqli_report_index(query, mysqli_server_status(mysql->mysql));
682 }
683 RETURN_TRUE;
684 }
685
686 #ifdef MYSQLI_USE_MYSQLND
687 switch (resultmode & ~(MYSQLI_ASYNC | MYSQLI_STORE_RESULT_COPY_DATA)) {
688 #else
689 switch (resultmode & ~MYSQLI_ASYNC) {
690 #endif
691 case MYSQLI_STORE_RESULT:
692 #ifdef MYSQLI_USE_MYSQLND
693 if (resultmode & MYSQLI_STORE_RESULT_COPY_DATA) {
694 result = mysqlnd_store_result_ofs(mysql->mysql);
695 } else
696 #endif
697 result = mysql_store_result(mysql->mysql);
698 break;
699 case MYSQLI_USE_RESULT:
700 result = mysql_use_result(mysql->mysql);
701 break;
702 }
703 if (!result) {
704 php_mysqli_throw_sql_exception((char *)mysql_sqlstate(mysql->mysql), mysql_errno(mysql->mysql),
705 "%s", mysql_error(mysql->mysql));
706 RETURN_FALSE;
707 }
708
709 if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
710 php_mysqli_report_index(query, mysqli_server_status(mysql->mysql));
711 }
712
713 mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
714 mysqli_resource->ptr = (void *)result;
715 mysqli_resource->status = MYSQLI_STATUS_VALID;
716 MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_result_class_entry);
717 }
718 /* }}} */
719
720 #if defined(MYSQLI_USE_MYSQLND)
721 #include "php_network.h"
722 /* {{{ mysqlnd_zval_array_to_mysqlnd_array functions */
723 static int mysqlnd_zval_array_to_mysqlnd_array(zval *in_array, MYSQLND ***out_array)
724 {
725 zval *elem;
726 int i = 0, current = 0;
727
728 if (Z_TYPE_P(in_array) != IS_ARRAY) {
729 return 0;
730 }
731 *out_array = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(in_array)) + 1, sizeof(MYSQLND *));
732 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(in_array), elem) {
733 i++;
734 if (Z_TYPE_P(elem) != IS_OBJECT ||
735 !instanceof_function(Z_OBJCE_P(elem), mysqli_link_class_entry)) {
736 php_error_docref(NULL, E_WARNING, "Parameter %d not a mysqli object", i);
737 } else {
738 MY_MYSQL *mysql;
739 MYSQLI_RESOURCE *my_res;
740 mysqli_object *intern = Z_MYSQLI_P(elem);
741 if (!(my_res = (MYSQLI_RESOURCE *)intern->ptr)) {
742 php_error_docref(NULL, E_WARNING, "[%d] Couldn't fetch %s", i, ZSTR_VAL(intern->zo.ce->name));
743 continue;
744 }
745 mysql = (MY_MYSQL*) my_res->ptr;
746 if (MYSQLI_STATUS_VALID && my_res->status < MYSQLI_STATUS_VALID) {
747 php_error_docref(NULL, E_WARNING, "Invalid object %d or resource %s", i, ZSTR_VAL(intern->zo.ce->name));
748 continue;
749 }
750 (*out_array)[current++] = mysql->mysql;
751 }
752 } ZEND_HASH_FOREACH_END();
753 return 0;
754 }
755 /* }}} */
756
757 /* {{{ mysqlnd_zval_array_from_mysqlnd_array */
758 static int mysqlnd_zval_array_from_mysqlnd_array(MYSQLND **in_array, zval *out_array)
759 {
760 MYSQLND **p = in_array;
761 zval dest_array;
762 zval *elem, *dest_elem;
763 int ret = 0, i = 0;
764
765 array_init_size(&dest_array, zend_hash_num_elements(Z_ARRVAL_P(out_array)));
766
767 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(out_array), elem) {
768 i++;
769 if (Z_TYPE_P(elem) != IS_OBJECT ||
770 !instanceof_function(Z_OBJCE_P(elem), mysqli_link_class_entry)) {
771 continue;
772 }
773 {
774 MY_MYSQL *mysql;
775 MYSQLI_RESOURCE *my_res;
776 mysqli_object *intern = Z_MYSQLI_P(elem);
777 if (!(my_res = (MYSQLI_RESOURCE *)intern->ptr)) {
778 php_error_docref(NULL, E_WARNING, "[%d] Couldn't fetch %s", i, ZSTR_VAL(intern->zo.ce->name));
779 continue;
780 }
781 mysql = (MY_MYSQL *) my_res->ptr;
782 if (mysql->mysql == *p) {
783 dest_elem = zend_hash_next_index_insert(Z_ARRVAL(dest_array), elem);
784 if (dest_elem) {
785 zval_add_ref(dest_elem);
786 }
787 ret++;
788 p++;
789 }
790 }
791 } ZEND_HASH_FOREACH_END();
792
793 /* destroy old array and add new one */
794 zval_ptr_dtor(out_array);
795 ZVAL_COPY_VALUE(out_array, &dest_array);
796
797 return 0;
798 }
799 /* }}} */
800
801 /* {{{ mysqlnd_dont_poll_zval_array_from_mysqlnd_array */
802 static int mysqlnd_dont_poll_zval_array_from_mysqlnd_array(MYSQLND **in_array, zval *in_zval_array, zval *out_array)
803 {
804 MYSQLND **p = in_array;
805 zval proxy, *elem, *dest_elem;
806 int ret = 0;
807
808 array_init(&proxy);
809 if (in_array) {
810 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(in_zval_array), elem) {
811 MY_MYSQL *mysql;
812 mysqli_object *intern = Z_MYSQLI_P(elem);
813 mysql = (MY_MYSQL *)((MYSQLI_RESOURCE *)intern->ptr)->ptr;
814 if (mysql->mysql == *p) {
815 dest_elem = zend_hash_next_index_insert(Z_ARRVAL(proxy), elem);
816 if (dest_elem) {
817 zval_add_ref(dest_elem);
818 }
819 ret++;
820 p++;
821 }
822 } ZEND_HASH_FOREACH_END();
823 }
824
825 /* destroy old array and add new one */
826 zval_ptr_dtor(out_array);
827 ZVAL_COPY_VALUE(out_array, &proxy);
828
829 return 0;
830 }
831 /* }}} */
832
833 /* {{{ proto int mysqli_poll(array read, array write, array error, int sec [, int usec]) U
834 Poll connections */
835 PHP_FUNCTION(mysqli_poll)
836 {
837 zval *r_array, *e_array, *dont_poll_array;
838 MYSQLND **new_r_array = NULL, **new_e_array = NULL, **new_dont_poll_array = NULL;
839 zend_long sec = 0, usec = 0;
840 enum_func_status ret;
841 int desc_num;
842
843 if (zend_parse_parameters(ZEND_NUM_ARGS(), "a!a!al|l", &r_array, &e_array, &dont_poll_array, &sec, &usec) == FAILURE) {
844 return;
845 }
846 if (sec < 0 || usec < 0) {
847 php_error_docref(NULL, E_WARNING, "Negative values passed for sec and/or usec");
848 RETURN_FALSE;
849 }
850
851 if (!r_array && !e_array) {
852 php_error_docref(NULL, E_WARNING, "No stream arrays were passed");
853 RETURN_FALSE;
854 }
855
856 if (r_array != NULL) {
857 mysqlnd_zval_array_to_mysqlnd_array(r_array, &new_r_array);
858 }
859 if (e_array != NULL) {
860 mysqlnd_zval_array_to_mysqlnd_array(e_array, &new_e_array);
861 }
862
863 ret = mysqlnd_poll(new_r_array, new_e_array, &new_dont_poll_array, sec, usec, &desc_num);
864
865 mysqlnd_dont_poll_zval_array_from_mysqlnd_array(r_array != NULL ? new_dont_poll_array:NULL, r_array, dont_poll_array);
866
867 if (r_array != NULL) {
868 mysqlnd_zval_array_from_mysqlnd_array(new_r_array, r_array);
869 }
870 if (e_array != NULL) {
871 mysqlnd_zval_array_from_mysqlnd_array(new_e_array, e_array);
872 }
873
874 if (new_dont_poll_array) {
875 efree(new_dont_poll_array);
876 }
877 if (new_r_array) {
878 efree(new_r_array);
879 }
880 if (new_e_array) {
881 efree(new_e_array);
882 }
883 if (ret == PASS) {
884 RETURN_LONG(desc_num);
885 } else {
886 RETURN_FALSE;
887 }
888 }
889 /* }}} */
890
891 /* {{{ proto int mysqli_reap_async_query(object link) U
892 Poll connections */
893 PHP_FUNCTION(mysqli_reap_async_query)
894 {
895 MY_MYSQL *mysql;
896 zval *mysql_link;
897 MYSQLI_RESOURCE *mysqli_resource;
898 MYSQL_RES *result = NULL;
899
900 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
901 return;
902 }
903
904 MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
905
906 if (FAIL == mysqlnd_reap_async_query(mysql->mysql)) {
907 RETURN_FALSE;
908 }
909
910 if (!mysql_field_count(mysql->mysql)) {
911 /* no result set - not a SELECT */
912 if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
913 /* php_mysqli_report_index("n/a", mysqli_server_status(mysql->mysql)); */
914 }
915 RETURN_TRUE;
916 }
917
918 switch (mysql->async_result_fetch_type) {
919 case MYSQLI_STORE_RESULT:
920 result = mysql_store_result(mysql->mysql);
921 break;
922 case MYSQLI_USE_RESULT:
923 result = mysql_use_result(mysql->mysql);
924 break;
925 }
926
927 if (!result) {
928 php_mysqli_throw_sql_exception((char *)mysql_sqlstate(mysql->mysql), mysql_errno(mysql->mysql),
929 "%s", mysql_error(mysql->mysql));
930 RETURN_FALSE;
931 }
932
933 if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
934 /* php_mysqli_report_index("n/a", mysqli_server_status(mysql->mysql)); */
935 }
936
937 mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
938 mysqli_resource->ptr = (void *)result;
939 mysqli_resource->status = MYSQLI_STATUS_VALID;
940 MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_result_class_entry);
941 }
942 /* }}} */
943
944 /* {{{ proto object mysqli_stmt_get_result(object link) U
945 Buffer result set on client */
946 PHP_FUNCTION(mysqli_stmt_get_result)
947 {
948 MYSQL_RES *result;
949 MYSQLI_RESOURCE *mysqli_resource;
950 MY_STMT *stmt;
951 zval *mysql_stmt;
952
953 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
954 return;
955 }
956 MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
957
958 if (!(result = mysqlnd_stmt_get_result(stmt->stmt))) {
959 MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
960 RETURN_FALSE;
961 }
962
963 mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
964 mysqli_resource->ptr = (void *)result;
965 mysqli_resource->status = MYSQLI_STATUS_VALID;
966 MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_result_class_entry);
967 }
968 /* }}} */
969 #endif
970
971 /* {{{ proto object mysqli_get_warnings(object link) */
972 PHP_FUNCTION(mysqli_get_warnings)
973 {
974 MY_MYSQL *mysql;
975 zval *mysql_link;
976 MYSQLI_RESOURCE *mysqli_resource;
977 MYSQLI_WARNING *w = NULL;
978
979 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
980 return;
981 }
982 MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
983
984 if (mysql_warning_count(mysql->mysql)) {
985 #ifdef MYSQLI_USE_MYSQLND
986 w = php_get_warnings(mysql->mysql->data);
987 #else
988 w = php_get_warnings(mysql->mysql);
989 #endif
990 }
991 if (!w) {
992 RETURN_FALSE;
993 }
994 mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
995 mysqli_resource->ptr = mysqli_resource->info = (void *)w;
996 mysqli_resource->status = MYSQLI_STATUS_VALID;
997 MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_warning_class_entry);
998 }
999 /* }}} */
1000
1001 /* {{{ proto object mysqli_stmt_get_warnings(object link) */
1002 PHP_FUNCTION(mysqli_stmt_get_warnings)
1003 {
1004 MY_STMT *stmt;
1005 zval *stmt_link;
1006 MYSQLI_RESOURCE *mysqli_resource;
1007 MYSQLI_WARNING *w = NULL;
1008
1009 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &stmt_link, mysqli_stmt_class_entry) == FAILURE) {
1010 return;
1011 }
1012 MYSQLI_FETCH_RESOURCE_STMT(stmt, stmt_link, MYSQLI_STATUS_VALID);
1013
1014 if (mysqli_stmt_warning_count(stmt->stmt)) {
1015 w = php_get_warnings(mysqli_stmt_get_connection(stmt->stmt));
1016 }
1017 if (!w) {
1018 RETURN_FALSE;
1019 }
1020 mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
1021 mysqli_resource->ptr = mysqli_resource->info = (void *)w;
1022 mysqli_resource->status = MYSQLI_STATUS_VALID;
1023 MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_warning_class_entry);
1024 }
1025 /* }}} */
1026
1027 #ifdef HAVE_MYSQLI_SET_CHARSET
1028 /* {{{ proto bool mysqli_set_charset(object link, string csname)
1029 sets client character set */
1030 PHP_FUNCTION(mysqli_set_charset)
1031 {
1032 MY_MYSQL *mysql;
1033 zval *mysql_link;
1034 char *cs_name;
1035 size_t csname_len;
1036
1037 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_link, mysqli_link_class_entry, &cs_name, &csname_len) == FAILURE) {
1038 return;
1039 }
1040 MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1041
1042 if (mysql_set_character_set(mysql->mysql, cs_name)) {
1043 RETURN_FALSE;
1044 }
1045 RETURN_TRUE;
1046 }
1047 /* }}} */
1048 #endif
1049
1050 #ifdef HAVE_MYSQLI_GET_CHARSET
1051 /* {{{ proto object mysqli_get_charset(object link) U
1052 returns a character set object */
1053 PHP_FUNCTION(mysqli_get_charset)
1054 {
1055 MY_MYSQL *mysql;
1056 zval *mysql_link;
1057 const char *name = NULL, *collation = NULL, *dir = NULL, *comment = NULL;
1058 uint32_t minlength, maxlength, number, state;
1059 #if !defined(MYSQLI_USE_MYSQLND)
1060 MY_CHARSET_INFO cs;
1061 #else
1062 const MYSQLND_CHARSET *cs;
1063 #endif
1064
1065 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
1066 return;
1067 }
1068 MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1069
1070
1071 #if !defined(MYSQLI_USE_MYSQLND)
1072 mysql_get_character_set_info(mysql->mysql, &cs);
1073 name = (char *)cs.csname;
1074 collation = (char *)cs.name;
1075 dir = (char *)cs.dir;
1076 minlength = cs.mbminlen;
1077 maxlength = cs.mbmaxlen;
1078 number = cs.number;
1079 state = cs.state;
1080 comment = cs.comment;
1081 #else
1082 cs = mysql->mysql->data->charset;
1083 if (!cs) {
1084 php_error_docref(NULL, E_WARNING, "The connection has no charset associated");
1085 RETURN_NULL();
1086 }
1087 name = cs->name;
1088 collation = cs->collation;
1089 minlength = cs->char_minlen;
1090 maxlength = cs->char_maxlen;
1091 number = cs->nr;
1092 comment = cs->comment;
1093 state = 1; /* all charsets are compiled in */
1094 #endif
1095 object_init(return_value);
1096
1097 add_property_string(return_value, "charset", (name) ? (char *)name : "");
1098 add_property_string(return_value, "collation",(collation) ? (char *)collation : "");
1099 add_property_string(return_value, "dir", (dir) ? (char *)dir : "");
1100 add_property_long(return_value, "min_length", minlength);
1101 add_property_long(return_value, "max_length", maxlength);
1102 add_property_long(return_value, "number", number);
1103 add_property_long(return_value, "state", state);
1104 add_property_string(return_value, "comment", (comment) ? (char *)comment : "");
1105 }
1106 /* }}} */
1107 #endif
1108
1109 #if !defined(MYSQLI_USE_MYSQLND)
1110 extern char * mysqli_escape_string_for_tx_name_in_comment(const char * const name);
1111
1112 /* {{{ proto bool mysqli_begin_transaction_libmysql */
1113 static int mysqli_begin_transaction_libmysql(MYSQL * conn, const unsigned int mode, const char * const name)
1114 {
1115 int ret;
1116 smart_str tmp_str = {0};
1117 char * name_esc;
1118 char * query;
1119 unsigned int query_len;
1120 if (mode & TRANS_START_WITH_CONSISTENT_SNAPSHOT) {
1121 if (tmp_str.s) {
1122 smart_str_appendl(&tmp_str, ", ", sizeof(", ") - 1);
1123 }
1124 smart_str_appendl(&tmp_str, "WITH CONSISTENT SNAPSHOT", sizeof("WITH CONSISTENT SNAPSHOT") - 1);
1125 }
1126 if (mode & TRANS_START_READ_WRITE) {
1127 if (tmp_str.s) {
1128 smart_str_appendl(&tmp_str, ", ", sizeof(", ") - 1);
1129 }
1130 smart_str_appendl(&tmp_str, "READ WRITE", sizeof("READ WRITE") - 1);
1131 } else if (mode & TRANS_START_READ_ONLY) {
1132 if (tmp_str.s) {
1133 smart_str_appendl(&tmp_str, ", ", sizeof(", ") - 1);
1134 }
1135 smart_str_appendl(&tmp_str, "READ ONLY", sizeof("READ ONLY") - 1);
1136 }
1137 smart_str_0(&tmp_str);
1138
1139 name_esc = mysqli_escape_string_for_tx_name_in_comment(name);
1140 query_len = spprintf(&query, 0, "START TRANSACTION%s %s",
1141 name_esc? name_esc:"", tmp_str.s? ZSTR_VAL(tmp_str.s):"");
1142
1143 smart_str_free(&tmp_str);
1144 if (name_esc) {
1145 efree(name_esc);
1146 }
1147
1148 ret = mysql_real_query(conn, query, query_len);
1149 efree(query);
1150
1151 if (ret && mode & (TRANS_START_READ_WRITE | TRANS_START_READ_ONLY) && mysql_errno(conn) == 1064) {
1152 php_error_docref(NULL, E_WARNING, "This server version doesn't support 'READ WRITE' and 'READ ONLY'. Minimum 5.6.5 is required");
1153 }
1154 return ret;
1155 }
1156 /* }}} */
1157 #endif
1158
1159 /* {{{ proto bool mysqli_begin_transaction(object link, [int flags [, string name]])
1160 Starts a transaction */
1161 PHP_FUNCTION(mysqli_begin_transaction)
1162 {
1163 MY_MYSQL *mysql;
1164 zval *mysql_link;
1165 zend_long flags = TRANS_START_NO_OPT;
1166 char * name = NULL;
1167 size_t name_len = -1;
1168 zend_bool err = FALSE;
1169
1170 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|ls", &mysql_link, mysqli_link_class_entry, &flags, &name, &name_len) == FAILURE) {
1171 return;
1172 }
1173 MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1174 if (flags < 0) {
1175 php_error_docref(NULL, E_WARNING, "Invalid value for parameter flags (" ZEND_LONG_FMT ")", flags);
1176 err = TRUE;
1177 }
1178 if (!name_len) {
1179 php_error_docref(NULL, E_WARNING, "Savepoint name cannot be empty");
1180 err = TRUE;
1181 }
1182 if (TRUE == err) {
1183 RETURN_FALSE;
1184 }
1185
1186 #if !defined(MYSQLI_USE_MYSQLND)
1187 if (mysqli_begin_transaction_libmysql(mysql->mysql, flags, name)) {
1188 RETURN_FALSE;
1189 }
1190 #else
1191 if (FAIL == mysqlnd_begin_transaction(mysql->mysql, flags, name)) {
1192 RETURN_FALSE;
1193 }
1194 #endif
1195 RETURN_TRUE;
1196 }
1197 /* }}} */
1198
1199 #if !defined(MYSQLI_USE_MYSQLND)
1200 /* {{{ proto bool mysqli_savepoint_libmysql */
1201 static int mysqli_savepoint_libmysql(MYSQL * conn, const char * const name, zend_bool release)
1202 {
1203 int ret;
1204 char * query;
1205 unsigned int query_len = spprintf(&query, 0, release? "RELEASE SAVEPOINT `%s`":"SAVEPOINT `%s`", name);
1206 ret = mysql_real_query(conn, query, query_len);
1207 efree(query);
1208 return ret;
1209 }
1210 /* }}} */
1211 #endif
1212
1213 /* {{{ proto bool mysqli_savepoint(object link, string name)
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 = -1;
1221
1222 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_link, mysqli_link_class_entry, &name, &name_len) == FAILURE) {
1223 return;
1224 }
1225 MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1226 if (!name || !name_len) {
1227 php_error_docref(NULL, E_WARNING, "Savepoint name cannot be empty");
1228 RETURN_FALSE;
1229 }
1230
1231 #if !defined(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 /* {{{ proto bool mysqli_release_savepoint(object link, string name)
1243 Starts a transaction */
1244 PHP_FUNCTION(mysqli_release_savepoint)
1245 {
1246 MY_MYSQL *mysql;
1247 zval *mysql_link;
1248 char * name = NULL;
1249 size_t name_len = -1;
1250
1251 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &mysql_link, mysqli_link_class_entry, &name, &name_len) == FAILURE) {
1252 return;
1253 }
1254 MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
1255 if (!name || !name_len) {
1256 php_error_docref(NULL, E_WARNING, "Savepoint name cannot be empty");
1257 RETURN_FALSE;
1258 }
1259 #if !defined(MYSQLI_USE_MYSQLND)
1260 if (mysqli_savepoint_libmysql(mysql->mysql, name, TRUE)) {
1261 #else
1262 if (FAIL == mysqlnd_release_savepoint(mysql->mysql, name)) {
1263 #endif
1264 RETURN_FALSE;
1265 }
1266 RETURN_TRUE;
1267 }
1268 /* }}} */
1269
1270 /* {{{ proto bool mysqli_get_links_stats()
1271 Returns information about open and cached links */
1272 PHP_FUNCTION(mysqli_get_links_stats)
1273 {
1274 if (ZEND_NUM_ARGS()) {
1275 php_error_docref(NULL, E_WARNING, "no parameters expected");
1276 return;
1277 }
1278 array_init(return_value);
1279 add_assoc_long_ex(return_value, "total", sizeof("total") - 1, MyG(num_links));
1280 add_assoc_long_ex(return_value, "active_plinks", sizeof("active_plinks") - 1, MyG(num_active_persistent));
1281 add_assoc_long_ex(return_value, "cached_plinks", sizeof("cached_plinks") - 1, MyG(num_inactive_persistent));
1282 }
1283 /* }}} */
1284