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: 1003 1240 80.9 %
Date: 2016-07-26 Functions: 54 71 76.1 %
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       46299 : static inline int rewrite_name_to_position(pdo_stmt_t *stmt, struct pdo_bound_param_data *param) /* {{{ */
     117             : {
     118       46299 :         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        4864 :                 int position = 0;
     127             : 
     128        4864 :                 if (stmt->named_rewrite_template) {
     129             :                         /* this is not an error here */
     130        4522 :                         return 1;
     131             :                 }
     132         342 :                 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         691 :                 ZEND_HASH_FOREACH_PTR(stmt->bound_param_map, name) {
     143         295 :                         if (strncmp(name, ZSTR_VAL(param->name), ZSTR_LEN(param->name) + 1)) {
     144         136 :                                 position++;
     145         136 :                                 continue;
     146             :                         }
     147         159 :                         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         159 :                         param->paramno = position;
     152         159 :                         return 1;
     153             :                 } ZEND_HASH_FOREACH_END();
     154         101 :                 pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined");
     155         101 :                 return 0;
     156             :         }
     157       41435 :         return 1;
     158             : }
     159             : /* }}} */
     160             : 
     161             : /* trigger callback hook for parameters */
     162       51827 : static int dispatch_param_event(pdo_stmt_t *stmt, enum pdo_param_event event_type) /* {{{ */
     163             : {
     164       51827 :         int ret = 1, is_param = 1;
     165             :         struct pdo_bound_param_data *param;
     166             :         HashTable *ht;
     167             : 
     168       51827 :         if (!stmt->methods->param_hook) {
     169           0 :                 return 1;
     170             :         }
     171             : 
     172       51827 :         ht = stmt->bound_params;
     173             : 
     174             : iterate:
     175      103649 :         if (ht) {
     176      173567 :                 ZEND_HASH_FOREACH_PTR(ht, param) {
     177       73892 :                         if (!stmt->methods->param_hook(stmt, param, event_type)) {
     178           5 :                                 ret = 0;
     179           5 :                                 break;
     180             :                         }
     181             :                 } ZEND_HASH_FOREACH_END();
     182             :         }
     183      103649 :         if (ret && is_param) {
     184       51822 :                 ht = stmt->bound_columns;
     185       51822 :                 is_param = 0;
     186       51822 :                 goto iterate;
     187             :         }
     188             : 
     189       51827 :         return ret;
     190             : }
     191             : /* }}} */
     192             : 
     193       12369 : int pdo_stmt_describe_columns(pdo_stmt_t *stmt) /* {{{ */
     194             : {
     195             :         int col;
     196             : 
     197       12369 :         stmt->columns = ecalloc(stmt->column_count, sizeof(struct pdo_column_data));
     198             : 
     199       15113 :         for (col = 0; col < stmt->column_count; col++) {
     200        2744 :                 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        2744 :                 if (stmt->dbh->native_case != stmt->dbh->desired_case && stmt->dbh->desired_case != PDO_CASE_NATURAL) {
     206        2640 :                         char *s = ZSTR_VAL(stmt->columns[col].name);
     207             : 
     208        2640 :                         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       16192 :                                         while (*s != '\0') {
     217       10938 :                                                 *s = tolower(*s);
     218       10938 :                                                 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        2744 :                 if (stmt->bound_columns) {
     238             :                         struct pdo_bound_param_data *param;
     239             : 
     240          44 :                         if ((param = zend_hash_find_ptr(stmt->bound_columns,
     241          22 :                                         stmt->columns[col].name)) != NULL) {
     242          21 :                                 param->paramno = col;
     243             :                         }
     244             :                 }
     245             : 
     246             :         }
     247       12369 :         return 1;
     248             : }
     249             : /* }}} */
     250             : 
     251          23 : static void get_lazy_object(pdo_stmt_t *stmt, zval *return_value) /* {{{ */
     252             : {
     253          46 :         if (Z_ISUNDEF(stmt->lazy_object_ref)) {
     254          17 :                 pdo_row_t *row = ecalloc(1, sizeof(pdo_row_t));
     255          17 :                 row->stmt = stmt;
     256          17 :                 zend_object_std_init(&row->std, pdo_row_ce);
     257          17 :                 ZVAL_OBJ(&stmt->lazy_object_ref, &row->std);
     258          17 :                 row->std.handlers = &pdo_row_object_handlers;
     259          17 :                 GC_REFCOUNT(&stmt->std)++;
     260          17 :                 GC_REFCOUNT(&row->std)--;
     261             :         }
     262          23 :         ZVAL_COPY(return_value, &stmt->lazy_object_ref);
     263          23 : }
     264             : /* }}} */
     265             : 
     266       46608 : static void param_dtor(zval *el) /* {{{ */
     267             : {
     268       46608 :         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       46608 :         if (param->stmt->methods->param_hook) {
     272       46608 :                         param->stmt->methods->param_hook(param->stmt, param, PDO_PARAM_EVT_FREE);
     273             :         }
     274             : 
     275       46608 :         if (param->name) {
     276       39617 :                 zend_string_release(param->name);
     277             :         }
     278             : 
     279       93216 :         if (!Z_ISUNDEF(param->parameter)) {
     280       46608 :                 zval_ptr_dtor(&param->parameter);
     281       46608 :                 ZVAL_UNDEF(&param->parameter);
     282             :         }
     283       93216 :         if (!Z_ISUNDEF(param->driver_params)) {
     284           0 :                 zval_ptr_dtor(&param->driver_params);
     285             :         }
     286       46608 :         efree(param);
     287       46608 : }
     288             : /* }}} */
     289             : 
     290       46712 : 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       46712 :         struct pdo_bound_param_data *pparam = NULL;
     295             : 
     296       46712 :         hash = is_param ? stmt->bound_params : stmt->bound_columns;
     297             : 
     298       46712 :         if (!hash) {
     299       12294 :                 ALLOC_HASHTABLE(hash);
     300       12294 :                 zend_hash_init(hash, 13, NULL, param_dtor, 0);
     301             : 
     302       12294 :                 if (is_param) {
     303       12101 :                         stmt->bound_params = hash;
     304             :                 } else {
     305         193 :                         stmt->bound_columns = hash;
     306             :                 }
     307             :         }
     308             : 
     309       93424 :         if (!Z_ISREF(param->parameter)) {
     310       16059 :                 parameter = &param->parameter;
     311             :         } else {
     312       30653 :                 parameter = Z_REFVAL(param->parameter);
     313             :         }
     314             : 
     315       99517 :         if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_STR && param->max_value_len <= 0 && !Z_ISNULL_P(parameter)) {
     316       26222 :                 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       26199 :                         convert_to_string(parameter);
     323             :                 }
     324       20632 :         } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_INT && (Z_TYPE_P(parameter) == IS_FALSE || Z_TYPE_P(parameter) == IS_TRUE)) {
     325           7 :                 convert_to_long(parameter);
     326       20493 :         } 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       46712 :         param->stmt = stmt;
     331       46712 :         param->is_param = is_param;
     332             : 
     333       46712 :         if (Z_REFCOUNTED(param->driver_params)) {
     334           0 :                 Z_ADDREF(param->driver_params);
     335             :         }
     336             : 
     337       46712 :         if (!is_param && param->name && stmt->columns) {
     338             :                 /* try to map the name to the column */
     339             :                 int i;
     340             : 
     341         137 :                 for (i = 0; i < stmt->column_count; i++) {
     342         272 :                         if (ZSTR_LEN(stmt->columns[i].name) == ZSTR_LEN(param->name) &&
     343         135 :                             strncmp(ZSTR_VAL(stmt->columns[i].name), ZSTR_VAL(param->name), ZSTR_LEN(param->name) + 1) == 0) {
     344         108 :                                 param->paramno = i;
     345         108 :                                 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         108 :                 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       46712 :         if (param->name) {
     360       48691 :                 if (is_param && ZSTR_VAL(param->name)[0] != ':') {
     361       18104 :                         zend_string *temp = zend_string_alloc(ZSTR_LEN(param->name) + 1, 0);
     362        9052 :                         ZSTR_VAL(temp)[0] = ':';
     363        9052 :                         memmove(ZSTR_VAL(temp) + 1, ZSTR_VAL(param->name), ZSTR_LEN(param->name) + 1);
     364        9052 :                         param->name = temp;
     365             :                 } else {
     366       61174 :                         param->name = zend_string_init(ZSTR_VAL(param->name), ZSTR_LEN(param->name), 0);
     367             :                 }
     368             :         }
     369             : 
     370       46712 :         if (is_param && !rewrite_name_to_position(stmt, param)) {
     371         101 :                 if (param->name) {
     372         101 :                         zend_string_release(param->name);
     373         101 :                         param->name = NULL;
     374             :                 }
     375         101 :                 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       46611 :         if (stmt->methods->param_hook) {
     383       46611 :                 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       46608 :         if (param->paramno >= 0) {
     397       11449 :                 zend_hash_index_del(hash, param->paramno);
     398             :         }
     399             : 
     400             :         /* allocate storage for the parameter, keyed by its "canonical" name */
     401       46608 :         if (param->name) {
     402       79234 :                 pparam = zend_hash_update_mem(hash, param->name, param, sizeof(struct pdo_bound_param_data));
     403             :         } else {
     404       13982 :                 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       46608 :         if (stmt->methods->param_hook) {
     409       46608 :                 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         106 :                         if (pparam->name) {
     414           3 :                                 zend_hash_del(hash, pparam->name);
     415             :                         } else {
     416         103 :                                 zend_hash_index_del(hash, pparam->paramno);
     417             :                         }
     418             :                         /* param->parameter is freed by hash dtor */
     419         106 :                         ZVAL_UNDEF(&param->parameter);
     420         106 :                         return 0;
     421             :                 }
     422             :         }
     423       46502 :         return 1;
     424             : }
     425             : /* }}} */
     426             : 
     427             : /* {{{ proto bool PDOStatement::execute([array $bound_input_params])
     428             :    Execute a prepared statement, optionally binding parameters */
     429       13565 : static PHP_METHOD(PDOStatement, execute)
     430             : {
     431       13565 :         zval *input_params = NULL;
     432       13565 :         int ret = 1;
     433       27130 :         PHP_STMT_GET_OBJ;
     434             : 
     435       13565 :         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!", &input_params)) {
     436           0 :                 RETURN_FALSE;
     437             :         }
     438             : 
     439       13565 :         PDO_STMT_CLEAR_ERR();
     440             : 
     441       13565 :         if (input_params) {
     442             :                 struct pdo_bound_param_data param;
     443             :                 zval *tmp;
     444        1809 :                 zend_string *key = NULL;
     445             :                 zend_ulong num_index;
     446             : 
     447        1809 :                 if (stmt->bound_params) {
     448        1159 :                         zend_hash_destroy(stmt->bound_params);
     449        1159 :                         FREE_HASHTABLE(stmt->bound_params);
     450        1159 :                         stmt->bound_params = NULL;
     451             :                 }
     452             : 
     453       33181 :                 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(input_params), num_index, key, tmp) {
     454       15778 :                         memset(&param, 0, sizeof(param));
     455             : 
     456       15778 :                         if (key) {
     457             :                                 /* yes this is correct.  we don't want to count the null byte.  ask wez */
     458        9399 :                                 param.name = key;
     459        9399 :                                 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        6379 :                                 param.paramno = num_index;
     469             :                         }
     470             : 
     471       15778 :                         param.param_type = PDO_PARAM_STR;
     472       15778 :                         ZVAL_COPY(&param.parameter, tmp);
     473             : 
     474       15778 :                         if (!really_register_bound_param(&param, stmt, 1)) {
     475         208 :                                 if (!Z_ISUNDEF(param.parameter)) {
     476         102 :                                         zval_ptr_dtor(&param.parameter);
     477             :                                 }
     478         208 :                                 RETURN_FALSE;
     479             :                         }
     480             :                 } ZEND_HASH_FOREACH_END();
     481             :         }
     482             : 
     483       13357 :         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         725 :                 ret = pdo_parse_params(stmt, stmt->query_string, stmt->query_stringlen,
     490             :                         &stmt->active_query_string, &stmt->active_query_stringlen);
     491             : 
     492         725 :                 if (ret == 0) {
     493             :                         /* no changes were made */
     494         267 :                         stmt->active_query_string = stmt->query_string;
     495         267 :                         stmt->active_query_stringlen = stmt->query_stringlen;
     496         267 :                         ret = 1;
     497         458 :                 } else if (ret == -1) {
     498             :                         /* something broke */
     499         204 :                         PDO_HANDLE_STMT_ERR();
     500         204 :                         RETURN_FALSE;
     501             :                 }
     502       12632 :         } else if (!dispatch_param_event(stmt, PDO_PARAM_EVT_EXEC_PRE)) {
     503           5 :                 PDO_HANDLE_STMT_ERR();
     504           5 :                 RETURN_FALSE;
     505             :         }
     506       13148 :         if (stmt->methods->executer(stmt)) {
     507       13113 :                 if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
     508         248 :                         efree(stmt->active_query_string);
     509             :                 }
     510       13113 :                 stmt->active_query_string = NULL;
     511       13113 :                 if (!stmt->executed) {
     512             :                         /* this is the first execute */
     513             : 
     514       12726 :                         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       11524 :                                 ret = pdo_stmt_describe_columns(stmt);
     518             :                         }
     519             : 
     520       12726 :                         stmt->executed = 1;
     521             :                 }
     522             : 
     523       13113 :                 if (ret && !dispatch_param_event(stmt, PDO_PARAM_EVT_EXEC_POST)) {
     524           0 :                         RETURN_FALSE;
     525             :                 }
     526             : 
     527       13113 :                 RETURN_BOOL(ret);
     528             :         }
     529          35 :         if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
     530           6 :                 efree(stmt->active_query_string);
     531             :         }
     532          35 :         stmt->active_query_string = NULL;
     533          35 :         PDO_HANDLE_STMT_ERR();
     534          35 :         RETURN_FALSE;
     535             : }
     536             : /* }}} */
     537             : 
     538       25365 : static inline void fetch_value(pdo_stmt_t *stmt, zval *dest, int colno, int *type_override) /* {{{ */
     539             : {
     540             :         struct pdo_column_data *col;
     541       25365 :         char *value = NULL;
     542       25365 :         size_t value_len = 0;
     543       25365 :         int caller_frees = 0;
     544             :         int type, new_type;
     545             : 
     546       25365 :         col = &stmt->columns[colno];
     547       25365 :         type = PDO_PARAM_TYPE(col->param_type);
     548       25365 :         new_type =  type_override ? (int)PDO_PARAM_TYPE(*type_override) : type;
     549             : 
     550       25365 :         value = NULL;
     551       25365 :         value_len = 0;
     552             : 
     553       25365 :         stmt->methods->get_col(stmt, colno, &value, &value_len, &caller_frees);
     554             : 
     555       25365 :         switch (type) {
     556             :                 case PDO_PARAM_ZVAL:
     557        2122 :                         if (value && value_len == sizeof(zval)) {
     558        1061 :                                 ZVAL_COPY_VALUE(dest, (zval *)value);
     559             :                         } else {
     560           0 :                                 ZVAL_NULL(dest);
     561             :                         }
     562             : 
     563        1061 :                         if (Z_TYPE_P(dest) == IS_NULL) {
     564          12 :                                 type = new_type;
     565             :                         }
     566        1061 :                         break;
     567             : 
     568             :                 case PDO_PARAM_INT:
     569         250 :                         if (value && value_len == sizeof(zend_long)) {
     570         232 :                                 ZVAL_LONG(dest, *(zend_long*)value);
     571         232 :                                 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        4000 :                         if (value && !(value_len == 0 && stmt->dbh->oracle_nulls == PDO_NULL_EMPTY_STRING)) {
     627        7828 :                                 ZVAL_STRINGL(dest, value, value_len);
     628        3914 :                                 break;
     629             :                         }
     630             :                 default:
     631          86 :                         ZVAL_NULL(dest);
     632             :         }
     633             : 
     634       25365 :         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       25365 :         if (caller_frees && value) {
     654           1 :                 efree(value);
     655             :         }
     656             : 
     657       25365 :         if (stmt->dbh->stringify) {
     658        3475 :                 switch (Z_TYPE_P(dest)) {
     659             :                         case IS_LONG:
     660             :                         case IS_DOUBLE:
     661         320 :                                 convert_to_string(dest);
     662             :                                 break;
     663             :                 }
     664             :         }
     665             : 
     666       25365 :         if (Z_TYPE_P(dest) == IS_NULL && stmt->dbh->oracle_nulls == PDO_NULL_TO_STRING) {
     667           2 :                 ZVAL_EMPTY_STRING(dest);
     668             :         }
     669       25365 : }
     670             : /* }}} */
     671             : 
     672       13426 : static int do_fetch_common(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori, zend_long offset, int do_bind) /* {{{ */
     673             : {
     674       13426 :         if (!stmt->executed) {
     675          15 :                 return 0;
     676             :         }
     677             : 
     678       13411 :         if (!dispatch_param_event(stmt, PDO_PARAM_EVT_FETCH_PRE)) {
     679           0 :                 return 0;
     680             :         }
     681             : 
     682       13411 :         if (!stmt->methods->fetcher(stmt, ori, offset)) {
     683         740 :                 return 0;
     684             :         }
     685             : 
     686             :         /* some drivers might need to describe the columns now */
     687       12671 :         if (!stmt->columns && !pdo_stmt_describe_columns(stmt)) {
     688           0 :                 return 0;
     689             :         }
     690             : 
     691       12671 :         if (!dispatch_param_event(stmt, PDO_PARAM_EVT_FETCH_POST)) {
     692           0 :                 return 0;
     693             :         }
     694             : 
     695       12671 :         if (do_bind && stmt->bound_columns) {
     696             :                 /* update those bound column variables now */
     697             :                 struct pdo_bound_param_data *param;
     698             : 
     699        2345 :                 ZEND_HASH_FOREACH_PTR(stmt->bound_columns, param) {
     700         897 :                         if (param->paramno >= 0) {
     701        1794 :                                 if (!Z_ISREF(param->parameter)) {
     702           0 :                                         continue;
     703             :                                 }
     704             : 
     705             :                                 /* delete old value */
     706         897 :                                 zval_ptr_dtor(Z_REFVAL(param->parameter));
     707             : 
     708             :                                 /* set new value */
     709         897 :                                 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       12671 :         return 1;
     720             : }
     721             : /* }}} */
     722             : 
     723         218 : static int do_fetch_class_prepare(pdo_stmt_t *stmt) /* {{{ */
     724             : {
     725         218 :         zend_class_entry *ce = stmt->fetch.cls.ce;
     726         218 :         zend_fcall_info *fci = &stmt->fetch.cls.fci;
     727         218 :         zend_fcall_info_cache *fcc = &stmt->fetch.cls.fcc;
     728             : 
     729         218 :         fci->size = sizeof(zend_fcall_info);
     730             : 
     731         218 :         if (!ce) {
     732           1 :                 stmt->fetch.cls.ce = ZEND_STANDARD_CLASS_DEF_PTR;
     733           1 :                 ce = ZEND_STANDARD_CLASS_DEF_PTR;
     734             :         }
     735             : 
     736         218 :         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         142 :         } 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          71 :                 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       14341 : 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       14341 :         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       14341 :         stmt->fetch.cls.fci.size = 0;
     812       28682 :         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       14341 :         if (stmt->fetch.func.values) {
     818          59 :                 efree(stmt->fetch.func.values);
     819          59 :                 stmt->fetch.func.values = NULL;
     820             :         }
     821       14341 : }
     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       13297 : 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       13297 :         int flags, idx, old_arg_count = 0;
     829       13297 :         zend_class_entry *ce = NULL, *old_ce = NULL;
     830             :         zval grp_val, *pgrp, retval, old_ctor_args;
     831             :         int colno;
     832             : 
     833       13297 :         if (how == PDO_FETCH_USE_DEFAULT) {
     834       10526 :                 how = stmt->default_fetch_type;
     835             :         }
     836       13297 :         flags = how & PDO_FETCH_FLAGS;
     837       13297 :         how = how & ~PDO_FETCH_FLAGS;
     838             : 
     839       13297 :         if (!do_fetch_common(stmt, ori, offset, do_bind)) {
     840         749 :                 return 0;
     841             :         }
     842             : 
     843       12548 :         if (how == PDO_FETCH_BOUND) {
     844         406 :                 RETVAL_TRUE;
     845         406 :                 return 1;
     846             :         }
     847             : 
     848       12262 :         if (flags & PDO_FETCH_GROUP && stmt->fetch.column == -1) {
     849         120 :                 colno = 1;
     850             :         } else {
     851       12022 :                 colno = stmt->fetch.column;
     852             :         }
     853             : 
     854       12142 :         if (return_value) {
     855       12142 :                 int i = 0;
     856             : 
     857       12142 :                 if (how == PDO_FETCH_LAZY) {
     858          23 :                         get_lazy_object(stmt, return_value);
     859          23 :                         return 1;
     860             :                 }
     861             : 
     862       12119 :                 RETVAL_FALSE;
     863             : 
     864       12119 :                 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       11304 :                                 if (!return_all) {
     871       11208 :                                         ZVAL_NEW_ARR(return_value);
     872       11208 :                                         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       11304 :                                 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         211 :                                 if (colno >= 0 && colno < stmt->column_count) {
     890         235 :                                         if (flags == PDO_FETCH_GROUP && stmt->fetch.column == -1) {
     891          24 :                                                 fetch_value(stmt, return_value, 1, NULL);
     892         187 :                                         } else if (flags == PDO_FETCH_GROUP && colno) {
     893           0 :                                                 fetch_value(stmt, return_value, 0, NULL);
     894             :                                         } else {
     895         187 :                                                 fetch_value(stmt, return_value, colno, NULL);
     896             :                                         }
     897         211 :                                         if (!return_all) {
     898          55 :                                                 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         246 :                                 if (flags & PDO_FETCH_CLASSTYPE) {
     913             :                                         zval val;
     914             :                                         zend_class_entry *cep;
     915             : 
     916         100 :                                         old_ce = stmt->fetch.cls.ce;
     917         100 :                                         ZVAL_COPY_VALUE(&old_ctor_args, &stmt->fetch.cls.ctor_args);
     918         100 :                                         old_arg_count = stmt->fetch.cls.fci.param_count;
     919         100 :                                         do_fetch_opt_finish(stmt, 0);
     920             : 
     921         100 :                                         fetch_value(stmt, &val, i++, NULL);
     922         100 :                                         if (Z_TYPE(val) != IS_NULL) {
     923          76 :                                                 convert_to_string(&val);
     924          76 :                                                 if ((cep = zend_lookup_class(Z_STR(val))) == NULL) {
     925           1 :                                                         stmt->fetch.cls.ce = ZEND_STANDARD_CLASS_DEF_PTR;
     926             :                                                 } else {
     927          75 :                                                         stmt->fetch.cls.ce = cep;
     928             :                                                 }
     929             :                                         }
     930             : 
     931         100 :                                         do_fetch_class_prepare(stmt);
     932             :                                         zval_dtor(&val);
     933             :                                 }
     934         246 :                                 ce = stmt->fetch.cls.ce;
     935         246 :                                 if (!ce) {
     936           6 :                                         pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch class specified");
     937           6 :                                         return 0;
     938             :                                 }
     939         240 :                                 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         240 :                                 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       12046 :                 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       35526 :                 for (idx = 0; i < stmt->column_count; i++, idx++) {
    1013             :                         zval val;
    1014       23582 :                         fetch_value(stmt, &val, i, NULL);
    1015             : 
    1016       23582 :                         switch (how) {
    1017             :                                 case PDO_FETCH_ASSOC:
    1018        1683 :                                         zend_symtable_update(Z_ARRVAL_P(return_value), stmt->columns[i].name, &val);
    1019        1683 :                                         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       20527 :                                         zend_symtable_update(Z_ARRVAL_P(return_value), stmt->columns[i].name, &val);
    1040       20527 :                                         if (Z_REFCOUNTED(val)) {
    1041             :                                                 Z_ADDREF(val);
    1042             :                                         }
    1043       20527 :                                         zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &val);
    1044       20527 :                                         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         277 :                                         zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &val);
    1082         277 :                                         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         956 :                                         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          34 :                                                 if (!ce->unserialize) {
    1111           6 :                                                         zval_ptr_dtor(&val);
    1112           6 :                                                         pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize class");
    1113           6 :                                                         return 0;
    1114          84 :                                                 } 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          28 :                                                         zval_ptr_dtor(&val);
    1122             :                                                 }
    1123             :                                         }
    1124         489 :                                         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       11944 :                 switch (how) {
    1140             :                         case PDO_FETCH_CLASS:
    1141         234 :                                 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         234 :                                 if (flags & PDO_FETCH_CLASSTYPE) {
    1154          94 :                                         do_fetch_opt_finish(stmt, 0);
    1155          94 :                                         stmt->fetch.cls.ce = old_ce;
    1156          94 :                                         ZVAL_COPY_VALUE(&stmt->fetch.cls.ctor_args, &old_ctor_args);
    1157          94 :                                         stmt->fetch.cls.fci.param_count = old_arg_count;
    1158             :                                 }
    1159         234 :                                 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       11944 :                 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       11944 :         return 1;
    1203             : }
    1204             : /* }}} */
    1205             : 
    1206        1823 : static int pdo_stmt_verify_mode(pdo_stmt_t *stmt, zend_long mode, int fetch_all) /* {{{ */
    1207             : {
    1208        1823 :         int flags = mode & PDO_FETCH_FLAGS;
    1209             : 
    1210        1823 :         mode = mode & ~PDO_FETCH_FLAGS;
    1211             : 
    1212        1823 :         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        1823 :         if (mode == PDO_FETCH_USE_DEFAULT) {
    1218         165 :                 flags = stmt->default_fetch_type & PDO_FETCH_FLAGS;
    1219         165 :                 mode = stmt->default_fetch_type & ~PDO_FETCH_FLAGS;
    1220             :         }
    1221             : 
    1222        1823 :         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          23 :                         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        1605 :                         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        1605 :                         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        1605 :                         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        1751 :                         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        1109 : static PHP_METHOD(PDOStatement, fetch)
    1260             : {
    1261        1109 :         zend_long how = PDO_FETCH_USE_DEFAULT;
    1262        1109 :         zend_long ori = PDO_FETCH_ORI_NEXT;
    1263        1109 :         zend_long off = 0;
    1264        2218 :     PHP_STMT_GET_OBJ;
    1265             : 
    1266        1109 :         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|lll", &how,
    1267             :                         &ori, &off)) {
    1268           0 :                 RETURN_FALSE;
    1269             :         }
    1270             : 
    1271        1109 :         PDO_STMT_CLEAR_ERR();
    1272             : 
    1273        1109 :         if (!pdo_stmt_verify_mode(stmt, how, 0)) {
    1274           0 :                 RETURN_FALSE;
    1275             :         }
    1276             : 
    1277        1109 :         if (!do_fetch(stmt, TRUE, return_value, how, ori, off, 0)) {
    1278         128 :                 PDO_HANDLE_STMT_ERR();
    1279         128 :                 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         129 : static PHP_METHOD(PDOStatement, fetchColumn)
    1352             : {
    1353         129 :         zend_long col_n = 0;
    1354         258 :         PHP_STMT_GET_OBJ;
    1355             : 
    1356         129 :         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &col_n)) {
    1357           0 :                 RETURN_FALSE;
    1358             :         }
    1359             : 
    1360         129 :         PDO_STMT_CLEAR_ERR();
    1361             : 
    1362         129 :         if (!do_fetch_common(stmt, PDO_FETCH_ORI_NEXT, 0, TRUE)) {
    1363           6 :                 PDO_HANDLE_STMT_ERR();
    1364           6 :                 RETURN_FALSE;
    1365             :         }
    1366             : 
    1367         123 :         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         564 : static PHP_METHOD(PDOStatement, fetchAll)
    1374             : {
    1375         564 :         zend_long how = PDO_FETCH_USE_DEFAULT;
    1376             :         zval data, *return_all;
    1377             :         zval *arg2;
    1378             :         zend_class_entry *old_ce;
    1379         564 :         zval old_ctor_args, *ctor_args = NULL;
    1380         564 :         int error = 0, flags, old_arg_count;
    1381        1128 :         PHP_STMT_GET_OBJ;
    1382             : 
    1383         564 :         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|lzz", &how, &arg2, &ctor_args)) {
    1384           0 :                 RETURN_FALSE;
    1385             :         }
    1386             : 
    1387         564 :         if (!pdo_stmt_verify_mode(stmt, how, 1)) {
    1388           0 :                 RETURN_FALSE;
    1389             :         }
    1390             : 
    1391         564 :         old_ce = stmt->fetch.cls.ce;
    1392         564 :         ZVAL_COPY_VALUE(&old_ctor_args, &stmt->fetch.cls.ctor_args);
    1393         564 :         old_arg_count = stmt->fetch.cls.fci.param_count;
    1394             : 
    1395         564 :         do_fetch_opt_finish(stmt, 0);
    1396             : 
    1397         564 :         switch(how & ~PDO_FETCH_FLAGS) {
    1398             :         case PDO_FETCH_CLASS:
    1399          63 :                 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          57 :                         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          38 :                         if (Z_TYPE_P(ctor_args) != IS_ARRAY || !zend_hash_num_elements(Z_ARRVAL_P(ctor_args))) {
    1411           6 :                                 ctor_args = NULL;
    1412             :                         }
    1413             :                         /* no break */
    1414             :                 case 2:
    1415          57 :                         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          44 :                                 ZVAL_UNDEF(&stmt->fetch.cls.ctor_args);
    1419             :                         }
    1420         114 :                         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          57 :                                 stmt->fetch.cls.ce = zend_fetch_class(Z_STR_P(arg2), ZEND_FETCH_CLASS_AUTO);
    1426          57 :                                 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          63 :                 if (!error) {
    1434          63 :                         do_fetch_class_prepare(stmt);
    1435             :                 }
    1436          63 :                 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          83 :                 switch(ZEND_NUM_ARGS()) {
    1457             :                 case 0:
    1458             :                 case 1:
    1459          59 :                         stmt->fetch.column = how & PDO_FETCH_GROUP ? -1 : 0;
    1460          59 :                         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          83 :                 break;
    1470             : 
    1471             :         default:
    1472         352 :                 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         564 :         flags = how & PDO_FETCH_FLAGS;
    1479             : 
    1480         564 :         if ((how & ~PDO_FETCH_FLAGS) == PDO_FETCH_USE_DEFAULT) {
    1481          68 :                 flags |= stmt->default_fetch_type & PDO_FETCH_FLAGS;
    1482          68 :                 how |= stmt->default_fetch_type & ~PDO_FETCH_FLAGS;
    1483             :         }
    1484             : 
    1485         564 :         if (!error)     {
    1486         557 :                 PDO_STMT_CLEAR_ERR();
    1487        1114 :                 if ((how & PDO_FETCH_GROUP) || how == PDO_FETCH_KEY_PAIR ||
    1488         421 :                         (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         421 :                         return_all = 0;
    1494             :                 }
    1495         557 :                 if (!do_fetch(stmt, 1, &data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all)) {
    1496          45 :                         error = 2;
    1497             :                 }
    1498             :         }
    1499         564 :         if (!error) {
    1500         512 :                 if ((how & PDO_FETCH_GROUP)) {
    1501         324 :                         while (do_fetch(stmt, 1, &data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all));
    1502         412 :                 } 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         376 :                         array_init(return_value);
    1506             :                         do {
    1507         782 :                                 zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &data);
    1508         782 :                         } while (do_fetch(stmt, 1, &data, how | flags, PDO_FETCH_ORI_NEXT, 0, 0));
    1509             :                 }
    1510             :         }
    1511             : 
    1512         564 :         do_fetch_opt_finish(stmt, 0);
    1513             : 
    1514         564 :         stmt->fetch.cls.ce = old_ce;
    1515         564 :         ZVAL_COPY_VALUE(&stmt->fetch.cls.ctor_args, &old_ctor_args);
    1516         564 :         stmt->fetch.cls.fci.param_count = old_arg_count;
    1517             : 
    1518         564 :         if (error) {
    1519          52 :                 PDO_HANDLE_STMT_ERR();
    1520          52 :                 if (error != 2) {
    1521           7 :                         RETURN_FALSE;
    1522             :                 } else { /* on no results, return an empty array */
    1523          45 :                         if (Z_TYPE_P(return_value) != IS_ARRAY) {
    1524          45 :                                 array_init(return_value);
    1525             :                         }
    1526          45 :                         return;
    1527             :                 }
    1528             :         }
    1529             : }
    1530             : /* }}} */
    1531             : 
    1532       30653 : static int register_bound_param(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int is_param) /* {{{ */
    1533             : {
    1534             :         struct pdo_bound_param_data param;
    1535       30653 :         zend_long param_type = PDO_PARAM_STR;
    1536       30653 :         zval *parameter, *driver_params = NULL;
    1537             : 
    1538       30653 :         memset(&param, 0, sizeof(param));
    1539       30653 :         param.paramno = -1;
    1540             : 
    1541       30653 :         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       30211 :                 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       30653 :         param.param_type = (int) param_type;
    1552             : 
    1553       30653 :         if (param.paramno > 0) {
    1554         442 :                 --param.paramno; /* make it zero-based internally */
    1555       30211 :         } 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       30653 :         if (driver_params) {
    1561           0 :                 ZVAL_COPY(&param.driver_params, driver_params);
    1562             :         }
    1563             : 
    1564       30653 :         ZVAL_COPY(&param.parameter, parameter);
    1565       30653 :         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       30652 :         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       30240 : static PHP_METHOD(PDOStatement, bindParam)
    1618             : {
    1619       60480 :         PHP_STMT_GET_OBJ;
    1620       30240 :         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         413 : static PHP_METHOD(PDOStatement, bindColumn)
    1627             : {
    1628         826 :         PHP_STMT_GET_OBJ;
    1629         413 :         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           9 : static PHP_METHOD(PDOStatement, rowCount)
    1636             : {
    1637          18 :         PHP_STMT_GET_OBJ;
    1638             : 
    1639           9 :         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          37 : static PHP_METHOD(PDOStatement, errorCode)
    1646             : {
    1647          74 :         PHP_STMT_GET_OBJ;
    1648             : 
    1649          37 :         if (zend_parse_parameters_none() == FAILURE) {
    1650           0 :                 return;
    1651             :         }
    1652             : 
    1653          37 :         if (stmt->error_code[0] == '\0') {
    1654           0 :                 RETURN_NULL();
    1655             :         }
    1656             : 
    1657          74 :         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         512 : static PHP_METHOD(PDOStatement, errorInfo)
    1664             : {
    1665             :         int error_count;
    1666         512 :         int error_count_diff     = 0;
    1667         512 :         int error_expected_count = 3;
    1668             : 
    1669        1024 :         PHP_STMT_GET_OBJ;
    1670             : 
    1671         512 :         if (zend_parse_parameters_none() == FAILURE) {
    1672           0 :                 return;
    1673             :         }
    1674             : 
    1675         512 :         array_init(return_value);
    1676         512 :         add_next_index_string(return_value, stmt->error_code);
    1677             : 
    1678         512 :         if (stmt->dbh->methods->fetch_err) {
    1679         512 :                 stmt->dbh->methods->fetch_err(stmt->dbh, stmt, return_value);
    1680             :         }
    1681             : 
    1682         512 :         error_count = zend_hash_num_elements(Z_ARRVAL_P(return_value));
    1683             : 
    1684         512 :         if (error_expected_count > error_count) {
    1685             :                 int current_index;
    1686             : 
    1687         488 :                 error_count_diff = error_expected_count - error_count;
    1688        1464 :                 for (current_index = 0; current_index < error_count_diff; current_index++) {
    1689         976 :                         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           1 : static PHP_METHOD(PDOStatement, setAttribute)
    1698             : {
    1699             :         zend_long attr;
    1700           1 :         zval *value = NULL;
    1701           2 :         PHP_STMT_GET_OBJ;
    1702             : 
    1703           1 :         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "lz!", &attr, &value)) {
    1704           0 :                 RETURN_FALSE;
    1705             :         }
    1706             : 
    1707           1 :         if (!stmt->methods->set_attribute) {
    1708           1 :                 goto fail;
    1709             :         }
    1710             : 
    1711           0 :         PDO_STMT_CLEAR_ERR();
    1712           0 :         if (stmt->methods->set_attribute(stmt, attr, value)) {
    1713           0 :                 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        2423 : static union _zend_function *dbstmt_method_get(zend_object **object_pp, zend_string *method_name, const zval *key)
    2207             : {
    2208        2423 :         zend_function *fbc = NULL;
    2209             :         zend_string *lc_method_name;
    2210        2423 :         zend_object *object = *object_pp;
    2211             : 
    2212        4846 :         lc_method_name = zend_string_alloc(ZSTR_LEN(method_name), 0);
    2213        2423 :         zend_str_tolower_copy(ZSTR_VAL(lc_method_name), ZSTR_VAL(method_name), ZSTR_LEN(method_name));
    2214             : 
    2215             : 
    2216        4846 :         if ((fbc = zend_hash_find_ptr(&object->ce->function_table, lc_method_name)) == NULL) {
    2217          26 :                 pdo_stmt_t *stmt = php_pdo_stmt_fetch_object(object);
    2218             :                 /* instance not created by PDO object */
    2219          26 :                 if (!stmt->dbh) {
    2220          13 :                         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        2423 :         if (!fbc) {
    2241          26 :                 fbc = std_object_handlers.get_method(object_pp, method_name, key);
    2242             :         }
    2243        2423 :         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       23453 : void pdo_stmt_init(void)
    2271             : {
    2272             :         zend_class_entry ce;
    2273             : 
    2274       23453 :         INIT_CLASS_ENTRY(ce, "PDOStatement", pdo_dbstmt_functions);
    2275       23453 :         pdo_dbstmt_ce = zend_register_internal_class(&ce);
    2276       23453 :         pdo_dbstmt_ce->get_iterator = pdo_stmt_iter_get;
    2277       23453 :         pdo_dbstmt_ce->create_object = pdo_dbstmt_new;
    2278       23453 :         zend_class_implements(pdo_dbstmt_ce, 1, zend_ce_traversable);
    2279       23453 :         zend_declare_property_null(pdo_dbstmt_ce, "queryString", sizeof("queryString")-1, ZEND_ACC_PUBLIC);
    2280             : 
    2281       23453 :         memcpy(&pdo_dbstmt_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
    2282       23453 :         pdo_dbstmt_object_handlers.offset = XtOffsetOf(pdo_stmt_t, std);
    2283       23453 :         pdo_dbstmt_object_handlers.dtor_obj = zend_objects_destroy_object;
    2284       23453 :         pdo_dbstmt_object_handlers.free_obj = pdo_dbstmt_free_storage;
    2285       23453 :         pdo_dbstmt_object_handlers.write_property = dbstmt_prop_write;
    2286       23453 :         pdo_dbstmt_object_handlers.unset_property = dbstmt_prop_delete;
    2287       23453 :         pdo_dbstmt_object_handlers.get_method = dbstmt_method_get;
    2288       23453 :         pdo_dbstmt_object_handlers.compare_objects = dbstmt_compare;
    2289       23453 :         pdo_dbstmt_object_handlers.clone_obj = dbstmt_clone_obj;
    2290             : 
    2291       23453 :         INIT_CLASS_ENTRY(ce, "PDORow", pdo_row_functions);
    2292       23453 :         pdo_row_ce = zend_register_internal_class(&ce);
    2293       23453 :         pdo_row_ce->ce_flags |= ZEND_ACC_FINAL; /* when removing this a lot of handlers need to be redone */
    2294       23453 :         pdo_row_ce->create_object = pdo_row_new;
    2295       23453 :         pdo_row_ce->serialize = pdo_row_serialize;
    2296       23453 : }
    2297             : 
    2298       12857 : PDO_API void php_pdo_free_statement(pdo_stmt_t *stmt)
    2299             : {
    2300       12857 :         if (stmt->bound_params) {
    2301       10942 :                 zend_hash_destroy(stmt->bound_params);
    2302       10942 :                 FREE_HASHTABLE(stmt->bound_params);
    2303       10942 :                 stmt->bound_params = NULL;
    2304             :         }
    2305       12857 :         if (stmt->bound_param_map) {
    2306         194 :                 zend_hash_destroy(stmt->bound_param_map);
    2307         194 :                 FREE_HASHTABLE(stmt->bound_param_map);
    2308         194 :                 stmt->bound_param_map = NULL;
    2309             :         }
    2310       12857 :         if (stmt->bound_columns) {
    2311         193 :                 zend_hash_destroy(stmt->bound_columns);
    2312         193 :                 FREE_HASHTABLE(stmt->bound_columns);
    2313         193 :                 stmt->bound_columns = NULL;
    2314             :         }
    2315             : 
    2316       12857 :         if (stmt->methods && stmt->methods->dtor) {
    2317       12835 :                 stmt->methods->dtor(stmt);
    2318             :         }
    2319       12857 :         if (stmt->query_string) {
    2320       12837 :                 efree(stmt->query_string);
    2321             :         }
    2322             : 
    2323       12857 :         if (stmt->columns) {
    2324             :                 int i;
    2325       12273 :                 struct pdo_column_data *cols = stmt->columns;
    2326             : 
    2327       14911 :                 for (i = 0; i < stmt->column_count; i++) {
    2328        2638 :                         if (cols[i].name) {
    2329        2638 :                                 zend_string_release(cols[i].name);
    2330        2638 :                                 cols[i].name = NULL;
    2331             :                         }
    2332             :                 }
    2333       12273 :                 efree(stmt->columns);
    2334       12273 :                 stmt->columns = NULL;
    2335             :         }
    2336             : 
    2337       25714 :         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       12857 :         do_fetch_opt_finish(stmt, 1);
    2343             : 
    2344       25714 :         if (!Z_ISUNDEF(stmt->database_object_handle)) {
    2345       12771 :                 zval_ptr_dtor(&stmt->database_object_handle);
    2346             :         }
    2347       12857 :         zend_object_std_dtor(&stmt->std);
    2348       12857 : }
    2349             : 
    2350       12857 : void pdo_dbstmt_free_storage(zend_object *std)
    2351             : {
    2352       12857 :         pdo_stmt_t *stmt = php_pdo_stmt_fetch_object(std);
    2353       12857 :         php_pdo_free_statement(stmt);
    2354       12857 : }
    2355             : 
    2356       12857 : zend_object *pdo_dbstmt_new(zend_class_entry *ce)
    2357             : {
    2358             :         pdo_stmt_t *stmt;
    2359             : 
    2360       12857 :         stmt = ecalloc(1, sizeof(pdo_stmt_t) + zend_object_properties_size(ce));
    2361       12857 :         zend_object_std_init(&stmt->std, ce);
    2362       12857 :         object_properties_init(&stmt->std, ce);
    2363             : 
    2364       12857 :         stmt->std.handlers = &pdo_dbstmt_object_handlers;
    2365             : 
    2366       12857 :         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           0 : static int row_prop_exists(zval *object, zval *member, int check_empty, void **cache_slot)
    2540             : {
    2541           0 :         pdo_row_t *row = (pdo_row_t *)Z_OBJ_P(object);
    2542           0 :         pdo_stmt_t *stmt = row->stmt;
    2543           0 :         int colno = -1;
    2544             :         zend_long lval;
    2545             : 
    2546           0 :         if (stmt) {
    2547           0 :                 if (Z_TYPE_P(member) == IS_LONG) {
    2548           0 :                         return Z_LVAL_P(member) >= 0 && Z_LVAL_P(member) < stmt->column_count;
    2549           0 :                 } else if (Z_TYPE_P(member) == IS_STRING) {
    2550           0 :                         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           0 :                 for (colno = 0; colno < stmt->column_count; colno++) {
    2560           0 :                         if (ZSTR_LEN(stmt->columns[colno].name) == Z_STRLEN_P(member) &&
    2561           0 :                             strncmp(ZSTR_VAL(stmt->columns[colno].name), Z_STRVAL_P(member), Z_STRLEN_P(member)) == 0) {
    2562           0 :                                 return 1;
    2563             :                         }
    2564             :                 }
    2565             :         }
    2566             : 
    2567           0 :         return 0;
    2568             : }
    2569             : 
    2570           0 : static int row_dim_exists(zval *object, zval *member, int check_empty)
    2571             : {
    2572           0 :         return row_prop_exists(object, member, check_empty, NULL);
    2573             : }
    2574             : 
    2575           0 : static void row_prop_delete(zval *object, zval *offset, void **cache_slot)
    2576             : {
    2577           0 :         php_error_docref(NULL, E_WARNING, "Cannot delete properties from a PDORow");
    2578           0 : }
    2579             : 
    2580           0 : static void row_dim_delete(zval *object, zval *offset)
    2581             : {
    2582           0 :         php_error_docref(NULL, E_WARNING, "Cannot delete properties from a PDORow");
    2583           0 : }
    2584             : 
    2585           4 : static HashTable *row_get_properties(zval *object)
    2586             : {
    2587           4 :         pdo_row_t *row = (pdo_row_t *)Z_OBJ_P(object);
    2588           4 :         pdo_stmt_t *stmt = row->stmt;
    2589             :         int i;
    2590             : 
    2591           4 :         if (stmt == NULL) {
    2592           0 :                 return NULL;
    2593             :         }
    2594             : 
    2595           4 :         if (!stmt->std.properties) {
    2596           3 :                 rebuild_object_properties(&stmt->std);
    2597             :         }
    2598           8 :         for (i = 0; i < stmt->column_count; i++) {
    2599             :                 zval val;
    2600           4 :                 fetch_value(stmt, &val, i, NULL);
    2601             : 
    2602           4 :                 zend_hash_update(stmt->std.properties, stmt->columns[i].name, &val);
    2603             :         }
    2604             : 
    2605           4 :         return stmt->std.properties;
    2606             : }
    2607             : 
    2608           0 : static union _zend_function *row_method_get(
    2609             :         zend_object **object_pp,
    2610             :         zend_string *method_name, const zval *key)
    2611             : {
    2612             :         zend_function *fbc;
    2613             :         zend_string *lc_method_name;
    2614             : 
    2615           0 :         lc_method_name = zend_string_alloc(ZSTR_LEN(method_name), 0);
    2616           0 :         zend_str_tolower_copy(ZSTR_VAL(lc_method_name), ZSTR_VAL(method_name), ZSTR_LEN(method_name));
    2617             : 
    2618           0 :         if ((fbc = zend_hash_find_ptr(&pdo_row_ce->function_table, lc_method_name)) == NULL) {
    2619             :                 zend_string_release(lc_method_name);
    2620           0 :                 return NULL;
    2621             :         }
    2622             : 
    2623             :         zend_string_release(lc_method_name);
    2624             : 
    2625           0 :         return fbc;
    2626             : }
    2627             : 
    2628           0 : static int row_call_method(zend_string *method, zend_object *object, INTERNAL_FUNCTION_PARAMETERS)
    2629             : {
    2630           0 :         return FAILURE;
    2631             : }
    2632             : 
    2633          14 : static union _zend_function *row_get_ctor(zend_object *object)
    2634             : {
    2635          14 :         zend_throw_exception_ex(php_pdo_get_exception(), 0, "You may not create a PDORow manually");
    2636          14 :         return NULL;
    2637             : }
    2638             : 
    2639           4 : static zend_string *row_get_classname(const zend_object *object)
    2640             : {
    2641           4 :         return zend_string_init("PDORow", sizeof("PDORow") - 1, 0);
    2642             : }
    2643             : 
    2644           0 : static int row_compare(zval *object1, zval *object2)
    2645             : {
    2646           0 :         return -1;
    2647             : }
    2648             : 
    2649             : zend_object_handlers pdo_row_object_handlers = {
    2650             :         0,
    2651             :         zend_objects_destroy_object,
    2652             :         pdo_row_free_storage,
    2653             :         NULL,
    2654             :         row_prop_read,
    2655             :         row_prop_write,
    2656             :         row_dim_read,
    2657             :         row_dim_write,
    2658             :         NULL,
    2659             :         NULL,
    2660             :         NULL,
    2661             :         row_prop_exists,
    2662             :         row_prop_delete,
    2663             :         row_dim_exists,
    2664             :         row_dim_delete,
    2665             :         row_get_properties,
    2666             :         row_method_get,
    2667             :         row_call_method,
    2668             :         row_get_ctor,
    2669             :         row_get_classname,
    2670             :         row_compare,
    2671             :         NULL, /* cast */
    2672             :         NULL,
    2673             :         NULL,
    2674             :         NULL,
    2675             :         NULL,
    2676             :         NULL,
    2677             :         NULL
    2678             : };
    2679             : 
    2680          31 : void pdo_row_free_storage(zend_object *std)
    2681             : {
    2682          31 :         pdo_row_t *row = (pdo_row_t *)std;
    2683          31 :         if (row->stmt) {
    2684          17 :                 ZVAL_UNDEF(&row->stmt->lazy_object_ref);
    2685          17 :                 OBJ_RELEASE(&row->stmt->std);
    2686             :         }
    2687          31 : }
    2688             : 
    2689          14 : zend_object *pdo_row_new(zend_class_entry *ce)
    2690             : {
    2691          14 :         pdo_row_t *row = ecalloc(1, sizeof(pdo_row_t));
    2692          14 :         zend_object_std_init(&row->std, ce);
    2693          14 :         row->std.handlers = &pdo_row_object_handlers;
    2694             : 
    2695          14 :         return &row->std;
    2696             : }
    2697             : 
    2698           0 : static int pdo_row_serialize(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data)
    2699             : {
    2700           0 :         php_error_docref(NULL, E_WARNING, "PDORow instances may not be serialized");
    2701           0 :         return FAILURE;
    2702             : }
    2703             : /* }}} */
    2704             : 
    2705             : /*
    2706             :  * Local variables:
    2707             :  * tab-width: 4
    2708             :  * c-basic-offset: 4
    2709             :  * End:
    2710             :  * vim600: noet sw=4 ts=4 fdm=marker
    2711             :  * vim<600: noet sw=4 ts=4
    2712             :  */

Generated by: LCOV version 1.10

Generated at Tue, 26 Jul 2016 17:07:41 +0000 (37 hours ago)

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