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: 986 1239 79.6 %
Date: 2015-04-14 Functions: 54 72 75.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Tue, 14 Apr 2015 11:48:47 +0000 (4 days ago)

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