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: 993 1244 79.8 %
Date: 2015-05-21 Functions: 54 72 75.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Thu, 21 May 2015 19:59:00 +0000 (5 days ago)

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