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