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

Generated by: LCOV version 1.10

Generated at Sat, 13 Dec 2014 06:16:18 +0000 (5 days ago)

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