PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/pdo - pdo_stmt.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 1022 1242 82.3 %
Date: 2016-09-27 Functions: 55 71 77.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   +----------------------------------------------------------------------+
       3             :   | PHP Version 7                                                        |
       4             :   +----------------------------------------------------------------------+
       5             :   | Copyright (c) 1997-2016 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             :   | Author: Wez Furlong <wez@php.net>                                    |
      16             :   |         Marcus Boerger <helly@php.net>                               |
      17             :   |         Sterling Hughes <sterling@php.net>                           |
      18             :   +----------------------------------------------------------------------+
      19             : */
      20             : 
      21             : /* $Id$ */
      22             : 
      23             : /* The PDO Statement Handle Class */
      24             : 
      25             : #ifdef HAVE_CONFIG_H
      26             : #include "config.h"
      27             : #endif
      28             : 
      29             : #include "php.h"
      30             : #include "php_ini.h"
      31             : #include "ext/standard/info.h"
      32             : #include "ext/standard/php_var.h"
      33             : #include "php_pdo.h"
      34             : #include "php_pdo_driver.h"
      35             : #include "php_pdo_int.h"
      36             : #include "zend_exceptions.h"
      37             : #include "zend_interfaces.h"
      38             : #include "php_memory_streams.h"
      39             : 
      40             : /* {{{ arginfo */
      41             : ZEND_BEGIN_ARG_INFO(arginfo_pdostatement__void, 0)
      42             : ZEND_END_ARG_INFO()
      43             : 
      44             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_execute, 0, 0, 0)
      45             :         ZEND_ARG_INFO(0, bound_input_params) /* array */
      46             : ZEND_END_ARG_INFO()
      47             : 
      48             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_fetch, 0, 0, 0)
      49             :         ZEND_ARG_INFO(0, how)
      50             :         ZEND_ARG_INFO(0, orientation)
      51             :         ZEND_ARG_INFO(0, offset)
      52             : ZEND_END_ARG_INFO()
      53             : 
      54             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_fetchobject, 0, 0, 0)
      55             :         ZEND_ARG_INFO(0, class_name)
      56             :         ZEND_ARG_INFO(0, ctor_args) /* array */
      57             : ZEND_END_ARG_INFO()
      58             : 
      59             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_fetchcolumn, 0, 0, 0)
      60             :         ZEND_ARG_INFO(0, column_number)
      61             : ZEND_END_ARG_INFO()
      62             : 
      63             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_fetchall, 0, 0, 0)
      64             :         ZEND_ARG_INFO(0, how)
      65             :         ZEND_ARG_INFO(0, class_name)
      66             :         ZEND_ARG_INFO(0, ctor_args) /* array */
      67             : ZEND_END_ARG_INFO()
      68             : 
      69             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_bindvalue, 0, 0, 2)
      70             :         ZEND_ARG_INFO(0, paramno)
      71             :         ZEND_ARG_INFO(0, param)
      72             :         ZEND_ARG_INFO(0, type)
      73             : ZEND_END_ARG_INFO()
      74             : 
      75             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_bindparam, 0, 0, 2)
      76             :         ZEND_ARG_INFO(0, paramno)
      77             :         ZEND_ARG_INFO(1, param)
      78             :         ZEND_ARG_INFO(0, type)
      79             :         ZEND_ARG_INFO(0, maxlen)
      80             :         ZEND_ARG_INFO(0, driverdata)
      81             : ZEND_END_ARG_INFO()
      82             : 
      83             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_bindcolumn, 0, 0, 2)
      84             :         ZEND_ARG_INFO(0, column)
      85             :         ZEND_ARG_INFO(1, param)
      86             :         ZEND_ARG_INFO(0, type)
      87             :         ZEND_ARG_INFO(0, maxlen)
      88             :         ZEND_ARG_INFO(0, driverdata)
      89             : ZEND_END_ARG_INFO()
      90             : 
      91             : ZEND_BEGIN_ARG_INFO(arginfo_pdostatement_setattribute, 0)
      92             :         ZEND_ARG_INFO(0, attribute)
      93             :         ZEND_ARG_INFO(0, value)
      94             : ZEND_END_ARG_INFO()
      95             : 
      96             : ZEND_BEGIN_ARG_INFO(arginfo_pdostatement_getattribute, 0)
      97             :         ZEND_ARG_INFO(0, attribute)
      98             : ZEND_END_ARG_INFO()
      99             : 
     100             : ZEND_BEGIN_ARG_INFO(arginfo_pdostatement_getcolumnmeta, 0)
     101             :         ZEND_ARG_INFO(0, column)
     102             : ZEND_END_ARG_INFO()
     103             : 
     104             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_setfetchmode, 0, 0, 1)
     105             :         ZEND_ARG_INFO(0, mode)
     106             :         ZEND_ARG_INFO(0, params)
     107             : ZEND_END_ARG_INFO()
     108             : /* }}} */
     109             : 
     110             : #define PHP_STMT_GET_OBJ        \
     111             :   pdo_stmt_t *stmt = Z_PDO_STMT_P(getThis());   \
     112             :   if (!stmt->dbh) {  \
     113             :           RETURN_FALSE; \
     114             :   }     \
     115             : 
     116       35921 : static inline int rewrite_name_to_position(pdo_stmt_t *stmt, struct pdo_bound_param_data *param) /* {{{ */
     117             : {
     118       35921 :         if (stmt->bound_param_map) {
     119             :                 /* rewriting :name to ? style.
     120             :                  * We need to fixup the parameter numbers on the parameters.
     121             :                  * If we find that a given named parameter has been used twice,
     122             :                  * we will raise an error, as we can't be sure that it is safe
     123             :                  * to bind multiple parameters onto the same zval in the underlying
     124             :                  * driver */
     125             :                 char *name;
     126        4660 :                 int position = 0;
     127             : 
     128        4660 :                 if (stmt->named_rewrite_template) {
     129             :                         /* this is not an error here */
     130        4522 :                         return 1;
     131             :                 }
     132         138 :                 if (!param->name) {
     133             :                         /* do the reverse; map the parameter number to the name */
     134         164 :                         if ((name = zend_hash_index_find_ptr(stmt->bound_param_map, param->paramno)) != NULL) {
     135         164 :                                 param->name = zend_string_init(name, strlen(name), 0);
     136          82 :                                 return 1;
     137             :                         }
     138           0 :                         pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined");
     139           0 :                         return 0;
     140             :                 }
     141             : 
     142         185 :                 ZEND_HASH_FOREACH_PTR(stmt->bound_param_map, name) {
     143          91 :                         if (strncmp(name, ZSTR_VAL(param->name), ZSTR_LEN(param->name) + 1)) {
     144          38 :                                 position++;
     145          38 :                                 continue;
     146             :                         }
     147          53 :                         if (param->paramno >= 0) {
     148           0 :                                 pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "PDO refuses to handle repeating the same :named parameter for multiple positions with this driver, as it might be unsafe to do so.  Consider using a separate name for each parameter instead");
     149           0 :                                 return -1;
     150             :                         }
     151          53 :                         param->paramno = position;
     152          53 :                         return 1;
     153             :                 } ZEND_HASH_FOREACH_END();
     154           3 :                 pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined");
     155           3 :                 return 0;
     156             :         }
     157       31261 :         return 1;
     158             : }
     159             : /* }}} */
     160             : 
     161             : /* trigger callback hook for parameters */
     162       51502 : static int dispatch_param_event(pdo_stmt_t *stmt, enum pdo_param_event event_type) /* {{{ */
     163             : {
     164       51502 :         int ret = 1, is_param = 1;
     165             :         struct pdo_bound_param_data *param;
     166             :         HashTable *ht;
     167             : 
     168       51502 :         if (!stmt->methods->param_hook) {
     169           0 :                 return 1;
     170             :         }
     171             : 
     172       51502 :         ht = stmt->bound_params;
     173             : 
     174             : iterate:
     175      103000 :         if (ht) {
     176      172984 :                 ZEND_HASH_FOREACH_PTR(ht, param) {
     177       73688 :                         if (!stmt->methods->param_hook(stmt, param, event_type)) {
     178           5 :                                 ret = 0;
     179           5 :                                 break;
     180             :                         }
     181             :                 } ZEND_HASH_FOREACH_END();
     182             :         }
     183      103000 :         if (ret && is_param) {
     184       51498 :                 ht = stmt->bound_columns;
     185       51498 :                 is_param = 0;
     186       51498 :                 goto iterate;
     187             :         }
     188             : 
     189       51502 :         return ret;
     190             : }
     191             : /* }}} */
     192             : 
     193       12244 : int pdo_stmt_describe_columns(pdo_stmt_t *stmt) /* {{{ */
     194             : {
     195             :         int col;
     196             : 
     197       12244 :         stmt->columns = ecalloc(stmt->column_count, sizeof(struct pdo_column_data));
     198             : 
     199       14862 :         for (col = 0; col < stmt->column_count; col++) {
     200        2618 :                 if (!stmt->methods->describer(stmt, col)) {
     201           0 :                         return 0;
     202             :                 }
     203             : 
     204             :                 /* if we are applying case conversions on column names, do so now */
     205        2618 :                 if (stmt->dbh->native_case != stmt->dbh->desired_case && stmt->dbh->desired_case != PDO_CASE_NATURAL) {
     206        2500 :                         char *s = ZSTR_VAL(stmt->columns[col].name);
     207             : 
     208        2500 :                         switch (stmt->dbh->desired_case) {
     209             :                                 case PDO_CASE_UPPER:
     210          70 :                                         while (*s != '\0') {
     211          44 :                                                 *s = toupper(*s);
     212          44 :                                                 s++;
     213             :                                         }
     214          13 :                                         break;
     215             :                                 case PDO_CASE_LOWER:
     216       15387 :                                         while (*s != '\0') {
     217       10413 :                                                 *s = tolower(*s);
     218       10413 :                                                 s++;
     219             :                                         }
     220             :                                         break;
     221             :                                 default:
     222             :                                         ;
     223             :                         }
     224             :                 }
     225             : 
     226             : #if 0
     227             :                 /* update the column index on named bound parameters */
     228             :                 if (stmt->bound_params) {
     229             :                         struct pdo_bound_param_data *param;
     230             : 
     231             :                         if (SUCCESS == zend_hash_find(stmt->bound_params, stmt->columns[col].name,
     232             :                                                 stmt->columns[col].namelen, (void**)&param)) {
     233             :                                 param->paramno = col;
     234             :                         }
     235             :                 }
     236             : #endif
     237        2618 :                 if (stmt->bound_columns) {
     238             :                         struct pdo_bound_param_data *param;
     239             : 
     240          54 :                         if ((param = zend_hash_find_ptr(stmt->bound_columns,
     241          27 :                                         stmt->columns[col].name)) != NULL) {
     242          22 :                                 param->paramno = col;
     243             :                         }
     244             :                 }
     245             : 
     246             :         }
     247       12244 :         return 1;
     248             : }
     249             : /* }}} */
     250             : 
     251          28 : static void get_lazy_object(pdo_stmt_t *stmt, zval *return_value) /* {{{ */
     252             : {
     253          56 :         if (Z_ISUNDEF(stmt->lazy_object_ref)) {
     254          22 :                 pdo_row_t *row = ecalloc(1, sizeof(pdo_row_t));
     255          22 :                 row->stmt = stmt;
     256          22 :                 zend_object_std_init(&row->std, pdo_row_ce);
     257          22 :                 ZVAL_OBJ(&stmt->lazy_object_ref, &row->std);
     258          22 :                 row->std.handlers = &pdo_row_object_handlers;
     259          22 :                 GC_REFCOUNT(&stmt->std)++;
     260          22 :                 GC_REFCOUNT(&row->std)--;
     261             :         }
     262          28 :         ZVAL_COPY(return_value, &stmt->lazy_object_ref);
     263          28 : }
     264             : /* }}} */
     265             : 
     266       36322 : static void param_dtor(zval *el) /* {{{ */
     267             : {
     268       36322 :         struct pdo_bound_param_data *param = (struct pdo_bound_param_data *)Z_PTR_P(el);
     269             : 
     270             :         /* tell the driver that it is going away */
     271       36322 :         if (param->stmt->methods->param_hook) {
     272       36322 :                         param->stmt->methods->param_hook(param->stmt, param, PDO_PARAM_EVT_FREE);
     273             :         }
     274             : 
     275       36322 :         if (param->name) {
     276       34521 :                 zend_string_release(param->name);
     277             :         }
     278             : 
     279       72644 :         if (!Z_ISUNDEF(param->parameter)) {
     280       36322 :                 zval_ptr_dtor(&param->parameter);
     281       36322 :                 ZVAL_UNDEF(&param->parameter);
     282             :         }
     283       72644 :         if (!Z_ISUNDEF(param->driver_params)) {
     284           0 :                 zval_ptr_dtor(&param->driver_params);
     285             :         }
     286       36322 :         efree(param);
     287       36322 : }
     288             : /* }}} */
     289             : 
     290       36336 : static int really_register_bound_param(struct pdo_bound_param_data *param, pdo_stmt_t *stmt, int is_param) /* {{{ */
     291             : {
     292             :         HashTable *hash;
     293             :         zval *parameter;
     294       36336 :         struct pdo_bound_param_data *pparam = NULL;
     295             : 
     296       36336 :         hash = is_param ? stmt->bound_params : stmt->bound_columns;
     297             : 
     298       36336 :         if (!hash) {
     299       11828 :                 ALLOC_HASHTABLE(hash);
     300       11828 :                 zend_hash_init(hash, 13, NULL, param_dtor, 0);
     301             : 
     302       11828 :                 if (is_param) {
     303       11633 :                         stmt->bound_params = hash;
     304             :                 } else {
     305         195 :                         stmt->bound_columns = hash;
     306             :                 }
     307             :         }
     308             : 
     309       72672 :         if (!Z_ISREF(param->parameter)) {
     310        5702 :                 parameter = &param->parameter;
     311             :         } else {
     312       30634 :                 parameter = Z_REFVAL(param->parameter);
     313             :         }
     314             : 
     315       68397 :         if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_STR && param->max_value_len <= 0 && !Z_ISNULL_P(parameter)) {
     316       15853 :                 if (Z_TYPE_P(parameter) == IS_DOUBLE) {
     317             :                         char *p;
     318          23 :                         int len = spprintf(&p, 0, "%.*H", (int) EG(precision), Z_DVAL_P(parameter));
     319          46 :                         ZVAL_STRINGL(parameter, p, len);
     320          23 :                         efree(p);
     321             :                 } else {
     322       15830 :                         convert_to_string(parameter);
     323             :                 }
     324       20623 :         } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_INT && (Z_TYPE_P(parameter) == IS_FALSE || Z_TYPE_P(parameter) == IS_TRUE)) {
     325           6 :                 convert_to_long(parameter);
     326       20487 :         } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_BOOL && Z_TYPE_P(parameter) == IS_LONG) {
     327           1 :                 convert_to_boolean(parameter);
     328             :         }
     329             : 
     330       36336 :         param->stmt = stmt;
     331       36336 :         param->is_param = is_param;
     332             : 
     333       36336 :         if (Z_REFCOUNTED(param->driver_params)) {
     334           0 :                 Z_ADDREF(param->driver_params);
     335             :         }
     336             : 
     337       36336 :         if (!is_param && param->name && stmt->columns) {
     338             :                 /* try to map the name to the column */
     339             :                 int i;
     340             : 
     341         136 :                 for (i = 0; i < stmt->column_count; i++) {
     342         270 :                         if (ZSTR_LEN(stmt->columns[i].name) == ZSTR_LEN(param->name) &&
     343         134 :                             strncmp(ZSTR_VAL(stmt->columns[i].name), ZSTR_VAL(param->name), ZSTR_LEN(param->name) + 1) == 0) {
     344         107 :                                 param->paramno = i;
     345         107 :                                 break;
     346             :                         }
     347             :                 }
     348             : 
     349             :                 /* if you prepare and then execute passing an array of params keyed by names,
     350             :                  * then this will trigger, and we don't want that */
     351         107 :                 if (param->paramno == -1) {
     352             :                         char *tmp;
     353           0 :                         spprintf(&tmp, 0, "Did not find column name '%s' in the defined columns; it will not be bound", ZSTR_VAL(param->name));
     354           0 :                         pdo_raise_impl_error(stmt->dbh, stmt, "HY000", tmp);
     355           0 :                         efree(tmp);
     356             :                 }
     357             :         }
     358             : 
     359       36336 :         if (param->name) {
     360       38547 :                 if (is_param && ZSTR_VAL(param->name)[0] != ':') {
     361        8194 :                         zend_string *temp = zend_string_alloc(ZSTR_LEN(param->name) + 1, 0);
     362        4097 :                         ZSTR_VAL(temp)[0] = ':';
     363        4097 :                         memmove(ZSTR_VAL(temp) + 1, ZSTR_VAL(param->name), ZSTR_LEN(param->name) + 1);
     364        4097 :                         param->name = temp;
     365             :                 } else {
     366       60706 :                         param->name = zend_string_init(ZSTR_VAL(param->name), ZSTR_LEN(param->name), 0);
     367             :                 }
     368             :         }
     369             : 
     370       36336 :         if (is_param && !rewrite_name_to_position(stmt, param)) {
     371           3 :                 if (param->name) {
     372           3 :                         zend_string_release(param->name);
     373           3 :                         param->name = NULL;
     374             :                 }
     375           3 :                 return 0;
     376             :         }
     377             : 
     378             :         /* ask the driver to perform any normalization it needs on the
     379             :          * parameter name.  Note that it is illegal for the driver to take
     380             :          * a reference to param, as it resides in transient storage only
     381             :          * at this time. */
     382       36333 :         if (stmt->methods->param_hook) {
     383       36333 :                 if (!stmt->methods->param_hook(stmt, param, PDO_PARAM_EVT_NORMALIZE
     384             :                                 )) {
     385           3 :                         if (param->name) {
     386           3 :                                 zend_string_release(param->name);
     387           3 :                                 param->name = NULL;
     388             :                         }
     389           3 :                         return 0;
     390             :                 }
     391             :         }
     392             : 
     393             :         /* delete any other parameter registered with this number.
     394             :          * If the parameter is named, it will be removed and correctly
     395             :          * disposed of by the hash_update call that follows */
     396       36330 :         if (param->paramno >= 0) {
     397        6152 :                 zend_hash_index_del(hash, param->paramno);
     398             :         }
     399             : 
     400             :         /* allocate storage for the parameter, keyed by its "canonical" name */
     401       36330 :         if (param->name) {
     402       69052 :                 pparam = zend_hash_update_mem(hash, param->name, param, sizeof(struct pdo_bound_param_data));
     403             :         } else {
     404        3608 :                 pparam = zend_hash_index_update_mem(hash, param->paramno, param, sizeof(struct pdo_bound_param_data));
     405             :         }
     406             : 
     407             :         /* tell the driver we just created a parameter */
     408       36330 :         if (stmt->methods->param_hook) {
     409       36330 :                 if (!stmt->methods->param_hook(stmt, pparam, PDO_PARAM_EVT_ALLOC
     410             :                                         )) {
     411             :                         /* undo storage allocation; the hash will free the parameter
     412             :                          * name if required */
     413           8 :                         if (pparam->name) {
     414           3 :                                 zend_hash_del(hash, pparam->name);
     415             :                         } else {
     416           5 :                                 zend_hash_index_del(hash, pparam->paramno);
     417             :                         }
     418             :                         /* param->parameter is freed by hash dtor */
     419           8 :                         ZVAL_UNDEF(&param->parameter);
     420           8 :                         return 0;
     421             :                 }
     422             :         }
     423       36322 :         return 1;
     424             : }
     425             : /* }}} */
     426             : 
     427             : /* {{{ proto bool PDOStatement::execute([array $bound_input_params])
     428             :    Execute a prepared statement, optionally binding parameters */
     429       13063 : static PHP_METHOD(PDOStatement, execute)
     430             : {
     431       13063 :         zval *input_params = NULL;
     432       13063 :         int ret = 1;
     433       26126 :         PHP_STMT_GET_OBJ;
     434             : 
     435       13063 :         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!", &input_params)) {
     436           0 :                 RETURN_FALSE;
     437             :         }
     438             : 
     439       13063 :         PDO_STMT_CLEAR_ERR();
     440             : 
     441       13063 :         if (input_params) {
     442             :                 struct pdo_bound_param_data param;
     443             :                 zval *tmp;
     444        1321 :                 zend_string *key = NULL;
     445             :                 zend_ulong num_index;
     446             : 
     447        1321 :                 if (stmt->bound_params) {
     448        1160 :                         zend_hash_destroy(stmt->bound_params);
     449        1160 :                         FREE_HASHTABLE(stmt->bound_params);
     450        1160 :                         stmt->bound_params = NULL;
     451             :                 }
     452             : 
     453       12175 :                 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(input_params), num_index, key, tmp) {
     454        5421 :                         memset(&param, 0, sizeof(param));
     455             : 
     456        5421 :                         if (key) {
     457             :                                 /* yes this is correct.  we don't want to count the null byte.  ask wez */
     458        4228 :                                 param.name = key;
     459        4228 :                                 param.paramno = -1;
     460             :                         } else {
     461             :                                 /* we're okay to be zero based here */
     462             :                                 /* num_index is unsignend
     463             :                                 if (num_index < 0) {
     464             :                                         pdo_raise_impl_error(stmt->dbh, stmt, "HY093", NULL);
     465             :                                         RETURN_FALSE;
     466             :                                 }
     467             :                                 */
     468        1193 :                                 param.paramno = num_index;
     469             :                         }
     470             : 
     471        5421 :                         param.param_type = PDO_PARAM_STR;
     472        5421 :                         ZVAL_COPY(&param.parameter, tmp);
     473             : 
     474        5421 :                         if (!really_register_bound_param(&param, stmt, 1)) {
     475          12 :                                 if (!Z_ISUNDEF(param.parameter)) {
     476           4 :                                         zval_ptr_dtor(&param.parameter);
     477             :                                 }
     478          12 :                                 RETURN_FALSE;
     479             :                         }
     480             :                 } ZEND_HASH_FOREACH_END();
     481             :         }
     482             : 
     483       13051 :         if (PDO_PLACEHOLDER_NONE == stmt->supports_placeholders) {
     484             :                 /* handle the emulated parameter binding,
     485             :          * stmt->active_query_string holds the query with binds expanded and
     486             :                  * quoted.
     487             :          */
     488             : 
     489         446 :                 ret = pdo_parse_params(stmt, stmt->query_string, stmt->query_stringlen,
     490             :                         &stmt->active_query_string, &stmt->active_query_stringlen);
     491             : 
     492         446 :                 if (ret == 0) {
     493             :                         /* no changes were made */
     494         237 :                         stmt->active_query_string = stmt->query_string;
     495         237 :                         stmt->active_query_stringlen = stmt->query_stringlen;
     496         237 :                         ret = 1;
     497         209 :                 } else if (ret == -1) {
     498             :                         /* something broke */
     499           6 :                         PDO_HANDLE_STMT_ERR();
     500           6 :                         RETURN_FALSE;
     501             :                 }
     502       12605 :         } else if (!dispatch_param_event(stmt, PDO_PARAM_EVT_EXEC_PRE)) {
     503           4 :                 PDO_HANDLE_STMT_ERR();
     504           4 :                 RETURN_FALSE;
     505             :         }
     506       13041 :         if (stmt->methods->executer(stmt)) {
     507       12999 :                 if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
     508         196 :                         efree(stmt->active_query_string);
     509             :                 }
     510       12999 :                 stmt->active_query_string = NULL;
     511       12999 :                 if (!stmt->executed) {
     512             :                         /* this is the first execute */
     513             : 
     514       12620 :                         if (stmt->dbh->alloc_own_columns && !stmt->columns) {
     515             :                                 /* for "big boy" drivers, we need to allocate memory to fetch
     516             :                                  * the results into, so lets do that now */
     517       11418 :                                 ret = pdo_stmt_describe_columns(stmt);
     518             :                         }
     519             : 
     520       12620 :                         stmt->executed = 1;
     521             :                 }
     522             : 
     523       12999 :                 if (ret && !dispatch_param_event(stmt, PDO_PARAM_EVT_EXEC_POST)) {
     524           0 :                         RETURN_FALSE;
     525             :                 }
     526             : 
     527       12999 :                 RETURN_BOOL(ret);
     528             :         }
     529          34 :         if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
     530           4 :                 efree(stmt->active_query_string);
     531             :         }
     532          34 :         stmt->active_query_string = NULL;
     533          34 :         PDO_HANDLE_STMT_ERR();
     534          34 :         RETURN_FALSE;
     535             : }
     536             : /* }}} */
     537             : 
     538       25271 : static inline void fetch_value(pdo_stmt_t *stmt, zval *dest, int colno, int *type_override) /* {{{ */
     539             : {
     540             :         struct pdo_column_data *col;
     541       25271 :         char *value = NULL;
     542       25271 :         size_t value_len = 0;
     543       25271 :         int caller_frees = 0;
     544             :         int type, new_type;
     545             : 
     546       25271 :         col = &stmt->columns[colno];
     547       25271 :         type = PDO_PARAM_TYPE(col->param_type);
     548       25271 :         new_type =  type_override ? (int)PDO_PARAM_TYPE(*type_override) : type;
     549             : 
     550       25271 :         value = NULL;
     551       25271 :         value_len = 0;
     552             : 
     553       25271 :         stmt->methods->get_col(stmt, colno, &value, &value_len, &caller_frees);
     554             : 
     555       25271 :         switch (type) {
     556             :                 case PDO_PARAM_ZVAL:
     557        2060 :                         if (value && value_len == sizeof(zval)) {
     558        1030 :                                 ZVAL_COPY_VALUE(dest, (zval *)value);
     559             :                         } else {
     560           0 :                                 ZVAL_NULL(dest);
     561             :                         }
     562             : 
     563        1030 :                         if (Z_TYPE_P(dest) == IS_NULL) {
     564          12 :                                 type = new_type;
     565             :                         }
     566        1030 :                         break;
     567             : 
     568             :                 case PDO_PARAM_INT:
     569         254 :                         if (value && value_len == sizeof(zend_long)) {
     570         236 :                                 ZVAL_LONG(dest, *(zend_long*)value);
     571         236 :                                 break;
     572             :                         }
     573          18 :                         ZVAL_NULL(dest);
     574          18 :                         break;
     575             : 
     576             :                 case PDO_PARAM_BOOL:
     577           2 :                         if (value && value_len == sizeof(zend_bool)) {
     578           2 :                                 ZVAL_BOOL(dest, *(zend_bool*)value);
     579           2 :                                 break;
     580             :                         }
     581           0 :                         ZVAL_NULL(dest);
     582           0 :                         break;
     583             : 
     584             :                 case PDO_PARAM_LOB:
     585       20052 :                         if (value == NULL) {
     586           2 :                                 ZVAL_NULL(dest);
     587       20050 :                         } else if (value_len == 0) {
     588             :                                 /* Warning, empty strings need to be passed as stream */
     589       20079 :                                 if (stmt->dbh->stringify || new_type == PDO_PARAM_STR) {
     590             :                                         zend_string *buf;
     591          31 :                                         buf = php_stream_copy_to_mem((php_stream*)value, PHP_STREAM_COPY_ALL, 0);
     592          31 :                                         if (buf == NULL) {
     593           3 :                                                 ZVAL_EMPTY_STRING(dest);
     594             :                                         } else {
     595          28 :                                                 ZVAL_STR(dest, buf);
     596             :                                         }
     597          31 :                                         php_stream_close((php_stream*)value);
     598             :                                 } else {
     599       20017 :                                         php_stream_to_zval((php_stream*)value, dest);
     600             :                                 }
     601           3 :                         } else if (!stmt->dbh->stringify && new_type != PDO_PARAM_STR) {
     602             :                                 /* they gave us a string, but LOBs are represented as streams in PDO */
     603             :                                 php_stream *stm;
     604             : #ifdef TEMP_STREAM_TAKE_BUFFER
     605           1 :                                 if (caller_frees) {
     606           1 :                                         stm = php_stream_memory_open(TEMP_STREAM_TAKE_BUFFER, value, value_len);
     607           1 :                                         if (stm) {
     608           1 :                                                 caller_frees = 0;
     609             :                                         }
     610             :                                 } else
     611             : #endif
     612             :                                 {
     613           0 :                                         stm = php_stream_memory_open(TEMP_STREAM_READONLY, value, value_len);
     614             :                                 }
     615           1 :                                 if (stm) {
     616           1 :                                         php_stream_to_zval(stm, dest);
     617             :                                 } else {
     618           0 :                                         ZVAL_NULL(dest);
     619             :                                 }
     620             :                         } else {
     621           2 :                                 ZVAL_STRINGL(dest, value, value_len);
     622             :                         }
     623       20052 :                         break;
     624             : 
     625             :                 case PDO_PARAM_STR:
     626        3933 :                         if (value && !(value_len == 0 && stmt->dbh->oracle_nulls == PDO_NULL_EMPTY_STRING)) {
     627        7688 :                                 ZVAL_STRINGL(dest, value, value_len);
     628        3844 :                                 break;
     629             :                         }
     630             :                 default:
     631          89 :                         ZVAL_NULL(dest);
     632             :         }
     633             : 
     634       25271 :         if (type != new_type) {
     635         369 :                 switch (new_type) {
     636             :                         case PDO_PARAM_INT:
     637          72 :                                 convert_to_long_ex(dest);
     638          72 :                                 break;
     639             :                         case PDO_PARAM_BOOL:
     640           0 :                                 convert_to_boolean_ex(dest);
     641           0 :                                 break;
     642             :                         case PDO_PARAM_STR:
     643         468 :                                 convert_to_string_ex(dest);
     644         279 :                                 break;
     645             :                         case PDO_PARAM_NULL:
     646           0 :                                 convert_to_null_ex(dest);
     647             :                                 break;
     648             :                         default:
     649             :                                 ;
     650             :                 }
     651             :         }
     652             : 
     653       25271 :         if (caller_frees && value) {
     654           1 :                 efree(value);
     655             :         }
     656             : 
     657       25271 :         if (stmt->dbh->stringify) {
     658        3441 :                 switch (Z_TYPE_P(dest)) {
     659             :                         case IS_LONG:
     660             :                         case IS_DOUBLE:
     661         322 :                                 convert_to_string(dest);
     662             :                                 break;
     663             :                 }
     664             :         }
     665             : 
     666       25271 :         if (Z_TYPE_P(dest) == IS_NULL && stmt->dbh->oracle_nulls == PDO_NULL_TO_STRING) {
     667           2 :                 ZVAL_EMPTY_STRING(dest);
     668             :         }
     669       25271 : }
     670             : /* }}} */
     671             : 
     672       13310 : static int do_fetch_common(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori, zend_long offset, int do_bind) /* {{{ */
     673             : {
     674       13310 :         if (!stmt->executed) {
     675          15 :                 return 0;
     676             :         }
     677             : 
     678       13295 :         if (!dispatch_param_event(stmt, PDO_PARAM_EVT_FETCH_PRE)) {
     679           0 :                 return 0;
     680             :         }
     681             : 
     682       13295 :         if (!stmt->methods->fetcher(stmt, ori, offset)) {
     683         692 :                 return 0;
     684             :         }
     685             : 
     686             :         /* some drivers might need to describe the columns now */
     687       12603 :         if (!stmt->columns && !pdo_stmt_describe_columns(stmt)) {
     688           0 :                 return 0;
     689             :         }
     690             : 
     691       12603 :         if (!dispatch_param_event(stmt, PDO_PARAM_EVT_FETCH_POST)) {
     692           1 :                 return 0;
     693             :         }
     694             : 
     695       12602 :         if (do_bind && stmt->bound_columns) {
     696             :                 /* update those bound column variables now */
     697             :                 struct pdo_bound_param_data *param;
     698             : 
     699        2348 :                 ZEND_HASH_FOREACH_PTR(stmt->bound_columns, param) {
     700         898 :                         if (param->paramno >= 0) {
     701        1796 :                                 if (!Z_ISREF(param->parameter)) {
     702           0 :                                         continue;
     703             :                                 }
     704             : 
     705             :                                 /* delete old value */
     706         898 :                                 zval_ptr_dtor(Z_REFVAL(param->parameter));
     707             : 
     708             :                                 /* set new value */
     709         898 :                                 fetch_value(stmt, Z_REFVAL(param->parameter), param->paramno, (int *)&param->param_type);
     710             : 
     711             :                                 /* TODO: some smart thing that avoids duplicating the value in the
     712             :                                  * general loop below.  For now, if you're binding output columns,
     713             :                                  * it's better to use LAZY or BOUND fetches if you want to shave
     714             :                                  * off those cycles */
     715             :                         }
     716             :                 } ZEND_HASH_FOREACH_END();
     717             :         }
     718             : 
     719       12602 :         return 1;
     720             : }
     721             : /* }}} */
     722             : 
     723         206 : static int do_fetch_class_prepare(pdo_stmt_t *stmt) /* {{{ */
     724             : {
     725         206 :         zend_class_entry *ce = stmt->fetch.cls.ce;
     726         206 :         zend_fcall_info *fci = &stmt->fetch.cls.fci;
     727         206 :         zend_fcall_info_cache *fcc = &stmt->fetch.cls.fcc;
     728             : 
     729         206 :         fci->size = sizeof(zend_fcall_info);
     730             : 
     731         206 :         if (!ce) {
     732           1 :                 stmt->fetch.cls.ce = ZEND_STANDARD_CLASS_DEF_PTR;
     733           1 :                 ce = ZEND_STANDARD_CLASS_DEF_PTR;
     734             :         }
     735             : 
     736         206 :         if (ce->constructor) {
     737         147 :                 ZVAL_UNDEF(&fci->function_name);
     738         147 :                 fci->retval = &stmt->fetch.cls.retval;
     739         147 :                 fci->param_count = 0;
     740         147 :                 fci->params = NULL;
     741         147 :                 fci->no_separation = 1;
     742             : 
     743         147 :                 zend_fcall_info_args_ex(fci, ce->constructor, &stmt->fetch.cls.ctor_args);
     744             : 
     745         147 :                 fcc->initialized = 1;
     746         147 :                 fcc->function_handler = ce->constructor;
     747         147 :                 fcc->calling_scope = zend_get_executed_scope();
     748         147 :                 fcc->called_scope = ce;
     749         147 :                 return 1;
     750         118 :         } else if (!Z_ISUNDEF(stmt->fetch.cls.ctor_args)) {
     751           0 :                 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied class does not have a constructor, use NULL for the ctor_params parameter, or simply omit it");
     752           0 :                 return 0;
     753             :         } else {
     754          59 :                 return 1; /* no ctor no args is also ok */
     755             :         }
     756             : }
     757             : /* }}} */
     758             : 
     759          66 : static int make_callable_ex(pdo_stmt_t *stmt, zval *callable, zend_fcall_info * fci, zend_fcall_info_cache * fcc, int num_args) /* {{{ */
     760             : {
     761          66 :         char *is_callable_error = NULL;
     762             : 
     763          66 :         if (zend_fcall_info_init(callable, 0, fci, fcc, NULL, &is_callable_error) == FAILURE) {
     764           7 :                 if (is_callable_error) {
     765           7 :                         pdo_raise_impl_error(stmt->dbh, stmt, "HY000", is_callable_error);
     766           7 :                         efree(is_callable_error);
     767             :                 } else {
     768           0 :                         pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied function must be a valid callback");
     769             :                 }
     770           7 :                 return 0;
     771             :         }
     772          59 :         if (is_callable_error) {
     773             :                 /* Possible E_STRICT error message */
     774           1 :                 efree(is_callable_error);
     775             :         }
     776             : 
     777          59 :         fci->param_count = num_args; /* probably less */
     778          59 :         fci->params = safe_emalloc(sizeof(zval), num_args, 0);
     779             : 
     780          59 :         return 1;
     781             : }
     782             : /* }}} */
     783             : 
     784          66 : static int do_fetch_func_prepare(pdo_stmt_t *stmt) /* {{{ */
     785             : {
     786          66 :         zend_fcall_info *fci = &stmt->fetch.cls.fci;
     787          66 :         zend_fcall_info_cache *fcc = &stmt->fetch.cls.fcc;
     788             : 
     789          66 :         if (!make_callable_ex(stmt, &stmt->fetch.func.function, fci, fcc, stmt->column_count)) {
     790           7 :                 return 0;
     791             :         } else {
     792          59 :                 stmt->fetch.func.values = safe_emalloc(sizeof(zval), stmt->column_count, 0);
     793          59 :                 return 1;
     794             :         }
     795             : }
     796             : /* }}} */
     797             : 
     798       13724 : static void do_fetch_opt_finish(pdo_stmt_t *stmt, int free_ctor_agrs) /* {{{ */
     799             : {
     800             :         /* fci.size is used to check if it is valid */
     801       13724 :         if (stmt->fetch.cls.fci.size && stmt->fetch.cls.fci.params) {
     802         204 :                 if (!Z_ISUNDEF(stmt->fetch.cls.ctor_args)) {
     803             :                     /* Added to free constructor arguments */
     804          43 :                         zend_fcall_info_args_clear(&stmt->fetch.cls.fci, 1);
     805             :                 } else {
     806          59 :                         efree(stmt->fetch.cls.fci.params);
     807             :                 }
     808         102 :                 stmt->fetch.cls.fci.params = NULL;
     809             :         }
     810             : 
     811       13724 :         stmt->fetch.cls.fci.size = 0;
     812       27448 :         if (!Z_ISUNDEF(stmt->fetch.cls.ctor_args) && free_ctor_agrs) {
     813          40 :                 zval_ptr_dtor(&stmt->fetch.cls.ctor_args);
     814          40 :                 ZVAL_UNDEF(&stmt->fetch.cls.ctor_args);
     815          40 :                 stmt->fetch.cls.fci.param_count = 0;
     816             :         }
     817       13724 :         if (stmt->fetch.func.values) {
     818          59 :                 efree(stmt->fetch.func.values);
     819          59 :                 stmt->fetch.func.values = NULL;
     820             :         }
     821       13724 : }
     822             : /* }}} */
     823             : 
     824             : /* perform a fetch.  If do_bind is true, update any bound columns.
     825             :  * If return_value is not null, store values into it according to HOW. */
     826       13184 : static int do_fetch(pdo_stmt_t *stmt, int do_bind, zval *return_value, enum pdo_fetch_type how, enum pdo_fetch_orientation ori, zend_long offset, zval *return_all) /* {{{ */
     827             : {
     828       13184 :         int flags, idx, old_arg_count = 0;
     829       13184 :         zend_class_entry *ce = NULL, *old_ce = NULL;
     830             :         zval grp_val, *pgrp, retval, old_ctor_args;
     831             :         int colno;
     832             : 
     833       13184 :         if (how == PDO_FETCH_USE_DEFAULT) {
     834       10534 :                 how = stmt->default_fetch_type;
     835             :         }
     836       13184 :         flags = how & PDO_FETCH_FLAGS;
     837       13184 :         how = how & ~PDO_FETCH_FLAGS;
     838             : 
     839       13184 :         if (!do_fetch_common(stmt, ori, offset, do_bind)) {
     840         702 :                 return 0;
     841             :         }
     842             : 
     843       12482 :         if (how == PDO_FETCH_BOUND) {
     844         406 :                 RETVAL_TRUE;
     845         406 :                 return 1;
     846             :         }
     847             : 
     848       12196 :         if (flags & PDO_FETCH_GROUP && stmt->fetch.column == -1) {
     849         120 :                 colno = 1;
     850             :         } else {
     851       11956 :                 colno = stmt->fetch.column;
     852             :         }
     853             : 
     854       12076 :         if (return_value) {
     855       12076 :                 int i = 0;
     856             : 
     857       12076 :                 if (how == PDO_FETCH_LAZY) {
     858          28 :                         get_lazy_object(stmt, return_value);
     859          28 :                         return 1;
     860             :                 }
     861             : 
     862       12048 :                 RETVAL_FALSE;
     863             : 
     864       12048 :                 switch (how) {
     865             :                         case PDO_FETCH_USE_DEFAULT:
     866             :                         case PDO_FETCH_ASSOC:
     867             :                         case PDO_FETCH_BOTH:
     868             :                         case PDO_FETCH_NUM:
     869             :                         case PDO_FETCH_NAMED:
     870       11249 :                                 if (!return_all) {
     871       11153 :                                         ZVAL_NEW_ARR(return_value);
     872       11153 :                                         zend_hash_init(Z_ARRVAL_P(return_value), stmt->column_count, NULL, ZVAL_PTR_DTOR, 0);;
     873             :                                 } else {
     874          96 :                                         array_init(return_value);
     875             :                                 }
     876       11249 :                                 break;
     877             : 
     878             :                         case PDO_FETCH_KEY_PAIR:
     879         102 :                                 if (stmt->column_count != 2) {
     880           6 :                                         pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_KEY_PAIR fetch mode requires the result set to contain extactly 2 columns.");
     881           6 :                                         return 0;
     882             :                                 }
     883          96 :                                 if (!return_all) {
     884           6 :                                         array_init(return_value);
     885             :                                 }
     886          96 :                                 break;
     887             : 
     888             :                         case PDO_FETCH_COLUMN:
     889         203 :                                 if (colno >= 0 && colno < stmt->column_count) {
     890         227 :                                         if (flags == PDO_FETCH_GROUP && stmt->fetch.column == -1) {
     891          24 :                                                 fetch_value(stmt, return_value, 1, NULL);
     892         179 :                                         } else if (flags == PDO_FETCH_GROUP && colno) {
     893           0 :                                                 fetch_value(stmt, return_value, 0, NULL);
     894             :                                         } else {
     895         179 :                                                 fetch_value(stmt, return_value, colno, NULL);
     896             :                                         }
     897         203 :                                         if (!return_all) {
     898          47 :                                                 return 1;
     899             :                                         } else {
     900         156 :                                                 break;
     901             :                                         }
     902             :                                 } else {
     903           0 :                                         pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Invalid column index");
     904             :                                 }
     905           0 :                                 return 0;
     906             : 
     907             :                         case PDO_FETCH_OBJ:
     908          18 :                                 object_init_ex(return_value, ZEND_STANDARD_CLASS_DEF_PTR);
     909          18 :                                 break;
     910             : 
     911             :                         case PDO_FETCH_CLASS:
     912         238 :                                 if (flags & PDO_FETCH_CLASSTYPE) {
     913             :                                         zval val;
     914             :                                         zend_class_entry *cep;
     915             : 
     916          92 :                                         old_ce = stmt->fetch.cls.ce;
     917          92 :                                         ZVAL_COPY_VALUE(&old_ctor_args, &stmt->fetch.cls.ctor_args);
     918          92 :                                         old_arg_count = stmt->fetch.cls.fci.param_count;
     919          92 :                                         do_fetch_opt_finish(stmt, 0);
     920             : 
     921          92 :                                         fetch_value(stmt, &val, i++, NULL);
     922          92 :                                         if (Z_TYPE(val) != IS_NULL) {
     923          70 :                                                 convert_to_string(&val);
     924          70 :                                                 if ((cep = zend_lookup_class(Z_STR(val))) == NULL) {
     925           1 :                                                         stmt->fetch.cls.ce = ZEND_STANDARD_CLASS_DEF_PTR;
     926             :                                                 } else {
     927          69 :                                                         stmt->fetch.cls.ce = cep;
     928             :                                                 }
     929             :                                         }
     930             : 
     931          92 :                                         do_fetch_class_prepare(stmt);
     932             :                                         zval_dtor(&val);
     933             :                                 }
     934         238 :                                 ce = stmt->fetch.cls.ce;
     935         238 :                                 if (!ce) {
     936           6 :                                         pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch class specified");
     937           6 :                                         return 0;
     938             :                                 }
     939         232 :                                 if ((flags & PDO_FETCH_SERIALIZE) == 0) {
     940         206 :                                         if (UNEXPECTED(object_init_ex(return_value, ce) != SUCCESS)) {
     941           0 :                                                 return 0;
     942             :                                         }
     943         206 :                                         if (!stmt->fetch.cls.fci.size) {
     944          18 :                                                 if (!do_fetch_class_prepare(stmt))
     945             :                                                 {
     946           0 :                                                         return 0;
     947             :                                                 }
     948             :                                         }
     949         206 :                                         if (ce->constructor && (flags & PDO_FETCH_PROPS_LATE)) {
     950           9 :                                                 stmt->fetch.cls.fci.object = Z_OBJ_P(return_value);
     951           9 :                                                 stmt->fetch.cls.fcc.object = Z_OBJ_P(return_value);
     952           9 :                                                 if (zend_call_function(&stmt->fetch.cls.fci, &stmt->fetch.cls.fcc) == FAILURE) {
     953           0 :                                                         pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call class constructor");
     954           0 :                                                         return 0;
     955             :                                                 } else {
     956          18 :                                                         if (!Z_ISUNDEF(stmt->fetch.cls.retval)) {
     957           9 :                                                                 zval_ptr_dtor(&stmt->fetch.cls.retval);
     958           9 :                                                                 ZVAL_UNDEF(&stmt->fetch.cls.retval);
     959             :                                                         }
     960             :                                                 }
     961             :                                         }
     962             :                                 }
     963         232 :                                 break;
     964             : 
     965             :                         case PDO_FETCH_INTO:
     966          84 :                                 if (Z_ISUNDEF(stmt->fetch.into)) {
     967           0 :                                         pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch-into object specified.");
     968           0 :                                         return 0;
     969             :                                         break;
     970             :                                 }
     971             : 
     972          42 :                                 ZVAL_COPY(return_value, &stmt->fetch.into);
     973             : 
     974          42 :                                 if (Z_OBJ_P(return_value)->ce == ZEND_STANDARD_CLASS_DEF_PTR) {
     975           0 :                                         how = PDO_FETCH_OBJ;
     976             :                                 }
     977          42 :                                 break;
     978             : 
     979             :                         case PDO_FETCH_FUNC:
     980         392 :                                 if (Z_ISUNDEF(stmt->fetch.func.function)) {
     981           6 :                                         pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch function specified");
     982           6 :                                         return 0;
     983             :                                 }
     984         190 :                                 if (!stmt->fetch.func.fci.size) {
     985           0 :                                         if (!do_fetch_func_prepare(stmt))
     986             :                                         {
     987           0 :                                                 return 0;
     988             :                                         }
     989             :                                 }
     990         190 :                                 break;
     991             : 
     992             : 
     993             :                         default:
     994             :                                 /* shouldn't happen */
     995           0 :                                 return 0;
     996             :                 }
     997             : 
     998       11983 :                 if (return_all && how != PDO_FETCH_KEY_PAIR) {
     999         324 :                         if (flags == PDO_FETCH_GROUP && how == PDO_FETCH_COLUMN && stmt->fetch.column > 0) {
    1000           0 :                                 fetch_value(stmt, &grp_val, colno, NULL);
    1001             :                         } else {
    1002         324 :                                 fetch_value(stmt, &grp_val, i, NULL);
    1003             :                         }
    1004         324 :                         convert_to_string(&grp_val);
    1005         324 :                         if (how == PDO_FETCH_COLUMN) {
    1006         156 :                                 i = stmt->column_count; /* no more data to fetch */
    1007             :                         } else {
    1008         168 :                                 i++;
    1009             :                         }
    1010             :                 }
    1011             : 
    1012       35365 :                 for (idx = 0; i < stmt->column_count; i++, idx++) {
    1013             :                         zval val;
    1014       23482 :                         fetch_value(stmt, &val, i, NULL);
    1015             : 
    1016       23482 :                         switch (how) {
    1017             :                                 case PDO_FETCH_ASSOC:
    1018        1590 :                                         zend_symtable_update(Z_ARRVAL_P(return_value), stmt->columns[i].name, &val);
    1019        1590 :                                         break;
    1020             : 
    1021             :                                 case PDO_FETCH_KEY_PAIR:
    1022             :                                         {
    1023             :                                                 zval tmp;
    1024          96 :                                                 fetch_value(stmt, &tmp, ++i, NULL);
    1025             : 
    1026          96 :                                                 if (Z_TYPE(val) == IS_LONG) {
    1027           0 :                                                         zend_hash_index_update((return_all ? Z_ARRVAL_P(return_all) : Z_ARRVAL_P(return_value)), Z_LVAL(val), &tmp);
    1028             :                                                 } else {
    1029          96 :                                                         convert_to_string(&val);
    1030          96 :                                                         zend_symtable_update((return_all ? Z_ARRVAL_P(return_all) : Z_ARRVAL_P(return_value)), Z_STR(val), &tmp);
    1031             :                                                 }
    1032          96 :                                                 zval_ptr_dtor(&val);
    1033          96 :                                                 return 1;
    1034             :                                         }
    1035             :                                         break;
    1036             : 
    1037             :                                 case PDO_FETCH_USE_DEFAULT:
    1038             :                                 case PDO_FETCH_BOTH:
    1039       20545 :                                         zend_symtable_update(Z_ARRVAL_P(return_value), stmt->columns[i].name, &val);
    1040       20545 :                                         if (Z_REFCOUNTED(val)) {
    1041             :                                                 Z_ADDREF(val);
    1042             :                                         }
    1043       20545 :                                         zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &val);
    1044       20545 :                                         break;
    1045             : 
    1046             :                                 case PDO_FETCH_NAMED:
    1047             :                                         /* already have an item with this name? */
    1048             :                                         {
    1049             :                                                 zval *curr_val;
    1050           0 :                                                 if ((curr_val = zend_hash_find(Z_ARRVAL_P(return_value), stmt->columns[i].name))) {
    1051             :                                                         zval arr;
    1052           0 :                                                         if (Z_TYPE_P(curr_val) != IS_ARRAY) {
    1053             :                                                                 /* a little bit of black magic here:
    1054             :                                                                  * we're creating a new array and swapping it for the
    1055             :                                                                  * zval that's already stored in the hash under the name
    1056             :                                                                  * we want.  We then add that zval to the array.
    1057             :                                                                  * This is effectively the same thing as:
    1058             :                                                                  * if (!is_array($hash[$name])) {
    1059             :                                                                  *   $hash[$name] = array($hash[$name]);
    1060             :                                                                  * }
    1061             :                                                                  * */
    1062             :                                                                 zval cur;
    1063             : 
    1064           0 :                                                                 array_init(&arr);
    1065             : 
    1066           0 :                                                                 ZVAL_COPY_VALUE(&cur, curr_val);
    1067           0 :                                                                 ZVAL_COPY_VALUE(curr_val, &arr);
    1068             : 
    1069           0 :                                                                 zend_hash_next_index_insert_new(Z_ARRVAL(arr), &cur);
    1070             :                                                         } else {
    1071           0 :                                                                 ZVAL_COPY_VALUE(&arr, curr_val);
    1072             :                                                         }
    1073           0 :                                                         zend_hash_next_index_insert_new(Z_ARRVAL(arr), &val);
    1074             :                                                 } else {
    1075           0 :                                                         zend_hash_update(Z_ARRVAL_P(return_value), stmt->columns[i].name, &val);
    1076             :                                                 }
    1077             :                                         }
    1078           0 :                                         break;
    1079             : 
    1080             :                                 case PDO_FETCH_NUM:
    1081         260 :                                         zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &val);
    1082         260 :                                         break;
    1083             : 
    1084             :                                 case PDO_FETCH_OBJ:
    1085             :                                 case PDO_FETCH_INTO:
    1086         162 :                                         zend_update_property_ex(NULL, return_value,
    1087         162 :                                                 stmt->columns[i].name,
    1088             :                                                 &val);
    1089         162 :                                         zval_ptr_dtor(&val);
    1090         162 :                                         break;
    1091             : 
    1092             :                                 case PDO_FETCH_CLASS:
    1093         948 :                                         if ((flags & PDO_FETCH_SERIALIZE) == 0 || idx) {
    1094         461 :                                                 zend_update_property_ex(ce, return_value,
    1095         461 :                                                         stmt->columns[i].name,
    1096             :                                                         &val);
    1097         461 :                                                 zval_ptr_dtor(&val);
    1098             :                                         } else {
    1099             : #ifdef MBO_0
    1100             :                                                 php_unserialize_data_t var_hash;
    1101             : 
    1102             :                                                 PHP_VAR_UNSERIALIZE_INIT(var_hash);
    1103             :                                                 if (php_var_unserialize(return_value, (const unsigned char**)&Z_STRVAL(val), Z_STRVAL(val)+Z_STRLEN(val), NULL) == FAILURE) {
    1104             :                                                         pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize data");
    1105             :                                                         PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
    1106             :                                                         return 0;
    1107             :                                                 }
    1108             :                                                 PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
    1109             : #endif
    1110          26 :                                                 if (!ce->unserialize) {
    1111           4 :                                                         zval_ptr_dtor(&val);
    1112           4 :                                                         pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize class");
    1113           4 :                                                         return 0;
    1114          66 :                                                 } else if (ce->unserialize(return_value, ce, (unsigned char *)(Z_TYPE(val) == IS_STRING ? Z_STRVAL(val) : ""), Z_TYPE(val) == IS_STRING ? Z_STRLEN(val) : 0, NULL) == FAILURE) {
    1115           0 :                                                         zval_ptr_dtor(&val);
    1116           0 :                                                         pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize class");
    1117             :                                                         zval_dtor(return_value);
    1118           0 :                                                         ZVAL_NULL(return_value);
    1119           0 :                                                         return 0;
    1120             :                                                 } else {
    1121          22 :                                                         zval_ptr_dtor(&val);
    1122             :                                                 }
    1123             :                                         }
    1124         483 :                                         break;
    1125             : 
    1126             :                                 case PDO_FETCH_FUNC:
    1127         342 :                                         ZVAL_COPY_VALUE(&stmt->fetch.func.values[idx], &val);
    1128         342 :                                         ZVAL_COPY_VALUE(&stmt->fetch.cls.fci.params[idx], &stmt->fetch.func.values[idx]);
    1129         342 :                                         break;
    1130             : 
    1131             :                                 default:
    1132           0 :                                         zval_ptr_dtor(&val);
    1133           0 :                                         pdo_raise_impl_error(stmt->dbh, stmt, "22003", "mode is out of range");
    1134           0 :                                         return 0;
    1135             :                                         break;
    1136             :                         }
    1137             :                 }
    1138             : 
    1139       11883 :                 switch (how) {
    1140             :                         case PDO_FETCH_CLASS:
    1141         228 :                                 if (ce->constructor && !(flags & (PDO_FETCH_PROPS_LATE | PDO_FETCH_SERIALIZE))) {
    1142         139 :                                         stmt->fetch.cls.fci.object = Z_OBJ_P(return_value);
    1143         139 :                                         stmt->fetch.cls.fcc.object = Z_OBJ_P(return_value);
    1144         139 :                                         if (zend_call_function(&stmt->fetch.cls.fci, &stmt->fetch.cls.fcc) == FAILURE) {
    1145           0 :                                                 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call class constructor");
    1146           0 :                                                 return 0;
    1147             :                                         } else {
    1148         278 :                                                 if (!Z_ISUNDEF(stmt->fetch.cls.retval)) {
    1149         139 :                                                         zval_ptr_dtor(&stmt->fetch.cls.retval);
    1150             :                                                 }
    1151             :                                         }
    1152             :                                 }
    1153         228 :                                 if (flags & PDO_FETCH_CLASSTYPE) {
    1154          88 :                                         do_fetch_opt_finish(stmt, 0);
    1155          88 :                                         stmt->fetch.cls.ce = old_ce;
    1156          88 :                                         ZVAL_COPY_VALUE(&stmt->fetch.cls.ctor_args, &old_ctor_args);
    1157          88 :                                         stmt->fetch.cls.fci.param_count = old_arg_count;
    1158             :                                 }
    1159         228 :                                 break;
    1160             : 
    1161             :                         case PDO_FETCH_FUNC:
    1162         190 :                                 stmt->fetch.func.fci.param_count = idx;
    1163         190 :                                 stmt->fetch.func.fci.retval = &retval;
    1164         190 :                                 if (zend_call_function(&stmt->fetch.func.fci, &stmt->fetch.func.fcc) == FAILURE) {
    1165           0 :                                         pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call user-supplied function");
    1166           0 :                                         return 0;
    1167             :                                 } else {
    1168         190 :                                         if (return_all) {
    1169          24 :                                                 zval_ptr_dtor(return_value); /* we don't need that */
    1170          24 :                                                 ZVAL_COPY_VALUE(return_value, &retval);
    1171         166 :                                         } else if (!Z_ISUNDEF(retval)) {
    1172         166 :                                                 ZVAL_COPY_VALUE(return_value, &retval);
    1173             :                                         }
    1174             :                                 }
    1175         722 :                                 while (idx--) {
    1176         342 :                                         zval_ptr_dtor(&stmt->fetch.func.values[idx]);
    1177             :                                 }
    1178             :                                 break;
    1179             : 
    1180             :                         default:
    1181             :                                 break;
    1182             :                 }
    1183             : 
    1184       11883 :                 if (return_all) {
    1185         324 :                         if ((flags & PDO_FETCH_UNIQUE) == PDO_FETCH_UNIQUE) {
    1186         210 :                                 zend_symtable_update(Z_ARRVAL_P(return_all), Z_STR(grp_val), return_value);
    1187             :                         } else {
    1188             :                                 zval grp;
    1189         228 :                                 if ((pgrp = zend_symtable_find(Z_ARRVAL_P(return_all), Z_STR(grp_val))) == NULL) {
    1190          72 :                                         array_init(&grp);
    1191          72 :                                         zend_symtable_update(Z_ARRVAL_P(return_all), Z_STR(grp_val), &grp);
    1192             :                                 } else {
    1193          42 :                                         ZVAL_COPY_VALUE(&grp, pgrp);
    1194             :                                 }
    1195         114 :                                 zend_hash_next_index_insert(Z_ARRVAL(grp), return_value);
    1196             :                         }
    1197             :                         zval_dtor(&grp_val);
    1198             :                 }
    1199             : 
    1200             :         }
    1201             : 
    1202       11883 :         return 1;
    1203             : }
    1204             : /* }}} */
    1205             : 
    1206        1763 : static int pdo_stmt_verify_mode(pdo_stmt_t *stmt, zend_long mode, int fetch_all) /* {{{ */
    1207             : {
    1208        1763 :         int flags = mode & PDO_FETCH_FLAGS;
    1209             : 
    1210        1763 :         mode = mode & ~PDO_FETCH_FLAGS;
    1211             : 
    1212        1763 :         if (mode < 0 || mode > PDO_FETCH__MAX) {
    1213           0 :                 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "invalid fetch mode");
    1214           0 :                 return 0;
    1215             :         }
    1216             : 
    1217        1763 :         if (mode == PDO_FETCH_USE_DEFAULT) {
    1218         176 :                 flags = stmt->default_fetch_type & PDO_FETCH_FLAGS;
    1219         176 :                 mode = stmt->default_fetch_type & ~PDO_FETCH_FLAGS;
    1220             :         }
    1221             : 
    1222        1763 :         switch(mode) {
    1223             :                 case PDO_FETCH_FUNC:
    1224          72 :                         if (!fetch_all) {
    1225           0 :                                 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_FUNC is only allowed in PDOStatement::fetchAll()");
    1226           0 :                                 return 0;
    1227             :                         }
    1228          72 :                         return 1;
    1229             : 
    1230             :                 case PDO_FETCH_LAZY:
    1231          29 :                         if (fetch_all) {
    1232           0 :                                 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_LAZY can't be used with PDOStatement::fetchAll()");
    1233           0 :                                 return 0;
    1234             :                         }
    1235             :                         /* fall through */
    1236             :                 default:
    1237        1549 :                         if ((flags & PDO_FETCH_SERIALIZE) == PDO_FETCH_SERIALIZE) {
    1238           0 :                                 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_SERIALIZE can only be used together with PDO::FETCH_CLASS");
    1239           0 :                                 return 0;
    1240             :                         }
    1241        1549 :                         if ((flags & PDO_FETCH_CLASSTYPE) == PDO_FETCH_CLASSTYPE) {
    1242           0 :                                 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_CLASSTYPE can only be used together with PDO::FETCH_CLASS");
    1243           0 :                                 return 0;
    1244             :                         }
    1245        1549 :                         if (mode >= PDO_FETCH__MAX) {
    1246           0 :                                 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "invalid fetch mode");
    1247           0 :                                 return 0;
    1248             :                         }
    1249             :                         /* no break; */
    1250             : 
    1251             :                 case PDO_FETCH_CLASS:
    1252        1691 :                         return 1;
    1253             :         }
    1254             : }
    1255             : /* }}} */
    1256             : 
    1257             : /* {{{ proto mixed PDOStatement::fetch([int $how = PDO_FETCH_BOTH [, int $orientation [, int $offset]]])
    1258             :    Fetches the next row and returns it, or false if there are no more rows */
    1259        1096 : static PHP_METHOD(PDOStatement, fetch)
    1260             : {
    1261        1096 :         zend_long how = PDO_FETCH_USE_DEFAULT;
    1262        1096 :         zend_long ori = PDO_FETCH_ORI_NEXT;
    1263        1096 :         zend_long off = 0;
    1264        2192 :     PHP_STMT_GET_OBJ;
    1265             : 
    1266        1096 :         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|lll", &how,
    1267             :                         &ori, &off)) {
    1268           0 :                 RETURN_FALSE;
    1269             :         }
    1270             : 
    1271        1096 :         PDO_STMT_CLEAR_ERR();
    1272             : 
    1273        1096 :         if (!pdo_stmt_verify_mode(stmt, how, 0)) {
    1274           0 :                 RETURN_FALSE;
    1275             :         }
    1276             : 
    1277        1096 :         if (!do_fetch(stmt, TRUE, return_value, how, ori, off, 0)) {
    1278         126 :                 PDO_HANDLE_STMT_ERR();
    1279         126 :                 RETURN_FALSE;
    1280             :         }
    1281             : }
    1282             : /* }}} */
    1283             : 
    1284             : /* {{{ proto mixed PDOStatement::fetchObject([string class_name [, NULL|array ctor_args]])
    1285             :    Fetches the next row and returns it as an object. */
    1286           7 : static PHP_METHOD(PDOStatement, fetchObject)
    1287             : {
    1288           7 :         zend_long how = PDO_FETCH_CLASS;
    1289           7 :         zend_long ori = PDO_FETCH_ORI_NEXT;
    1290           7 :         zend_long off = 0;
    1291           7 :         zend_string *class_name = NULL;
    1292             :         zend_class_entry *old_ce;
    1293           7 :         zval old_ctor_args, *ctor_args = NULL;
    1294           7 :         int error = 0, old_arg_count;
    1295             : 
    1296          14 :         PHP_STMT_GET_OBJ;
    1297             : 
    1298           7 :         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|S!a", &class_name, &ctor_args)) {
    1299           0 :                 RETURN_FALSE;
    1300             :         }
    1301             : 
    1302           7 :         PDO_STMT_CLEAR_ERR();
    1303             : 
    1304           7 :         if (!pdo_stmt_verify_mode(stmt, how, 0)) {
    1305           0 :                 RETURN_FALSE;
    1306             :         }
    1307             : 
    1308           7 :         old_ce = stmt->fetch.cls.ce;
    1309           7 :         ZVAL_COPY_VALUE(&old_ctor_args, &stmt->fetch.cls.ctor_args);
    1310           7 :         old_arg_count = stmt->fetch.cls.fci.param_count;
    1311             : 
    1312           7 :         do_fetch_opt_finish(stmt, 0);
    1313             : 
    1314           7 :         if (ctor_args) {
    1315          12 :                 if (Z_TYPE_P(ctor_args) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(ctor_args))) {
    1316           4 :                         ZVAL_DUP(&stmt->fetch.cls.ctor_args, ctor_args);
    1317             :                 } else {
    1318           0 :                         ZVAL_UNDEF(&stmt->fetch.cls.ctor_args);
    1319             :                 }
    1320             :         }
    1321          11 :         if (class_name && !error) {
    1322           5 :                 stmt->fetch.cls.ce = zend_fetch_class(class_name, ZEND_FETCH_CLASS_AUTO);
    1323             : 
    1324           4 :                 if (!stmt->fetch.cls.ce) {
    1325           0 :                         pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Could not find user-supplied class");
    1326           0 :                         error = 1;
    1327             :                 }
    1328           2 :         } else if (!error) {
    1329           2 :                 stmt->fetch.cls.ce = zend_standard_class_def;
    1330             :         }
    1331             : 
    1332           6 :         if (!error && !do_fetch(stmt, TRUE, return_value, how, ori, off, 0)) {
    1333           1 :                 error = 1;
    1334             :         }
    1335           6 :         if (error) {
    1336           1 :                 PDO_HANDLE_STMT_ERR();
    1337             :         }
    1338           6 :         do_fetch_opt_finish(stmt, 1);
    1339             : 
    1340           6 :         stmt->fetch.cls.ce = old_ce;
    1341           6 :         ZVAL_COPY_VALUE(&stmt->fetch.cls.ctor_args, &old_ctor_args);
    1342           6 :         stmt->fetch.cls.fci.param_count = old_arg_count;
    1343           6 :         if (error) {
    1344           1 :                 RETURN_FALSE;
    1345             :         }
    1346             : }
    1347             : /* }}} */
    1348             : 
    1349             : /* {{{ proto string PDOStatement::fetchColumn([int column_number])
    1350             :    Returns a data of the specified column in the result set. */
    1351         126 : static PHP_METHOD(PDOStatement, fetchColumn)
    1352             : {
    1353         126 :         zend_long col_n = 0;
    1354         252 :         PHP_STMT_GET_OBJ;
    1355             : 
    1356         126 :         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &col_n)) {
    1357           0 :                 RETURN_FALSE;
    1358             :         }
    1359             : 
    1360         126 :         PDO_STMT_CLEAR_ERR();
    1361             : 
    1362         126 :         if (!do_fetch_common(stmt, PDO_FETCH_ORI_NEXT, 0, TRUE)) {
    1363           6 :                 PDO_HANDLE_STMT_ERR();
    1364           6 :                 RETURN_FALSE;
    1365             :         }
    1366             : 
    1367         120 :         fetch_value(stmt, return_value, col_n, NULL);
    1368             : }
    1369             : /* }}} */
    1370             : 
    1371             : /* {{{ proto array PDOStatement::fetchAll([int $how = PDO_FETCH_BOTH [, string class_name [, NULL|array ctor_args]]])
    1372             :    Returns an array of all of the results. */
    1373         517 : static PHP_METHOD(PDOStatement, fetchAll)
    1374             : {
    1375         517 :         zend_long how = PDO_FETCH_USE_DEFAULT;
    1376             :         zval data, *return_all;
    1377             :         zval *arg2;
    1378             :         zend_class_entry *old_ce;
    1379         517 :         zval old_ctor_args, *ctor_args = NULL;
    1380         517 :         int error = 0, flags, old_arg_count;
    1381        1034 :         PHP_STMT_GET_OBJ;
    1382             : 
    1383         517 :         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|lzz", &how, &arg2, &ctor_args)) {
    1384           0 :                 RETURN_FALSE;
    1385             :         }
    1386             : 
    1387         517 :         if (!pdo_stmt_verify_mode(stmt, how, 1)) {
    1388           0 :                 RETURN_FALSE;
    1389             :         }
    1390             : 
    1391         517 :         old_ce = stmt->fetch.cls.ce;
    1392         517 :         ZVAL_COPY_VALUE(&old_ctor_args, &stmt->fetch.cls.ctor_args);
    1393         517 :         old_arg_count = stmt->fetch.cls.fci.param_count;
    1394             : 
    1395         517 :         do_fetch_opt_finish(stmt, 0);
    1396             : 
    1397         517 :         switch(how & ~PDO_FETCH_FLAGS) {
    1398             :         case PDO_FETCH_CLASS:
    1399          59 :                 switch(ZEND_NUM_ARGS()) {
    1400             :                 case 0:
    1401             :                 case 1:
    1402           6 :                         stmt->fetch.cls.ce = zend_standard_class_def;
    1403           6 :                         break;
    1404             :                 case 3:
    1405          51 :                         if (Z_TYPE_P(ctor_args) != IS_NULL && Z_TYPE_P(ctor_args) != IS_ARRAY) {
    1406           0 :                                 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array");
    1407           0 :                                 error = 1;
    1408           0 :                                 break;
    1409             :                         }
    1410          34 :                         if (Z_TYPE_P(ctor_args) != IS_ARRAY || !zend_hash_num_elements(Z_ARRVAL_P(ctor_args))) {
    1411           4 :                                 ctor_args = NULL;
    1412             :                         }
    1413             :                         /* no break */
    1414             :                 case 2:
    1415          53 :                         if (ctor_args) {
    1416          13 :                                 ZVAL_COPY_VALUE(&stmt->fetch.cls.ctor_args, ctor_args); /* we're not going to free these */
    1417             :                         } else {
    1418          40 :                                 ZVAL_UNDEF(&stmt->fetch.cls.ctor_args);
    1419             :                         }
    1420         106 :                         if (Z_TYPE_P(arg2) != IS_STRING) {
    1421           0 :                                 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Invalid class name (should be a string)");
    1422           0 :                                 error = 1;
    1423           0 :                                 break;
    1424             :                         } else {
    1425          53 :                                 stmt->fetch.cls.ce = zend_fetch_class(Z_STR_P(arg2), ZEND_FETCH_CLASS_AUTO);
    1426          53 :                                 if (!stmt->fetch.cls.ce) {
    1427           0 :                                         pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not find user-specified class");
    1428           0 :                                         error = 1;
    1429             :                                         break;
    1430             :                                 }
    1431             :                         }
    1432             :                 }
    1433          59 :                 if (!error) {
    1434          59 :                         do_fetch_class_prepare(stmt);
    1435             :                 }
    1436          59 :                 break;
    1437             : 
    1438             :         case PDO_FETCH_FUNC:
    1439          66 :                 switch (ZEND_NUM_ARGS()) {
    1440             :                         case 0:
    1441             :                         case 1:
    1442           0 :                                 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "no fetch function specified");
    1443           0 :                                 error = 1;
    1444           0 :                                 break;
    1445             :                         case 3:
    1446             :                         case 2:
    1447          66 :                                 ZVAL_COPY_VALUE(&stmt->fetch.func.function, arg2);
    1448          66 :                                 if (do_fetch_func_prepare(stmt) == 0) {
    1449           7 :                                         error = 1;
    1450             :                                 }
    1451             :                                 break;
    1452             :                 }
    1453          66 :                 break;
    1454             : 
    1455             :         case PDO_FETCH_COLUMN:
    1456          81 :                 switch(ZEND_NUM_ARGS()) {
    1457             :                 case 0:
    1458             :                 case 1:
    1459          57 :                         stmt->fetch.column = how & PDO_FETCH_GROUP ? -1 : 0;
    1460          57 :                         break;
    1461             :                 case 2:
    1462          24 :                         convert_to_long(arg2);
    1463          24 :                         stmt->fetch.column = Z_LVAL_P(arg2);
    1464          24 :                         break;
    1465             :                 case 3:
    1466           0 :                         pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Third parameter not allowed for PDO::FETCH_COLUMN");
    1467           0 :                         error = 1;
    1468             :                 }
    1469          81 :                 break;
    1470             : 
    1471             :         default:
    1472         311 :                 if (ZEND_NUM_ARGS() > 1) {
    1473           0 :                         pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Extraneous additional parameters");
    1474           0 :                         error = 1;
    1475             :                 }
    1476             :         }
    1477             : 
    1478         517 :         flags = how & PDO_FETCH_FLAGS;
    1479             : 
    1480         517 :         if ((how & ~PDO_FETCH_FLAGS) == PDO_FETCH_USE_DEFAULT) {
    1481          71 :                 flags |= stmt->default_fetch_type & PDO_FETCH_FLAGS;
    1482          71 :                 how |= stmt->default_fetch_type & ~PDO_FETCH_FLAGS;
    1483             :         }
    1484             : 
    1485         517 :         if (!error)     {
    1486         510 :                 PDO_STMT_CLEAR_ERR();
    1487        1020 :                 if ((how & PDO_FETCH_GROUP) || how == PDO_FETCH_KEY_PAIR ||
    1488         374 :                         (how == PDO_FETCH_USE_DEFAULT && stmt->default_fetch_type == PDO_FETCH_KEY_PAIR)
    1489             :                 ) {
    1490         136 :                         array_init(return_value);
    1491         136 :                         return_all = return_value;
    1492             :                 } else {
    1493         374 :                         return_all = 0;
    1494             :                 }
    1495         510 :                 if (!do_fetch(stmt, 1, &data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all)) {
    1496          26 :                         error = 2;
    1497             :                 }
    1498             :         }
    1499         517 :         if (!error) {
    1500         484 :                 if ((how & PDO_FETCH_GROUP)) {
    1501         324 :                         while (do_fetch(stmt, 1, &data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all));
    1502         384 :                 } else if (how == PDO_FETCH_KEY_PAIR || (how == PDO_FETCH_USE_DEFAULT && stmt->default_fetch_type == PDO_FETCH_KEY_PAIR)) {
    1503          90 :                         while (do_fetch(stmt, 1, &data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all));
    1504             :                 } else {
    1505         348 :                         array_init(return_value);
    1506             :                         do {
    1507         729 :                                 zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &data);
    1508         729 :                         } while (do_fetch(stmt, 1, &data, how | flags, PDO_FETCH_ORI_NEXT, 0, 0));
    1509             :                 }
    1510             :         }
    1511             : 
    1512         517 :         do_fetch_opt_finish(stmt, 0);
    1513             : 
    1514         517 :         stmt->fetch.cls.ce = old_ce;
    1515         517 :         ZVAL_COPY_VALUE(&stmt->fetch.cls.ctor_args, &old_ctor_args);
    1516         517 :         stmt->fetch.cls.fci.param_count = old_arg_count;
    1517             : 
    1518         517 :         if (error) {
    1519          33 :                 PDO_HANDLE_STMT_ERR();
    1520          33 :                 if (error != 2) {
    1521           7 :                         RETURN_FALSE;
    1522             :                 } else { /* on no results, return an empty array */
    1523          26 :                         if (Z_TYPE_P(return_value) != IS_ARRAY) {
    1524          26 :                                 array_init(return_value);
    1525             :                         }
    1526          26 :                         return;
    1527             :                 }
    1528             :         }
    1529             : }
    1530             : /* }}} */
    1531             : 
    1532       30634 : static int register_bound_param(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int is_param) /* {{{ */
    1533             : {
    1534             :         struct pdo_bound_param_data param;
    1535       30634 :         zend_long param_type = PDO_PARAM_STR;
    1536       30634 :         zval *parameter, *driver_params = NULL;
    1537             : 
    1538       30634 :         memset(&param, 0, sizeof(param));
    1539       30634 :         param.paramno = -1;
    1540             : 
    1541       30634 :         if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(),
    1542             :                         "lz|llz!", &param.paramno, &parameter, &param_type, &param.max_value_len,
    1543             :                         &driver_params)) {
    1544       30193 :                 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "Sz|llz!", &param.name,
    1545             :                                 &parameter, &param_type, &param.max_value_len,
    1546             :                                 &driver_params)) {
    1547           0 :                         return 0;
    1548             :                 }
    1549             :         }
    1550             : 
    1551       30634 :         param.param_type = (int) param_type;
    1552             : 
    1553       30634 :         if (param.paramno > 0) {
    1554         441 :                 --param.paramno; /* make it zero-based internally */
    1555       30193 :         } else if (!param.name) {
    1556           0 :                 pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "Columns/Parameters are 1-based");
    1557           0 :                 return 0;
    1558             :         }
    1559             : 
    1560       30634 :         if (driver_params) {
    1561           0 :                 ZVAL_COPY(&param.driver_params, driver_params);
    1562             :         }
    1563             : 
    1564       30634 :         ZVAL_COPY(&param.parameter, parameter);
    1565       30634 :         if (!really_register_bound_param(&param, stmt, is_param)) {
    1566           1 :                 if (!Z_ISUNDEF(param.parameter)) {
    1567           1 :                         zval_ptr_dtor(&(param.parameter));
    1568             :                 }
    1569           1 :                 return 0;
    1570             :         }
    1571       30633 :         return 1;
    1572             : } /* }}} */
    1573             : 
    1574             : /* {{{ proto bool PDOStatement::bindValue(mixed $paramno, mixed $param [, int $type ])
    1575             :    bind an input parameter to the value of a PHP variable.  $paramno is the 1-based position of the placeholder in the SQL statement (but can be the parameter name for drivers that support named placeholders).  It should be called prior to execute(). */
    1576         281 : static PHP_METHOD(PDOStatement, bindValue)
    1577             : {
    1578             :         struct pdo_bound_param_data param;
    1579         281 :         zend_long param_type = PDO_PARAM_STR;
    1580             :         zval *parameter;
    1581         562 :         PHP_STMT_GET_OBJ;
    1582             : 
    1583         281 :         memset(&param, 0, sizeof(param));
    1584         281 :         param.paramno = -1;
    1585             : 
    1586         281 :         if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(),
    1587             :                         "lz/|l", &param.paramno, &parameter, &param_type)) {
    1588          29 :                 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "Sz/|l", &param.name,
    1589             :                                 &parameter, &param_type)) {
    1590           0 :                         RETURN_FALSE;
    1591             :                 }
    1592             :         }
    1593             : 
    1594         281 :         param.param_type = (int) param_type;
    1595             : 
    1596         281 :         if (param.paramno > 0) {
    1597         252 :                 --param.paramno; /* make it zero-based internally */
    1598          29 :         } else if (!param.name) {
    1599           0 :                 pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "Columns/Parameters are 1-based");
    1600           0 :                 RETURN_FALSE;
    1601             :         }
    1602             : 
    1603         281 :         ZVAL_COPY(&param.parameter, parameter);
    1604         281 :         if (!really_register_bound_param(&param, stmt, TRUE)) {
    1605           1 :                 if (!Z_ISUNDEF(param.parameter)) {
    1606           1 :                         zval_ptr_dtor(&(param.parameter));
    1607           1 :                         ZVAL_UNDEF(&param.parameter);
    1608             :                 }
    1609           1 :                 RETURN_FALSE;
    1610             :         }
    1611         280 :         RETURN_TRUE;
    1612             : }
    1613             : /* }}} */
    1614             : 
    1615             : /* {{{ proto bool PDOStatement::bindParam(mixed $paramno, mixed &$param [, int $type [, int $maxlen [, mixed $driverdata]]])
    1616             :    bind a parameter to a PHP variable.  $paramno is the 1-based position of the placeholder in the SQL statement (but can be the parameter name for drivers that support named placeholders).  This isn't supported by all drivers.  It should be called prior to execute(). */
    1617       30219 : static PHP_METHOD(PDOStatement, bindParam)
    1618             : {
    1619       60438 :         PHP_STMT_GET_OBJ;
    1620       30219 :         RETURN_BOOL(register_bound_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, TRUE));
    1621             : }
    1622             : /* }}} */
    1623             : 
    1624             : /* {{{ proto bool PDOStatement::bindColumn(mixed $column, mixed &$param [, int $type [, int $maxlen [, mixed $driverdata]]])
    1625             :    bind a column to a PHP variable.  On each row fetch $param will contain the value of the corresponding column.  $column is the 1-based offset of the column, or the column name.  For portability, don't call this before execute(). */
    1626         415 : static PHP_METHOD(PDOStatement, bindColumn)
    1627             : {
    1628         830 :         PHP_STMT_GET_OBJ;
    1629         415 :         RETURN_BOOL(register_bound_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, 0));
    1630             : }
    1631             : /* }}} */
    1632             : 
    1633             : /* {{{ proto int PDOStatement::rowCount()
    1634             :    Returns the number of rows in a result set, or the number of rows affected by the last execute().  It is not always meaningful. */
    1635          12 : static PHP_METHOD(PDOStatement, rowCount)
    1636             : {
    1637          24 :         PHP_STMT_GET_OBJ;
    1638             : 
    1639          12 :         RETURN_LONG(stmt->row_count);
    1640             : }
    1641             : /* }}} */
    1642             : 
    1643             : /* {{{ proto string PDOStatement::errorCode()
    1644             :    Fetch the error code associated with the last operation on the statement handle */
    1645          31 : static PHP_METHOD(PDOStatement, errorCode)
    1646             : {
    1647          62 :         PHP_STMT_GET_OBJ;
    1648             : 
    1649          31 :         if (zend_parse_parameters_none() == FAILURE) {
    1650           0 :                 return;
    1651             :         }
    1652             : 
    1653          31 :         if (stmt->error_code[0] == '\0') {
    1654           0 :                 RETURN_NULL();
    1655             :         }
    1656             : 
    1657          62 :         RETURN_STRING(stmt->error_code);
    1658             : }
    1659             : /* }}} */
    1660             : 
    1661             : /* {{{ proto array PDOStatement::errorInfo()
    1662             :    Fetch extended error information associated with the last operation on the statement handle */
    1663          56 : static PHP_METHOD(PDOStatement, errorInfo)
    1664             : {
    1665             :         int error_count;
    1666          56 :         int error_count_diff     = 0;
    1667          56 :         int error_expected_count = 3;
    1668             : 
    1669         112 :         PHP_STMT_GET_OBJ;
    1670             : 
    1671          56 :         if (zend_parse_parameters_none() == FAILURE) {
    1672           0 :                 return;
    1673             :         }
    1674             : 
    1675          56 :         array_init(return_value);
    1676          56 :         add_next_index_string(return_value, stmt->error_code);
    1677             : 
    1678          56 :         if (stmt->dbh->methods->fetch_err) {
    1679          56 :                 stmt->dbh->methods->fetch_err(stmt->dbh, stmt, return_value);
    1680             :         }
    1681             : 
    1682          56 :         error_count = zend_hash_num_elements(Z_ARRVAL_P(return_value));
    1683             : 
    1684          56 :         if (error_expected_count > error_count) {
    1685             :                 int current_index;
    1686             : 
    1687          34 :                 error_count_diff = error_expected_count - error_count;
    1688         102 :                 for (current_index = 0; current_index < error_count_diff; current_index++) {
    1689          68 :                         add_next_index_null(return_value);
    1690             :                 }
    1691             :         }
    1692             : }
    1693             : /* }}} */
    1694             : 
    1695             : /* {{{ proto bool PDOStatement::setAttribute(long attribute, mixed value)
    1696             :    Set an attribute */
    1697           2 : static PHP_METHOD(PDOStatement, setAttribute)
    1698             : {
    1699             :         zend_long attr;
    1700           2 :         zval *value = NULL;
    1701           4 :         PHP_STMT_GET_OBJ;
    1702             : 
    1703           2 :         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "lz!", &attr, &value)) {
    1704           0 :                 RETURN_FALSE;
    1705             :         }
    1706             : 
    1707           2 :         if (!stmt->methods->set_attribute) {
    1708           1 :                 goto fail;
    1709             :         }
    1710             : 
    1711           1 :         PDO_STMT_CLEAR_ERR();
    1712           1 :         if (stmt->methods->set_attribute(stmt, attr, value)) {
    1713           1 :                 RETURN_TRUE;
    1714             :         }
    1715             : 
    1716             : fail:
    1717           1 :         if (!stmt->methods->set_attribute) {
    1718           1 :                 pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "This driver doesn't support setting attributes");
    1719             :         } else {
    1720           0 :                 PDO_HANDLE_STMT_ERR();
    1721             :         }
    1722           1 :         RETURN_FALSE;
    1723             : }
    1724             : /* }}} */
    1725             : 
    1726             : /* {{{ proto mixed PDOStatement::getAttribute(long attribute)
    1727             :    Get an attribute */
    1728             : 
    1729           0 : static int generic_stmt_attr_get(pdo_stmt_t *stmt, zval *return_value, zend_long attr)
    1730             : {
    1731           0 :         switch (attr) {
    1732             :                 case PDO_ATTR_EMULATE_PREPARES:
    1733           0 :                         RETVAL_BOOL(stmt->supports_placeholders == PDO_PLACEHOLDER_NONE);
    1734           0 :                         return 1;
    1735             :         }
    1736           0 :         return 0;
    1737             : }
    1738             : 
    1739           0 : static PHP_METHOD(PDOStatement, getAttribute)
    1740             : {
    1741             :         zend_long attr;
    1742           0 :         PHP_STMT_GET_OBJ;
    1743             : 
    1744           0 :         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "l", &attr)) {
    1745           0 :                 RETURN_FALSE;
    1746             :         }
    1747             : 
    1748           0 :         if (!stmt->methods->get_attribute) {
    1749           0 :                 if (!generic_stmt_attr_get(stmt, return_value, attr)) {
    1750           0 :                         pdo_raise_impl_error(stmt->dbh, stmt, "IM001",
    1751             :                                 "This driver doesn't support getting attributes");
    1752           0 :                         RETURN_FALSE;
    1753             :                 }
    1754           0 :                 return;
    1755             :         }
    1756             : 
    1757           0 :         PDO_STMT_CLEAR_ERR();
    1758           0 :         switch (stmt->methods->get_attribute(stmt, attr, return_value)) {
    1759             :                 case -1:
    1760           0 :                         PDO_HANDLE_STMT_ERR();
    1761           0 :                         RETURN_FALSE;
    1762             : 
    1763             :                 case 0:
    1764           0 :                         if (!generic_stmt_attr_get(stmt, return_value, attr)) {
    1765             :                                 /* XXX: should do something better here */
    1766           0 :                                 pdo_raise_impl_error(stmt->dbh, stmt, "IM001",
    1767             :                                         "driver doesn't support getting that attribute");
    1768           0 :                                 RETURN_FALSE;
    1769             :                         }
    1770           0 :                         return;
    1771             : 
    1772             :                 default:
    1773           0 :                         return;
    1774             :         }
    1775             : }
    1776             : /* }}} */
    1777             : 
    1778             : /* {{{ proto int PDOStatement::columnCount()
    1779             :    Returns the number of columns in the result set */
    1780          32 : static PHP_METHOD(PDOStatement, columnCount)
    1781             : {
    1782          64 :         PHP_STMT_GET_OBJ;
    1783          32 :         if (zend_parse_parameters_none() == FAILURE) {
    1784           0 :                 return;
    1785             :         }
    1786          32 :         RETURN_LONG(stmt->column_count);
    1787             : }
    1788             : /* }}} */
    1789             : 
    1790             : /* {{{ proto array PDOStatement::getColumnMeta(int $column)
    1791             :    Returns meta data for a numbered column */
    1792          88 : static PHP_METHOD(PDOStatement, getColumnMeta)
    1793             : {
    1794             :         zend_long colno;
    1795             :         struct pdo_column_data *col;
    1796         176 :         PHP_STMT_GET_OBJ;
    1797             : 
    1798          88 :         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "l", &colno)) {
    1799           3 :                 RETURN_FALSE;
    1800             :         }
    1801          85 :         if(colno < 0) {
    1802           1 :                 pdo_raise_impl_error(stmt->dbh, stmt, "42P10", "column number must be non-negative");
    1803           1 :                 RETURN_FALSE;
    1804             :         }
    1805             : 
    1806          84 :         if (!stmt->methods->get_column_meta) {
    1807           0 :                 pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "driver doesn't support meta data");
    1808           0 :                 RETURN_FALSE;
    1809             :         }
    1810             : 
    1811          84 :         PDO_STMT_CLEAR_ERR();
    1812          84 :         if (FAILURE == stmt->methods->get_column_meta(stmt, colno, return_value)) {
    1813           3 :                 PDO_HANDLE_STMT_ERR();
    1814           3 :                 RETURN_FALSE;
    1815             :         }
    1816             : 
    1817             :         /* add stock items */
    1818          81 :         col = &stmt->columns[colno];
    1819         162 :         add_assoc_str(return_value, "name", zend_string_copy(col->name));
    1820          81 :         add_assoc_long(return_value, "len", col->maxlen); /* FIXME: unsigned ? */
    1821          81 :         add_assoc_long(return_value, "precision", col->precision);
    1822          81 :         if (col->param_type != PDO_PARAM_ZVAL) {
    1823             :                 /* if param_type is PDO_PARAM_ZVAL the driver has to provide correct data */
    1824          15 :                 add_assoc_long(return_value, "pdo_type", col->param_type);
    1825             :         }
    1826             : }
    1827             : /* }}} */
    1828             : 
    1829             : /* {{{ proto bool PDOStatement::setFetchMode(int mode [mixed* params])
    1830             :    Changes the default fetch mode for subsequent fetches (params have different meaning for different fetch modes) */
    1831             : 
    1832         149 : int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int skip)
    1833             : {
    1834         149 :         zend_long mode = PDO_FETCH_BOTH;
    1835         149 :         int flags = 0, argc = ZEND_NUM_ARGS() - skip;
    1836             :         zval *args;
    1837             :         zend_class_entry *cep;
    1838             :         int retval;
    1839             : 
    1840         149 :         do_fetch_opt_finish(stmt, 1);
    1841             : 
    1842         149 :         switch (stmt->default_fetch_type) {
    1843             :                 case PDO_FETCH_INTO:
    1844          30 :                         if (!Z_ISUNDEF(stmt->fetch.into)) {
    1845           0 :                                 zval_ptr_dtor(&stmt->fetch.into);
    1846           0 :                                 ZVAL_UNDEF(&stmt->fetch.into);
    1847             :                         }
    1848             :                         break;
    1849             :                 default:
    1850             :                         ;
    1851             :         }
    1852             : 
    1853         149 :         stmt->default_fetch_type = PDO_FETCH_BOTH;
    1854             : 
    1855         149 :         if (argc == 0) {
    1856           0 :                 return SUCCESS;
    1857             :         }
    1858             : 
    1859         149 :         args = safe_emalloc(ZEND_NUM_ARGS(), sizeof(zval), 0);
    1860             : 
    1861         149 :         retval = zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args);
    1862             : 
    1863         149 :         if (SUCCESS == retval) {
    1864         298 :                 if (Z_TYPE(args[skip]) != IS_LONG) {
    1865           6 :                         pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "mode must be an integer");
    1866           6 :                         retval = FAILURE;
    1867             :                 } else {
    1868         143 :                         mode = Z_LVAL(args[skip]);
    1869         143 :                         flags = mode & PDO_FETCH_FLAGS;
    1870             : 
    1871         143 :                         retval = pdo_stmt_verify_mode(stmt, mode, 0);
    1872             :                 }
    1873             :         }
    1874             : 
    1875         149 :         if (FAILURE == retval) {
    1876           6 :                 PDO_STMT_CLEAR_ERR();
    1877           6 :                 efree(args);
    1878           6 :                 return FAILURE;
    1879             :         }
    1880             : 
    1881         143 :         retval = FAILURE;
    1882         143 :         switch (mode & ~PDO_FETCH_FLAGS) {
    1883             :                 case PDO_FETCH_USE_DEFAULT:
    1884             :                 case PDO_FETCH_LAZY:
    1885             :                 case PDO_FETCH_ASSOC:
    1886             :                 case PDO_FETCH_NUM:
    1887             :                 case PDO_FETCH_BOTH:
    1888             :                 case PDO_FETCH_OBJ:
    1889             :                 case PDO_FETCH_BOUND:
    1890             :                 case PDO_FETCH_NAMED:
    1891             :                 case PDO_FETCH_KEY_PAIR:
    1892          60 :                         if (argc != 1) {
    1893           6 :                                 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode doesn't allow any extra arguments");
    1894             :                         } else {
    1895          54 :                                 retval = SUCCESS;
    1896             :                         }
    1897          60 :                         break;
    1898             : 
    1899             :                 case PDO_FETCH_COLUMN:
    1900           6 :                         if (argc != 2) {
    1901           6 :                                 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the colno argument");
    1902           0 :                         } else  if (Z_TYPE(args[skip+1]) != IS_LONG) {
    1903           0 :                                 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "colno must be an integer");
    1904             :                         } else {
    1905           0 :                                 stmt->fetch.column = Z_LVAL(args[skip+1]);
    1906           0 :                                 retval = SUCCESS;
    1907             :                         }
    1908           6 :                         break;
    1909             : 
    1910             :                 case PDO_FETCH_CLASS:
    1911             :                         /* Gets its class name from 1st column */
    1912          49 :                         if ((flags & PDO_FETCH_CLASSTYPE) == PDO_FETCH_CLASSTYPE) {
    1913           1 :                                 if (argc != 1) {
    1914           0 :                                         pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode doesn't allow any extra arguments");
    1915             :                                 } else {
    1916           1 :                                         stmt->fetch.cls.ce = NULL;
    1917           1 :                                         retval = SUCCESS;
    1918             :                                 }
    1919             :                         } else {
    1920          48 :                                 if (argc < 2) {
    1921           6 :                                         pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the classname argument");
    1922          42 :                                 } else if (argc > 3) {
    1923           6 :                                         pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "too many arguments");
    1924          72 :                                 } else if (Z_TYPE(args[skip+1]) != IS_STRING) {
    1925           0 :                                         pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "classname must be a string");
    1926             :                                 } else {
    1927          36 :                                         cep = zend_lookup_class(Z_STR(args[skip+1]));
    1928          36 :                                         if (cep) {
    1929          36 :                                                 retval = SUCCESS;
    1930          36 :                                                 stmt->fetch.cls.ce = cep;
    1931             :                                         }
    1932             :                                 }
    1933             :                         }
    1934             : 
    1935          49 :                         if (SUCCESS == retval) {
    1936          37 :                                 ZVAL_UNDEF(&stmt->fetch.cls.ctor_args);
    1937             : #ifdef ilia_0 /* we'll only need this when we have persistent statements, if ever */
    1938             :                                 if (stmt->dbh->is_persistent) {
    1939             :                                         php_error_docref(NULL, E_WARNING, "PHP might crash if you don't call $stmt->setFetchMode() to reset to defaults on this persistent statement.  This will be fixed in a later release");
    1940             :                                 }
    1941             : #endif
    1942          37 :                                 if (argc == 3) {
    1943          63 :                                         if (Z_TYPE(args[skip+2]) != IS_NULL && Z_TYPE(args[skip+2]) != IS_ARRAY) {
    1944           0 :                                                 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array");
    1945           0 :                                                 retval = FAILURE;
    1946          42 :                                         } else if (Z_TYPE(args[skip+2]) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL(args[skip+2]))) {
    1947          21 :                                                 ZVAL_DUP(&stmt->fetch.cls.ctor_args, &args[skip+2]);
    1948             :                                         }
    1949             :                                 }
    1950             : 
    1951          37 :                                 if (SUCCESS == retval) {
    1952          37 :                                         do_fetch_class_prepare(stmt);
    1953             :                                 }
    1954             :                         }
    1955             : 
    1956          49 :                         break;
    1957             : 
    1958             :                 case PDO_FETCH_INTO:
    1959          28 :                         if (argc != 2) {
    1960           6 :                                 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the object parameter");
    1961          44 :                         } else if (Z_TYPE(args[skip+1]) != IS_OBJECT) {
    1962           0 :                                 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "object must be an object");
    1963             :                         } else {
    1964          22 :                                 retval = SUCCESS;
    1965             :                         }
    1966             : 
    1967          28 :                         if (SUCCESS == retval) {
    1968             : #ifdef ilia_0 /* we'll only need this when we have persistent statements, if ever */
    1969             :                                 if (stmt->dbh->is_persistent) {
    1970             :                                         php_error_docref(NULL, E_WARNING, "PHP might crash if you don't call $stmt->setFetchMode() to reset to defaults on this persistent statement.  This will be fixed in a later release");
    1971             :                                 }
    1972             : #endif
    1973          22 :                                 ZVAL_COPY(&stmt->fetch.into, &args[skip+1]);
    1974             :                         }
    1975             : 
    1976          28 :                         break;
    1977             : 
    1978             :                 default:
    1979           0 :                         pdo_raise_impl_error(stmt->dbh, stmt, "22003", "Invalid fetch mode specified");
    1980             :         }
    1981             : 
    1982         143 :         if (SUCCESS == retval) {
    1983         113 :                 stmt->default_fetch_type = mode;
    1984             :         }
    1985             : 
    1986             :         /*
    1987             :          * PDO error (if any) has already been raised at this point.
    1988             :          *
    1989             :          * The error_code is cleared, otherwise the caller will read the
    1990             :          * last error message from the driver.
    1991             :          *
    1992             :          */
    1993         143 :         PDO_STMT_CLEAR_ERR();
    1994             : 
    1995         143 :         efree(args);
    1996             : 
    1997         143 :         return retval;
    1998             : }
    1999             : 
    2000          71 : static PHP_METHOD(PDOStatement, setFetchMode)
    2001             : {
    2002         142 :         PHP_STMT_GET_OBJ;
    2003             : 
    2004          71 :         RETVAL_BOOL(
    2005             :                 pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAM_PASSTHRU,
    2006             :                         stmt, 0) == SUCCESS ? 1 : 0
    2007             :                 );
    2008             : }
    2009             : /* }}} */
    2010             : 
    2011             : /* {{{ proto bool PDOStatement::nextRowset()
    2012             :    Advances to the next rowset in a multi-rowset statement handle. Returns true if it succeeded, false otherwise */
    2013             : 
    2014         106 : static int pdo_stmt_do_next_rowset(pdo_stmt_t *stmt)
    2015             : {
    2016             :         /* un-describe */
    2017         106 :         if (stmt->columns) {
    2018             :                 int i;
    2019          96 :                 struct pdo_column_data *cols = stmt->columns;
    2020             : 
    2021         202 :                 for (i = 0; i < stmt->column_count; i++) {
    2022         106 :                         zend_string_release(cols[i].name);
    2023             :                 }
    2024          96 :                 efree(stmt->columns);
    2025          96 :                 stmt->columns = NULL;
    2026          96 :                 stmt->column_count = 0;
    2027             :         }
    2028             : 
    2029         106 :         if (!stmt->methods->next_rowset(stmt)) {
    2030             :                 /* Set the executed flag to 0 to reallocate columns on next execute */
    2031          78 :                 stmt->executed = 0;
    2032          78 :                 return 0;
    2033             :         }
    2034             : 
    2035          28 :         pdo_stmt_describe_columns(stmt);
    2036             : 
    2037          28 :         return 1;
    2038             : }
    2039             : 
    2040          79 : static PHP_METHOD(PDOStatement, nextRowset)
    2041             : {
    2042         158 :         PHP_STMT_GET_OBJ;
    2043             : 
    2044          79 :         if (!stmt->methods->next_rowset) {
    2045           0 :                 pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "driver does not support multiple rowsets");
    2046           0 :                 RETURN_FALSE;
    2047             :         }
    2048             : 
    2049          79 :         PDO_STMT_CLEAR_ERR();
    2050             : 
    2051          79 :         if (!pdo_stmt_do_next_rowset(stmt)) {
    2052          51 :                 PDO_HANDLE_STMT_ERR();
    2053          51 :                 RETURN_FALSE;
    2054             :         }
    2055             : 
    2056          28 :         RETURN_TRUE;
    2057             : }
    2058             : /* }}} */
    2059             : 
    2060             : /* {{{ proto bool PDOStatement::closeCursor()
    2061             :    Closes the cursor, leaving the statement ready for re-execution. */
    2062        1431 : static PHP_METHOD(PDOStatement, closeCursor)
    2063             : {
    2064        2862 :         PHP_STMT_GET_OBJ;
    2065             : 
    2066        1431 :         if (!stmt->methods->cursor_closer) {
    2067             :                 /* emulate it by fetching and discarding rows */
    2068             :                 do {
    2069          32 :                         while (stmt->methods->fetcher(stmt, PDO_FETCH_ORI_NEXT, 0))
    2070             :                                 ;
    2071          30 :                         if (!stmt->methods->next_rowset) {
    2072           3 :                                 break;
    2073             :                         }
    2074             : 
    2075          27 :                         if (!pdo_stmt_do_next_rowset(stmt)) {
    2076          27 :                                 break;
    2077             :                         }
    2078             : 
    2079           0 :                 } while (1);
    2080          30 :                 stmt->executed = 0;
    2081          30 :                 RETURN_TRUE;
    2082             :         }
    2083             : 
    2084        1401 :         PDO_STMT_CLEAR_ERR();
    2085             : 
    2086        1401 :         if (!stmt->methods->cursor_closer(stmt)) {
    2087           0 :                 PDO_HANDLE_STMT_ERR();
    2088           0 :                 RETURN_FALSE;
    2089             :         }
    2090        1401 :         stmt->executed = 0;
    2091        1401 :         RETURN_TRUE;
    2092             : }
    2093             : /* }}} */
    2094             : 
    2095             : /* {{{ proto void PDOStatement::debugDumpParams()
    2096             :    A utility for internals hackers to debug parameter internals */
    2097           1 : static PHP_METHOD(PDOStatement, debugDumpParams)
    2098             : {
    2099           1 :         php_stream *out = php_stream_open_wrapper("php://output", "w", 0, NULL);
    2100             :         struct pdo_bound_param_data *param;
    2101           2 :         PHP_STMT_GET_OBJ;
    2102             : 
    2103           1 :         if (out == NULL) {
    2104           0 :                 RETURN_FALSE;
    2105             :         }
    2106             : 
    2107           1 :         php_stream_printf(out, "SQL: [%zd] %.*s\n",
    2108             :                 stmt->query_stringlen,
    2109             :                 (int) stmt->query_stringlen, stmt->query_string);
    2110             : 
    2111           2 :         php_stream_printf(out, "Params:  %d\n",
    2112           2 :                 stmt->bound_params ? zend_hash_num_elements(stmt->bound_params) : 0);
    2113             : 
    2114           1 :         if (stmt->bound_params) {
    2115             :                 zend_ulong num;
    2116           1 :                 zend_string *key = NULL;
    2117           7 :                 ZEND_HASH_FOREACH_KEY_PTR(stmt->bound_params, num, key, param) {
    2118           3 :                         if (key) {
    2119           2 :                                 php_stream_printf(out, "Key: Name: [%zd] %.*s\n",
    2120             :                                         ZSTR_LEN(key), (int) ZSTR_LEN(key), ZSTR_VAL(key));
    2121             :                         } else {
    2122           1 :                                 php_stream_printf(out, "Key: Position #" ZEND_ULONG_FMT ":\n", num);
    2123             :                         }
    2124             : 
    2125          18 :                         php_stream_printf(out, "paramno=%pd\nname=[%zd] \"%.*s\"\nis_param=%d\nparam_type=%d\n",
    2126          10 :                                                         param->paramno, param->name ? ZSTR_LEN(param->name) : 0, param->name ? (int) ZSTR_LEN(param->name) : 0,
    2127           5 :                                                         param->name ? ZSTR_VAL(param->name) : "",
    2128             :                                                         param->is_param,
    2129           3 :                                                         param->param_type);
    2130             : 
    2131             :                 } ZEND_HASH_FOREACH_END();
    2132             :         }
    2133             : 
    2134           1 :         php_stream_close(out);
    2135             : }
    2136             : /* }}} */
    2137             : 
    2138             : /* {{{ proto int PDOStatement::__wakeup()
    2139             :    Prevents use of a PDOStatement instance that has been unserialized */
    2140           0 : static PHP_METHOD(PDOStatement, __wakeup)
    2141             : {
    2142           0 :         zend_throw_exception_ex(php_pdo_get_exception(), 0, "You cannot serialize or unserialize PDOStatement instances");
    2143           0 : }
    2144             : /* }}} */
    2145             : 
    2146             : /* {{{ proto int PDOStatement::__sleep()
    2147             :    Prevents serialization of a PDOStatement instance */
    2148           0 : static PHP_METHOD(PDOStatement, __sleep)
    2149             : {
    2150           0 :         zend_throw_exception_ex(php_pdo_get_exception(), 0, "You cannot serialize or unserialize PDOStatement instances");
    2151           0 : }
    2152             : /* }}} */
    2153             : 
    2154             : const zend_function_entry pdo_dbstmt_functions[] = {
    2155             :         PHP_ME(PDOStatement, execute,           arginfo_pdostatement_execute,           ZEND_ACC_PUBLIC)
    2156             :         PHP_ME(PDOStatement, fetch,                     arginfo_pdostatement_fetch,                     ZEND_ACC_PUBLIC)
    2157             :         PHP_ME(PDOStatement, bindParam,         arginfo_pdostatement_bindparam,         ZEND_ACC_PUBLIC)
    2158             :         PHP_ME(PDOStatement, bindColumn,        arginfo_pdostatement_bindcolumn,        ZEND_ACC_PUBLIC)
    2159             :         PHP_ME(PDOStatement, bindValue,         arginfo_pdostatement_bindvalue,         ZEND_ACC_PUBLIC)
    2160             :         PHP_ME(PDOStatement, rowCount,          arginfo_pdostatement__void,                     ZEND_ACC_PUBLIC)
    2161             :         PHP_ME(PDOStatement, fetchColumn,       arginfo_pdostatement_fetchcolumn,       ZEND_ACC_PUBLIC)
    2162             :         PHP_ME(PDOStatement, fetchAll,          arginfo_pdostatement_fetchall,          ZEND_ACC_PUBLIC)
    2163             :         PHP_ME(PDOStatement, fetchObject,       arginfo_pdostatement_fetchobject,       ZEND_ACC_PUBLIC)
    2164             :         PHP_ME(PDOStatement, errorCode,         arginfo_pdostatement__void,                     ZEND_ACC_PUBLIC)
    2165             :         PHP_ME(PDOStatement, errorInfo,         arginfo_pdostatement__void,                     ZEND_ACC_PUBLIC)
    2166             :         PHP_ME(PDOStatement, setAttribute,      arginfo_pdostatement_setattribute,      ZEND_ACC_PUBLIC)
    2167             :         PHP_ME(PDOStatement, getAttribute,      arginfo_pdostatement_getattribute,      ZEND_ACC_PUBLIC)
    2168             :         PHP_ME(PDOStatement, columnCount,       arginfo_pdostatement__void,                     ZEND_ACC_PUBLIC)
    2169             :         PHP_ME(PDOStatement, getColumnMeta,     arginfo_pdostatement_getcolumnmeta,     ZEND_ACC_PUBLIC)
    2170             :         PHP_ME(PDOStatement, setFetchMode,      arginfo_pdostatement_setfetchmode,      ZEND_ACC_PUBLIC)
    2171             :         PHP_ME(PDOStatement, nextRowset,        arginfo_pdostatement__void,                     ZEND_ACC_PUBLIC)
    2172             :         PHP_ME(PDOStatement, closeCursor,       arginfo_pdostatement__void,                     ZEND_ACC_PUBLIC)
    2173             :         PHP_ME(PDOStatement, debugDumpParams, arginfo_pdostatement__void,               ZEND_ACC_PUBLIC)
    2174             :         PHP_ME(PDOStatement, __wakeup,          arginfo_pdostatement__void,                     ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
    2175             :         PHP_ME(PDOStatement, __sleep,           arginfo_pdostatement__void,                     ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
    2176             :         PHP_FE_END
    2177             : };
    2178             : 
    2179             : /* {{{ overloaded handlers for PDOStatement class */
    2180          37 : static void dbstmt_prop_write(zval *object, zval *member, zval *value, void **cache_slot)
    2181             : {
    2182          37 :         pdo_stmt_t *stmt = Z_PDO_STMT_P(object);
    2183             : 
    2184          37 :         convert_to_string(member);
    2185             : 
    2186          37 :         if (strcmp(Z_STRVAL_P(member), "queryString") == 0) {
    2187           0 :                 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "property queryString is read only");
    2188             :         } else {
    2189          37 :                 std_object_handlers.write_property(object, member, value, cache_slot);
    2190             :         }
    2191          37 : }
    2192             : 
    2193           0 : static void dbstmt_prop_delete(zval *object, zval *member, void **cache_slot)
    2194             : {
    2195           0 :         pdo_stmt_t *stmt = Z_PDO_STMT_P(object);
    2196             : 
    2197           0 :         convert_to_string(member);
    2198             : 
    2199           0 :         if (strcmp(Z_STRVAL_P(member), "queryString") == 0) {
    2200           0 :                 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "property queryString is read only");
    2201             :         } else {
    2202           0 :                 std_object_handlers.unset_property(object, member, cache_slot);
    2203             :         }
    2204           0 : }
    2205             : 
    2206        2367 : static union _zend_function *dbstmt_method_get(zend_object **object_pp, zend_string *method_name, const zval *key)
    2207             : {
    2208        2367 :         zend_function *fbc = NULL;
    2209             :         zend_string *lc_method_name;
    2210        2367 :         zend_object *object = *object_pp;
    2211             : 
    2212        4734 :         lc_method_name = zend_string_alloc(ZSTR_LEN(method_name), 0);
    2213        2367 :         zend_str_tolower_copy(ZSTR_VAL(lc_method_name), ZSTR_VAL(method_name), ZSTR_LEN(method_name));
    2214             : 
    2215             : 
    2216        4734 :         if ((fbc = zend_hash_find_ptr(&object->ce->function_table, lc_method_name)) == NULL) {
    2217          27 :                 pdo_stmt_t *stmt = php_pdo_stmt_fetch_object(object);
    2218             :                 /* instance not created by PDO object */
    2219          27 :                 if (!stmt->dbh) {
    2220          14 :                         goto out;
    2221             :                 }
    2222             :                 /* not a pre-defined method, nor a user-defined method; check
    2223             :                  * the driver specific methods */
    2224          13 :                 if (!stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT]) {
    2225          13 :                         if (!pdo_hash_methods(Z_PDO_OBJECT_P(&stmt->database_object_handle),
    2226             :                                 PDO_DBH_DRIVER_METHOD_KIND_STMT)
    2227           0 :                                 || !stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT]) {
    2228             :                                 goto out;
    2229             :                         }
    2230             :                 }
    2231             : 
    2232           0 :                 if ((fbc = zend_hash_find_ptr(stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT], lc_method_name)) == NULL) {
    2233             :                         goto out;
    2234             :                 }
    2235             :                 /* got it */
    2236             :         }
    2237             : 
    2238             : out:
    2239             :         zend_string_release(lc_method_name);
    2240        2367 :         if (!fbc) {
    2241          27 :                 fbc = std_object_handlers.get_method(object_pp, method_name, key);
    2242             :         }
    2243        2367 :         return fbc;
    2244             : }
    2245             : 
    2246           0 : static int dbstmt_compare(zval *object1, zval *object2)
    2247             : {
    2248           0 :         return -1;
    2249             : }
    2250             : 
    2251           0 : static zend_object *dbstmt_clone_obj(zval *zobject)
    2252             : {
    2253             :         pdo_stmt_t *stmt;
    2254             :         pdo_stmt_t *old_stmt;
    2255             : 
    2256           0 :         stmt = ecalloc(1, sizeof(pdo_stmt_t) + zend_object_properties_size(Z_OBJCE_P(zobject)));
    2257           0 :         zend_object_std_init(&stmt->std, Z_OBJCE_P(zobject));
    2258           0 :         object_properties_init(&stmt->std, Z_OBJCE_P(zobject));
    2259             : 
    2260           0 :         old_stmt = Z_PDO_STMT_P(zobject);
    2261             : 
    2262           0 :         zend_objects_clone_members(&stmt->std, &old_stmt->std);
    2263             : 
    2264           0 :         return &stmt->std;
    2265             : }
    2266             : 
    2267             : zend_object_handlers pdo_dbstmt_object_handlers;
    2268             : static int pdo_row_serialize(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data);
    2269             : 
    2270       23950 : void pdo_stmt_init(void)
    2271             : {
    2272             :         zend_class_entry ce;
    2273             : 
    2274       23950 :         INIT_CLASS_ENTRY(ce, "PDOStatement", pdo_dbstmt_functions);
    2275       23950 :         pdo_dbstmt_ce = zend_register_internal_class(&ce);
    2276       23950 :         pdo_dbstmt_ce->get_iterator = pdo_stmt_iter_get;
    2277       23950 :         pdo_dbstmt_ce->create_object = pdo_dbstmt_new;
    2278       23950 :         zend_class_implements(pdo_dbstmt_ce, 1, zend_ce_traversable);
    2279       23950 :         zend_declare_property_null(pdo_dbstmt_ce, "queryString", sizeof("queryString")-1, ZEND_ACC_PUBLIC);
    2280             : 
    2281       23950 :         memcpy(&pdo_dbstmt_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
    2282       23950 :         pdo_dbstmt_object_handlers.offset = XtOffsetOf(pdo_stmt_t, std);
    2283       23950 :         pdo_dbstmt_object_handlers.dtor_obj = zend_objects_destroy_object;
    2284       23950 :         pdo_dbstmt_object_handlers.free_obj = pdo_dbstmt_free_storage;
    2285       23950 :         pdo_dbstmt_object_handlers.write_property = dbstmt_prop_write;
    2286       23950 :         pdo_dbstmt_object_handlers.unset_property = dbstmt_prop_delete;
    2287       23950 :         pdo_dbstmt_object_handlers.get_method = dbstmt_method_get;
    2288       23950 :         pdo_dbstmt_object_handlers.compare_objects = dbstmt_compare;
    2289       23950 :         pdo_dbstmt_object_handlers.clone_obj = dbstmt_clone_obj;
    2290             : 
    2291       23950 :         INIT_CLASS_ENTRY(ce, "PDORow", pdo_row_functions);
    2292       23950 :         pdo_row_ce = zend_register_internal_class(&ce);
    2293       23950 :         pdo_row_ce->ce_flags |= ZEND_ACC_FINAL; /* when removing this a lot of handlers need to be redone */
    2294       23950 :         pdo_row_ce->create_object = pdo_row_new;
    2295       23950 :         pdo_row_ce->serialize = pdo_row_serialize;
    2296       23950 : }
    2297             : 
    2298       12348 : PDO_API void php_pdo_free_statement(pdo_stmt_t *stmt)
    2299             : {
    2300       12348 :         if (stmt->bound_params) {
    2301       10467 :                 zend_hash_destroy(stmt->bound_params);
    2302       10467 :                 FREE_HASHTABLE(stmt->bound_params);
    2303       10467 :                 stmt->bound_params = NULL;
    2304             :         }
    2305       12348 :         if (stmt->bound_param_map) {
    2306          87 :                 zend_hash_destroy(stmt->bound_param_map);
    2307          87 :                 FREE_HASHTABLE(stmt->bound_param_map);
    2308          87 :                 stmt->bound_param_map = NULL;
    2309             :         }
    2310       12348 :         if (stmt->bound_columns) {
    2311         194 :                 zend_hash_destroy(stmt->bound_columns);
    2312         194 :                 FREE_HASHTABLE(stmt->bound_columns);
    2313         194 :                 stmt->bound_columns = NULL;
    2314             :         }
    2315             : 
    2316       12348 :         if (stmt->methods && stmt->methods->dtor) {
    2317       12319 :                 stmt->methods->dtor(stmt);
    2318             :         }
    2319       12348 :         if (stmt->query_string) {
    2320       12326 :                 efree(stmt->query_string);
    2321             :         }
    2322             : 
    2323       12348 :         if (stmt->columns) {
    2324             :                 int i;
    2325       12144 :                 struct pdo_column_data *cols = stmt->columns;
    2326             : 
    2327       14651 :                 for (i = 0; i < stmt->column_count; i++) {
    2328        2507 :                         if (cols[i].name) {
    2329        2507 :                                 zend_string_release(cols[i].name);
    2330        2507 :                                 cols[i].name = NULL;
    2331             :                         }
    2332             :                 }
    2333       12144 :                 efree(stmt->columns);
    2334       12144 :                 stmt->columns = NULL;
    2335             :         }
    2336             : 
    2337       24696 :         if (!Z_ISUNDEF(stmt->fetch.into) && stmt->default_fetch_type == PDO_FETCH_INTO) {
    2338           7 :                 zval_ptr_dtor(&stmt->fetch.into);
    2339           7 :                 ZVAL_UNDEF(&stmt->fetch.into);
    2340             :         }
    2341             : 
    2342       12348 :         do_fetch_opt_finish(stmt, 1);
    2343             : 
    2344       24696 :         if (!Z_ISUNDEF(stmt->database_object_handle)) {
    2345       12252 :                 zval_ptr_dtor(&stmt->database_object_handle);
    2346             :         }
    2347       12348 :         zend_object_std_dtor(&stmt->std);
    2348       12348 : }
    2349             : 
    2350       12348 : void pdo_dbstmt_free_storage(zend_object *std)
    2351             : {
    2352       12348 :         pdo_stmt_t *stmt = php_pdo_stmt_fetch_object(std);
    2353       12348 :         php_pdo_free_statement(stmt);
    2354       12348 : }
    2355             : 
    2356       12364 : zend_object *pdo_dbstmt_new(zend_class_entry *ce)
    2357             : {
    2358             :         pdo_stmt_t *stmt;
    2359             : 
    2360       12364 :         stmt = ecalloc(1, sizeof(pdo_stmt_t) + zend_object_properties_size(ce));
    2361       12364 :         zend_object_std_init(&stmt->std, ce);
    2362       12364 :         object_properties_init(&stmt->std, ce);
    2363             : 
    2364       12364 :         stmt->std.handlers = &pdo_dbstmt_object_handlers;
    2365             : 
    2366       12364 :         return &stmt->std;
    2367             : }
    2368             : /* }}} */
    2369             : 
    2370             : /* {{{ statement iterator */
    2371             : 
    2372             : struct php_pdo_iterator {
    2373             :         zend_object_iterator iter;
    2374             :         zend_ulong key;
    2375             :         zval fetch_ahead;
    2376             : };
    2377             : 
    2378         106 : static void pdo_stmt_iter_dtor(zend_object_iterator *iter)
    2379             : {
    2380         106 :         struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter;
    2381             : 
    2382         106 :         zval_ptr_dtor(&I->iter.data);
    2383             : 
    2384         212 :         if (!Z_ISUNDEF(I->fetch_ahead)) {
    2385          25 :                 zval_ptr_dtor(&I->fetch_ahead);
    2386             :         }
    2387         106 : }
    2388             : 
    2389       10423 : static int pdo_stmt_iter_valid(zend_object_iterator *iter)
    2390             : {
    2391       10423 :         struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter;
    2392             : 
    2393       20846 :         return Z_ISUNDEF(I->fetch_ahead) ? FAILURE : SUCCESS;
    2394             : }
    2395             : 
    2396       10336 : static zval *pdo_stmt_iter_get_data(zend_object_iterator *iter)
    2397             : {
    2398       10336 :         struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter;
    2399             : 
    2400             :         /* sanity */
    2401       20672 :         if (Z_ISUNDEF(I->fetch_ahead)) {
    2402           0 :                 return NULL;
    2403             :         }
    2404             : 
    2405       10336 :         return &I->fetch_ahead;
    2406             : }
    2407             : 
    2408          25 : static void pdo_stmt_iter_get_key(zend_object_iterator *iter, zval *key)
    2409             : {
    2410          25 :         struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter;
    2411             : 
    2412          25 :         if (I->key == (ulong)-1) {
    2413           0 :                 ZVAL_NULL(key);
    2414             :         } else {
    2415          25 :                 ZVAL_LONG(key, I->key);
    2416             :         }
    2417          25 : }
    2418             : 
    2419       10323 : static void pdo_stmt_iter_move_forwards(zend_object_iterator *iter)
    2420             : {
    2421       10323 :         struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter;
    2422       10323 :         pdo_stmt_t *stmt = Z_PDO_STMT_P(&I->iter.data); /* for PDO_HANDLE_STMT_ERR() */
    2423             : 
    2424       20646 :         if (!Z_ISUNDEF(I->fetch_ahead)) {
    2425       10317 :                 zval_ptr_dtor(&I->fetch_ahead);
    2426             :         }
    2427             : 
    2428       10323 :         if (!do_fetch(stmt, TRUE, &I->fetch_ahead, PDO_FETCH_USE_DEFAULT,
    2429             :                         PDO_FETCH_ORI_NEXT, 0, 0)) {
    2430             : 
    2431          87 :                 PDO_HANDLE_STMT_ERR();
    2432          87 :                 I->key = (ulong)-1;
    2433          87 :                 ZVAL_UNDEF(&I->fetch_ahead);
    2434             : 
    2435          87 :                 return;
    2436             :         }
    2437             : 
    2438       10236 :         I->key++;
    2439             : }
    2440             : 
    2441             : static zend_object_iterator_funcs pdo_stmt_iter_funcs = {
    2442             :         pdo_stmt_iter_dtor,
    2443             :         pdo_stmt_iter_valid,
    2444             :         pdo_stmt_iter_get_data,
    2445             :         pdo_stmt_iter_get_key,
    2446             :         pdo_stmt_iter_move_forwards,
    2447             :         NULL,
    2448             :         NULL
    2449             : };
    2450             : 
    2451         106 : zend_object_iterator *pdo_stmt_iter_get(zend_class_entry *ce, zval *object, int by_ref)
    2452             : {
    2453         106 :         pdo_stmt_t *stmt = Z_PDO_STMT_P(object);
    2454             :         struct php_pdo_iterator *I;
    2455             : 
    2456         106 :         if (by_ref) {
    2457           0 :                 zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
    2458             :         }
    2459             : 
    2460         106 :         I = ecalloc(1, sizeof(struct php_pdo_iterator));
    2461         106 :         zend_iterator_init(&I->iter);
    2462         106 :         I->iter.funcs = &pdo_stmt_iter_funcs;
    2463         106 :         ZVAL_COPY(&I->iter.data, object);
    2464             : 
    2465         106 :         if (!do_fetch(stmt, 1, &I->fetch_ahead, PDO_FETCH_USE_DEFAULT,
    2466             :                         PDO_FETCH_ORI_NEXT, 0, 0)) {
    2467           0 :                 PDO_HANDLE_STMT_ERR();
    2468           0 :                 I->key = (ulong)-1;
    2469           0 :                 ZVAL_UNDEF(&I->fetch_ahead);
    2470             :         }
    2471             : 
    2472         106 :         return &I->iter;
    2473             : }
    2474             : 
    2475             : /* }}} */
    2476             : 
    2477             : /* {{{ overloaded handlers for PDORow class (used by PDO_FETCH_LAZY) */
    2478             : 
    2479             : const zend_function_entry pdo_row_functions[] = {
    2480             :         PHP_FE_END
    2481             : };
    2482             : 
    2483          34 : static zval *row_prop_read(zval *object, zval *member, int type, void **cache_slot, zval *rv)
    2484             : {
    2485          34 :         pdo_row_t *row = (pdo_row_t *)Z_OBJ_P(object);
    2486          34 :         pdo_stmt_t *stmt = row->stmt;
    2487          34 :         int colno = -1;
    2488             :         zval zobj;
    2489             :         zend_long lval;
    2490             : 
    2491          34 :         ZVAL_NULL(rv);
    2492          34 :         if (stmt) {
    2493          34 :                 if (Z_TYPE_P(member) == IS_LONG) {
    2494           1 :                         if (Z_LVAL_P(member) >= 0 && Z_LVAL_P(member) < stmt->column_count) {
    2495           0 :                                 fetch_value(stmt, rv, Z_LVAL_P(member), NULL);
    2496             :                         }
    2497          68 :                 } else if (Z_TYPE_P(member) == IS_STRING
    2498          33 :                            && is_numeric_string_ex(Z_STRVAL_P(member), Z_STRLEN_P(member), &lval, NULL, 0, NULL) == IS_LONG)        {
    2499           2 :                         if (lval >= 0 && lval < stmt->column_count) {
    2500           1 :                                 fetch_value(stmt, rv, lval, NULL);
    2501             :                         }
    2502             :                 } else {
    2503          31 :                         convert_to_string(member);
    2504             :                         /* TODO: replace this with a hash of available column names to column
    2505             :                          * numbers */
    2506          47 :                         for (colno = 0; colno < stmt->column_count; colno++) {
    2507          71 :                                 if (ZSTR_LEN(stmt->columns[colno].name) == Z_STRLEN_P(member) &&
    2508          28 :                                     strncmp(ZSTR_VAL(stmt->columns[colno].name), Z_STRVAL_P(member), Z_STRLEN_P(member)) == 0) {
    2509          27 :                                         fetch_value(stmt, rv, colno, NULL);
    2510          27 :                                         return rv;
    2511             :                                 }
    2512             :                         }
    2513           4 :                         if (strcmp(Z_STRVAL_P(member), "queryString") == 0) {
    2514           3 :                                 ZVAL_OBJ(&zobj, &stmt->std);
    2515             :                                 //zval_ptr_dtor(rv);
    2516           3 :                                 return std_object_handlers.read_property(&zobj, member, type, cache_slot, rv);
    2517             :                         }
    2518             :                 }
    2519             :         }
    2520             : 
    2521           4 :         return rv;
    2522             : }
    2523             : 
    2524           1 : static zval *row_dim_read(zval *object, zval *member, int type, zval *rv)
    2525             : {
    2526           1 :         return row_prop_read(object, member, type, NULL, rv);
    2527             : }
    2528             : 
    2529           0 : static void row_prop_write(zval *object, zval *member, zval *value, void **cache_slot)
    2530             : {
    2531           0 :         php_error_docref(NULL, E_WARNING, "This PDORow is not from a writable result set");
    2532           0 : }
    2533             : 
    2534           0 : static void row_dim_write(zval *object, zval *member, zval *value)
    2535             : {
    2536           0 :         php_error_docref(NULL, E_WARNING, "This PDORow is not from a writable result set");
    2537           0 : }
    2538             : 
    2539          32 : static int row_prop_exists(zval *object, zval *member, int check_empty, void **cache_slot)
    2540             : {
    2541          32 :         pdo_row_t *row = (pdo_row_t *)Z_OBJ_P(object);
    2542          32 :         pdo_stmt_t *stmt = row->stmt;
    2543          32 :         int colno = -1;
    2544             :         zend_long lval;
    2545             : 
    2546          32 :         if (stmt) {
    2547          32 :                 if (Z_TYPE_P(member) == IS_LONG) {
    2548           0 :                         return Z_LVAL_P(member) >= 0 && Z_LVAL_P(member) < stmt->column_count;
    2549          32 :                 } else if (Z_TYPE_P(member) == IS_STRING) {
    2550          64 :                         if (is_numeric_string_ex(Z_STRVAL_P(member), Z_STRLEN_P(member), &lval, NULL, 0, NULL) == IS_LONG)  {
    2551           0 :                                 return lval >=0 && lval < stmt->column_count;
    2552             :                         }
    2553             :                 } else {
    2554           0 :                         convert_to_string(member);
    2555             :                 }
    2556             : 
    2557             :                 /* TODO: replace this with a hash of available column names to column
    2558             :                  * numbers */
    2559          80 :                 for (colno = 0; colno < stmt->column_count; colno++) {
    2560          96 :                         if (ZSTR_LEN(stmt->columns[colno].name) == Z_STRLEN_P(member) &&
    2561          24 :                             strncmp(ZSTR_VAL(stmt->columns[colno].name), Z_STRVAL_P(member), Z_STRLEN_P(member)) == 0) {
    2562             :                                         int res;
    2563             :                                         zval val;
    2564             : 
    2565          24 :                                         fetch_value(stmt, &val, colno, NULL TSRMLS_CC);
    2566          48 :                                         res = check_empty ? i_zend_is_true(&val) : Z_TYPE(val) != IS_NULL;
    2567             :                                         zval_dtor(&val);
    2568             : 
    2569          24 :                                         return res;
    2570             :                         }
    2571             :                 }
    2572             :         }
    2573             : 
    2574           8 :         return 0;
    2575             : }
    2576             : 
    2577           0 : static int row_dim_exists(zval *object, zval *member, int check_empty)
    2578             : {
    2579           0 :         return row_prop_exists(object, member, check_empty, NULL);
    2580             : }
    2581             : 
    2582           0 : static void row_prop_delete(zval *object, zval *offset, void **cache_slot)
    2583             : {
    2584           0 :         php_error_docref(NULL, E_WARNING, "Cannot delete properties from a PDORow");
    2585           0 : }
    2586             : 
    2587           0 : static void row_dim_delete(zval *object, zval *offset)
    2588             : {
    2589           0 :         php_error_docref(NULL, E_WARNING, "Cannot delete properties from a PDORow");
    2590           0 : }
    2591             : 
    2592           4 : static HashTable *row_get_properties(zval *object)
    2593             : {
    2594           4 :         pdo_row_t *row = (pdo_row_t *)Z_OBJ_P(object);
    2595           4 :         pdo_stmt_t *stmt = row->stmt;
    2596             :         int i;
    2597             : 
    2598           4 :         if (stmt == NULL) {
    2599           0 :                 return NULL;
    2600             :         }
    2601             : 
    2602           4 :         if (!stmt->std.properties) {
    2603           3 :                 rebuild_object_properties(&stmt->std);
    2604             :         }
    2605           8 :         for (i = 0; i < stmt->column_count; i++) {
    2606             :                 zval val;
    2607           4 :                 fetch_value(stmt, &val, i, NULL);
    2608             : 
    2609           4 :                 zend_hash_update(stmt->std.properties, stmt->columns[i].name, &val);
    2610             :         }
    2611             : 
    2612           4 :         return stmt->std.properties;
    2613             : }
    2614             : 
    2615           0 : static union _zend_function *row_method_get(
    2616             :         zend_object **object_pp,
    2617             :         zend_string *method_name, const zval *key)
    2618             : {
    2619             :         zend_function *fbc;
    2620             :         zend_string *lc_method_name;
    2621             : 
    2622           0 :         lc_method_name = zend_string_alloc(ZSTR_LEN(method_name), 0);
    2623           0 :         zend_str_tolower_copy(ZSTR_VAL(lc_method_name), ZSTR_VAL(method_name), ZSTR_LEN(method_name));
    2624             : 
    2625           0 :         if ((fbc = zend_hash_find_ptr(&pdo_row_ce->function_table, lc_method_name)) == NULL) {
    2626             :                 zend_string_release(lc_method_name);
    2627           0 :                 return NULL;
    2628             :         }
    2629             : 
    2630             :         zend_string_release(lc_method_name);
    2631             : 
    2632           0 :         return fbc;
    2633             : }
    2634             : 
    2635           0 : static int row_call_method(zend_string *method, zend_object *object, INTERNAL_FUNCTION_PARAMETERS)
    2636             : {
    2637           0 :         return FAILURE;
    2638             : }
    2639             : 
    2640          16 : static union _zend_function *row_get_ctor(zend_object *object)
    2641             : {
    2642          16 :         zend_throw_exception_ex(php_pdo_get_exception(), 0, "You may not create a PDORow manually");
    2643          16 :         return NULL;
    2644             : }
    2645             : 
    2646           4 : static zend_string *row_get_classname(const zend_object *object)
    2647             : {
    2648           4 :         return zend_string_init("PDORow", sizeof("PDORow") - 1, 0);
    2649             : }
    2650             : 
    2651           0 : static int row_compare(zval *object1, zval *object2)
    2652             : {
    2653           0 :         return -1;
    2654             : }
    2655             : 
    2656             : zend_object_handlers pdo_row_object_handlers = {
    2657             :         0,
    2658             :         zend_objects_destroy_object,
    2659             :         pdo_row_free_storage,
    2660             :         NULL,
    2661             :         row_prop_read,
    2662             :         row_prop_write,
    2663             :         row_dim_read,
    2664             :         row_dim_write,
    2665             :         NULL,
    2666             :         NULL,
    2667             :         NULL,
    2668             :         row_prop_exists,
    2669             :         row_prop_delete,
    2670             :         row_dim_exists,
    2671             :         row_dim_delete,
    2672             :         row_get_properties,
    2673             :         row_method_get,
    2674             :         row_call_method,
    2675             :         row_get_ctor,
    2676             :         row_get_classname,
    2677             :         row_compare,
    2678             :         NULL, /* cast */
    2679             :         NULL,
    2680             :         NULL,
    2681             :         NULL,
    2682             :         NULL,
    2683             :         NULL,
    2684             :         NULL
    2685             : };
    2686             : 
    2687          38 : void pdo_row_free_storage(zend_object *std)
    2688             : {
    2689          38 :         pdo_row_t *row = (pdo_row_t *)std;
    2690          38 :         if (row->stmt) {
    2691          22 :                 ZVAL_UNDEF(&row->stmt->lazy_object_ref);
    2692          22 :                 OBJ_RELEASE(&row->stmt->std);
    2693             :         }
    2694          38 : }
    2695             : 
    2696          16 : zend_object *pdo_row_new(zend_class_entry *ce)
    2697             : {
    2698          16 :         pdo_row_t *row = ecalloc(1, sizeof(pdo_row_t));
    2699          16 :         zend_object_std_init(&row->std, ce);
    2700          16 :         row->std.handlers = &pdo_row_object_handlers;
    2701             : 
    2702          16 :         return &row->std;
    2703             : }
    2704             : 
    2705           0 : static int pdo_row_serialize(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data)
    2706             : {
    2707           0 :         php_error_docref(NULL, E_WARNING, "PDORow instances may not be serialized");
    2708           0 :         return FAILURE;
    2709             : }
    2710             : /* }}} */
    2711             : 
    2712             : /*
    2713             :  * Local variables:
    2714             :  * tab-width: 4
    2715             :  * c-basic-offset: 4
    2716             :  * End:
    2717             :  * vim600: noet sw=4 ts=4 fdm=marker
    2718             :  * vim<600: noet sw=4 ts=4
    2719             :  */

Generated by: LCOV version 1.10

Generated at Tue, 27 Sep 2016 10:26:03 +0000 (18 hours ago)

Copyright © 2005-2016 The PHP Group
All rights reserved.