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: 1008 1244 81.0 %
Date: 2016-06-25 Functions: 55 72 76.4 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Sat, 25 Jun 2016 07:09:01 +0000 (35 hours ago)

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