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: 980 1232 79.5 %
Date: 2014-10-30 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       11455 : static inline int rewrite_name_to_position(pdo_stmt_t *stmt, struct pdo_bound_param_data *param TSRMLS_DC) /* {{{ */
     123             : {
     124       11455 :         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         426 :                 int position = 0;
     133             : 
     134         426 :                 if (stmt->named_rewrite_template) {
     135             :                         /* this is not an error here */
     136         169 :                         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       11029 :         return 1;       
     164             : }
     165             : /* }}} */
     166             : 
     167             : /* trigger callback hook for parameters */
     168        7874 : static int dispatch_param_event(pdo_stmt_t *stmt, enum pdo_param_event event_type TSRMLS_DC) /* {{{ */
     169             : {
     170        7874 :         int ret = 1, is_param = 1;
     171             :         struct pdo_bound_param_data *param;
     172             :         HashTable *ht;
     173             : 
     174        7874 :         if (!stmt->methods->param_hook) {
     175           0 :                 return 1;
     176             :         }
     177             : 
     178        7874 :         ht = stmt->bound_params;
     179             : 
     180             : iterate:
     181       15743 :         if (ht) {
     182       14515 :                 ZEND_HASH_FOREACH_PTR(ht, param) {
     183        5474 :                         if (!stmt->methods->param_hook(stmt, param, event_type TSRMLS_CC)) {
     184           5 :                                 ret = 0;
     185           5 :                                 break;
     186             :                         }
     187             :                 } ZEND_HASH_FOREACH_END();
     188             :         }
     189       15743 :         if (ret && is_param) {
     190        7869 :                 ht = stmt->bound_columns;
     191        7869 :                 is_param = 0;
     192        7869 :                 goto iterate;
     193             :         }
     194             : 
     195        7874 :         return ret;
     196             : }
     197             : /* }}} */
     198             : 
     199        1824 : int pdo_stmt_describe_columns(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
     200             : {
     201             :         int col;
     202             : 
     203        1824 :         stmt->columns = ecalloc(stmt->column_count, sizeof(struct pdo_column_data));
     204             : 
     205        3983 :         for (col = 0; col < stmt->column_count; col++) {
     206        2159 :                 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        2159 :                 if (stmt->dbh->native_case != stmt->dbh->desired_case && stmt->dbh->desired_case != PDO_CASE_NATURAL) {
     212        2082 :                         char *s = stmt->columns[col].name;
     213             : 
     214        2082 :                         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       11534 :                                         while (*s != '\0') {
     223        7396 :                                                 *s = tolower(*s);
     224        7396 :                                                 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        2159 :                 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        1824 :         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       11756 : static void param_dtor(zval *el) /* {{{ */
     272             : {
     273       11756 :         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       11756 :         if (param->stmt->methods->param_hook) {
     277             :                 TSRMLS_FETCH();
     278       11756 :                 param->stmt->methods->param_hook(param->stmt, param, PDO_PARAM_EVT_FREE TSRMLS_CC);
     279             :         }
     280             : 
     281       11756 :         if (param->name) {
     282        5452 :                 zend_string_release(param->name);
     283             :         }
     284             : 
     285       23512 :         if (!Z_ISUNDEF(param->parameter)) {
     286       11756 :                 zval_ptr_dtor(&param->parameter);
     287       11756 :                 ZVAL_UNDEF(&param->parameter);
     288             :         }
     289       23512 :         if (!Z_ISUNDEF(param->driver_params)) {
     290           0 :                 zval_ptr_dtor(&param->driver_params);
     291             :         }
     292       11756 :         efree(param);
     293       11756 : }
     294             : /* }}} */
     295             : 
     296       11860 : 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       11860 :         struct pdo_bound_param_data *pparam = NULL;
     301             : 
     302       11860 :         hash = is_param ? stmt->bound_params : stmt->bound_columns;
     303             : 
     304       11860 :         if (!hash) {
     305        1225 :                 ALLOC_HASHTABLE(hash);
     306        1225 :                 zend_hash_init(hash, 13, NULL, param_dtor, 0);
     307             : 
     308        1225 :                 if (is_param) {
     309        1035 :                         stmt->bound_params = hash;
     310             :                 } else {
     311         190 :                         stmt->bound_columns = hash;
     312             :                 }
     313             :         }
     314             : 
     315       23720 :         if (!Z_ISREF(param->parameter)) {
     316       11242 :                 parameter = &param->parameter;
     317             :         } else {
     318         618 :                 parameter = Z_REFVAL(param->parameter);
     319             :         }
     320             : 
     321       35014 :         if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_STR && param->max_value_len <= 0 && !Z_ISNULL_P(parameter)) {
     322       11402 :                 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       11379 :                         convert_to_string(parameter);
     329             :                 }
     330         593 :         } 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         460 :         } 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       11860 :         param->stmt = stmt;
     337       11860 :         param->is_param = is_param;
     338             : 
     339       11860 :         if (Z_REFCOUNTED(param->driver_params)) {
     340           0 :                 Z_ADDREF(param->driver_params);
     341             :         }
     342             : 
     343       11860 :         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       11860 :         if (param->name) {
     365       10582 :                 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        1060 :                         param->name = zend_string_init(param->name->val, param->name->len, 0);
     372             :                 }
     373             :         }
     374             : 
     375       11860 :         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       11759 :         if (stmt->methods->param_hook) {
     388       11759 :                 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       11756 :         if (param->paramno >= 0) {
     402        6658 :                 zend_hash_index_del(hash, param->paramno);
     403             :         }
     404             : 
     405             :         /* allocate storage for the parameter, keyed by its "canonical" name */
     406       11756 :         if (param->name) {
     407       10904 :                 pparam = zend_hash_update_mem(hash, param->name, param, sizeof(struct pdo_bound_param_data));
     408             :         } else {
     409       12608 :                 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       11756 :         if (stmt->methods->param_hook) {
     414       11756 :                 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       11656 :         return 1;
     429             : }
     430             : /* }}} */
     431             : 
     432             : /* {{{ proto bool PDOStatement::execute([array $bound_input_params])
     433             :    Execute a prepared statement, optionally binding parameters */
     434        2034 : static PHP_METHOD(PDOStatement, execute)
     435             : {
     436        2034 :         zval *input_params = NULL;
     437        2034 :         int ret = 1;
     438        2034 :         PHP_STMT_GET_OBJ;
     439             : 
     440        2034 :         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!", &input_params)) {
     441           0 :                 RETURN_FALSE;
     442             :         }
     443             : 
     444        2034 :         PDO_STMT_CLEAR_ERR();
     445             :         
     446        2034 :         if (input_params) {
     447             :                 struct pdo_bound_param_data param;
     448             :                 zval *tmp;
     449         760 :                 zend_string *key = NULL;
     450             :                 zend_ulong num_index;
     451             :         
     452         760 :                 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       22494 :                 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(input_params), num_index, key, tmp) {
     459       10968 :                         memset(&param, 0, sizeof(param));
     460             : 
     461       10968 :                         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        5616 :                                 param.paramno = num_index;
     474             :                         }
     475             : 
     476       10968 :                         param.param_type = PDO_PARAM_STR;
     477       10968 :                         ZVAL_COPY(&param.parameter, tmp);
     478             : 
     479       10968 :                         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        1832 :         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         725 :                 ret = pdo_parse_params(stmt, stmt->query_string, stmt->query_stringlen,
     495             :                         &stmt->active_query_string, &stmt->active_query_stringlen TSRMLS_CC);
     496             : 
     497         725 :                 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         460 :                 } else if (ret == -1) {
     503             :                         /* something broke */
     504         201 :                         PDO_HANDLE_STMT_ERR();
     505         201 :                         RETURN_FALSE;
     506             :                 }
     507        1107 :         } else if (!dispatch_param_event(stmt, PDO_PARAM_EVT_EXEC_PRE TSRMLS_CC)) {
     508           5 :                 PDO_HANDLE_STMT_ERR();
     509           5 :                 RETURN_FALSE;
     510             :         }
     511        1626 :         if (stmt->methods->executer(stmt TSRMLS_CC)) {
     512        1592 :                 if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
     513         253 :                         efree(stmt->active_query_string);
     514             :                 }
     515        1592 :                 stmt->active_query_string = NULL;
     516        1592 :                 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        1592 :                 if (ret && !dispatch_param_event(stmt, PDO_PARAM_EVT_EXEC_POST TSRMLS_CC)) {
     529           0 :                         RETURN_FALSE;
     530             :                 }
     531             :                         
     532        1592 :                 RETURN_BOOL(ret);
     533             :         }
     534          34 :         if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
     535           6 :                 efree(stmt->active_query_string);
     536             :         }
     537          34 :         stmt->active_query_string = NULL;
     538          34 :         PDO_HANDLE_STMT_ERR();
     539          34 :         RETURN_FALSE;
     540             : }
     541             : /* }}} */
     542             : 
     543        4708 : 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        4708 :         char *value = NULL;
     547        4708 :         size_t value_len = 0;
     548        4708 :         int caller_frees = 0;
     549             :         int type, new_type;
     550             : 
     551        4708 :         col = &stmt->columns[colno];
     552        4708 :         type = PDO_PARAM_TYPE(col->param_type);
     553        4708 :         new_type =  type_override ? PDO_PARAM_TYPE(*type_override) : type;
     554             : 
     555        4708 :         value = NULL;
     556        4708 :         value_len = 0;
     557             : 
     558        4708 :         stmt->methods->get_col(stmt, colno, &value, &value_len, &caller_frees TSRMLS_CC);
     559             : 
     560        4708 :         switch (type) {
     561             :                 case PDO_PARAM_ZVAL:
     562        2036 :                         if (value && value_len == sizeof(zval)) {
     563        1018 :                                 ZVAL_COPY_VALUE(dest, (zval *)value);
     564             :                         } else {
     565           0 :                                 ZVAL_NULL(dest);
     566             :                         }
     567             :                         
     568        1018 :                         if (Z_TYPE_P(dest) == IS_NULL) {
     569          12 :                                 type = new_type;
     570             :                         }
     571        1018 :                         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           0 :                         if (value && value_len == sizeof(zend_bool)) {
     583           0 :                                 ZVAL_BOOL(dest, *(zend_bool*)value);
     584           0 :                                 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        3435 :                         if (value && !(value_len == 0 && stmt->dbh->oracle_nulls == PDO_NULL_EMPTY_STRING)) {
     632        6740 :                                 ZVAL_STRINGL(dest, value, value_len);
     633        3370 :                                 break;
     634             :                         }
     635             :                 default:
     636          65 :                         ZVAL_NULL(dest);
     637             :         }
     638             : 
     639        4708 :         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        4708 :         if (caller_frees && value) {
     659           1 :                 efree(value);
     660             :         }
     661             : 
     662        4708 :         if (stmt->dbh->stringify) {
     663        2839 :                 switch (Z_TYPE_P(dest)) {
     664             :                         case IS_LONG:
     665             :                         case IS_DOUBLE:
     666         289 :                                 convert_to_string(dest);
     667             :                                 break;
     668             :                 }
     669             :         }
     670             : 
     671        4708 :         if (Z_TYPE_P(dest) == IS_NULL && stmt->dbh->oracle_nulls == PDO_NULL_TO_STRING) {
     672           0 :                 ZVAL_EMPTY_STRING(dest);
     673             :         }
     674        4708 : }
     675             : /* }}} */
     676             : 
     677        2899 : static int do_fetch_common(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori, zend_long offset, int do_bind TSRMLS_DC) /* {{{ */
     678             : {
     679        2899 :         if (!stmt->executed) {
     680          12 :                 return 0;
     681             :         }
     682             : 
     683        2887 :         if (!dispatch_param_event(stmt, PDO_PARAM_EVT_FETCH_PRE TSRMLS_CC)) {
     684           0 :                 return 0;
     685             :         }
     686             : 
     687        2887 :         if (!stmt->methods->fetcher(stmt, ori, offset TSRMLS_CC)) {
     688         599 :                 return 0;
     689             :         }
     690             : 
     691             :         /* some drivers might need to describe the columns now */
     692        2288 :         if (!stmt->columns && !pdo_stmt_describe_columns(stmt TSRMLS_CC)) {
     693           0 :                 return 0;
     694             :         }
     695             :         
     696        2288 :         if (!dispatch_param_event(stmt, PDO_PARAM_EVT_FETCH_POST TSRMLS_CC)) {
     697           0 :                 return 0;
     698             :         }
     699             : 
     700        2288 :         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        2288 :         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        3494 : 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        3494 :         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        3494 :         stmt->fetch.cls.fci.size = 0;
     820        6988 :         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        3494 :         if (stmt->fetch.func.values) {
     826          50 :                 efree(stmt->fetch.func.values);
     827          50 :                 stmt->fetch.func.values = NULL;
     828             :         }
     829        3494 :         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        2832 : 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        2832 :         int flags, idx, old_arg_count = 0;
     838        2832 :         zend_class_entry *ce = NULL, *old_ce = NULL;
     839             :         zval grp_val, *pgrp, retval, old_ctor_args;
     840             :         int colno;
     841             : 
     842        2832 :         if (how == PDO_FETCH_USE_DEFAULT) {
     843         419 :                 how = stmt->default_fetch_type;
     844             :         }
     845        2832 :         flags = how & PDO_FETCH_FLAGS;
     846        2832 :         how = how & ~PDO_FETCH_FLAGS;
     847             : 
     848        2832 :         if (!do_fetch_common(stmt, ori, offset, do_bind TSRMLS_CC)) {
     849         609 :                 return 0;
     850             :         }
     851             : 
     852        2223 :         if (how == PDO_FETCH_BOUND) {
     853         397 :                 RETVAL_TRUE;
     854         397 :                 return 1;
     855             :         }
     856             : 
     857        1931 :         if (flags & PDO_FETCH_GROUP && stmt->fetch.column == -1) {
     858         105 :                 colno = 1;
     859             :         } else {
     860        1721 :                 colno = stmt->fetch.column;
     861             :         }
     862             : 
     863        1826 :         if (return_value) {
     864        1826 :                 int i = 0;
     865             : 
     866        1826 :                 if (how == PDO_FETCH_LAZY) {
     867          20 :                         get_lazy_object(stmt, return_value TSRMLS_CC);
     868          20 :                         return 1;
     869             :                 }
     870             : 
     871        1806 :                 RETVAL_FALSE;
     872             : 
     873        1806 :                 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        1116 :                                 if (!return_all) {
     880        1036 :                                         ZVAL_NEW_ARR(return_value);
     881        1036 :                                         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        1116 :                                 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        1744 :                 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        4766 :                 for (idx = 0; i < stmt->column_count; i++, idx++) {
    1022             :                         zval val;
    1023        3112 :                         fetch_value(stmt, &val, i, NULL TSRMLS_CC);
    1024             : 
    1025        3112 :                         switch (how) {
    1026             :                                 case PDO_FETCH_ASSOC:
    1027        1532 :                                         add_assoc_zval(return_value, stmt->columns[i].name, &val);
    1028        1532 :                                         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        1654 :                 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        1654 :                 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        1654 :         return 1;
    1213             : }
    1214             : /* }}} */
    1215             : 
    1216        1610 : static int pdo_stmt_verify_mode(pdo_stmt_t *stmt, zend_long mode, int fetch_all TSRMLS_DC) /* {{{ */
    1217             : {
    1218        1610 :         int flags = mode & PDO_FETCH_FLAGS;
    1219             : 
    1220        1610 :         mode = mode & ~PDO_FETCH_FLAGS;
    1221             : 
    1222        1610 :         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        1610 :         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        1610 :         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        1423 :                         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        1423 :                         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        1423 :                         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        1548 :                         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        1023 : static PHP_METHOD(PDOStatement, fetch)
    1271             : {
    1272        1023 :         zend_long how = PDO_FETCH_USE_DEFAULT;
    1273        1023 :         zend_long ori = PDO_FETCH_ORI_NEXT;
    1274        1023 :         zend_long off = 0;
    1275        1023 :     PHP_STMT_GET_OBJ;
    1276             : 
    1277        1023 :         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lll", &how,
    1278             :                         &ori, &off)) {
    1279           0 :                 RETURN_FALSE;
    1280             :         }
    1281             : 
    1282        1023 :         PDO_STMT_CLEAR_ERR();
    1283             : 
    1284        1023 :         if (!pdo_stmt_verify_mode(stmt, how, 0 TSRMLS_CC)) {
    1285           0 :                 RETURN_FALSE;
    1286             :         }
    1287             : 
    1288        1023 :         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          67 : static PHP_METHOD(PDOStatement, fetchColumn)
    1363             : {
    1364          67 :         zend_long col_n = 0;
    1365          67 :         PHP_STMT_GET_OBJ;
    1366             : 
    1367          67 :         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &col_n)) {
    1368           0 :                 RETURN_FALSE;
    1369             :         }
    1370             : 
    1371          67 :         PDO_STMT_CLEAR_ERR();
    1372             : 
    1373          67 :         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          65 :         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         459 : static PHP_METHOD(PDOStatement, fetchAll)
    1385             : {
    1386         459 :         zend_long how = PDO_FETCH_USE_DEFAULT;
    1387             :         zval data, *return_all;
    1388             :         zval *arg2;
    1389             :         zend_class_entry *old_ce;
    1390         459 :         zval old_ctor_args, *ctor_args = NULL;
    1391         459 :         int error = 0, flags, old_arg_count;
    1392         459 :         PHP_STMT_GET_OBJ;         
    1393             : 
    1394         459 :         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lzz", &how, &arg2, &ctor_args)) {
    1395           0 :                 RETURN_FALSE;
    1396             :         }
    1397             : 
    1398         459 :         if (!pdo_stmt_verify_mode(stmt, how, 1 TSRMLS_CC)) {
    1399           0 :                 RETURN_FALSE;
    1400             :         }
    1401             : 
    1402         459 :         old_ce = stmt->fetch.cls.ce;
    1403         459 :         ZVAL_COPY_VALUE(&old_ctor_args, &stmt->fetch.cls.ctor_args);
    1404         459 :         old_arg_count = stmt->fetch.cls.fci.param_count;
    1405             : 
    1406         459 :         do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
    1407             : 
    1408         459 :         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         278 :                 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         459 :         flags = how & PDO_FETCH_FLAGS;
    1490             :         
    1491         459 :         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         459 :         if (!error)     {
    1497         452 :                 PDO_STMT_CLEAR_ERR();
    1498         904 :                 if ((how & PDO_FETCH_GROUP) || how == PDO_FETCH_KEY_PAIR || 
    1499         337 :                         (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         337 :                         return_all = 0;
    1505             :                 }
    1506         452 :                 if (!do_fetch(stmt, 1, &data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all TSRMLS_CC)) {
    1507          42 :                         error = 2;
    1508             :                 }
    1509             :         }
    1510         459 :         if (!error) {
    1511         410 :                 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         325 :                 } 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         295 :                         array_init(return_value);
    1519             :                         do {
    1520         626 :                                 add_next_index_zval(return_value, &data);
    1521         626 :                         } while (do_fetch(stmt, 1, &data, how | flags, PDO_FETCH_ORI_NEXT, 0, 0 TSRMLS_CC));
    1522             :                 }
    1523             :         }
    1524             :         
    1525         459 :         do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
    1526             : 
    1527         459 :         stmt->fetch.cls.ce = old_ce;
    1528         459 :         ZVAL_COPY_VALUE(&stmt->fetch.cls.ctor_args, &old_ctor_args);
    1529         459 :         stmt->fetch.cls.fci.param_count = old_arg_count;
    1530             :         
    1531         459 :         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         618 : static int register_bound_param(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int is_param) /* {{{ */
    1546             : {
    1547         618 :         struct pdo_bound_param_data param = {0};
    1548         618 :         zend_long param_type = PDO_PARAM_STR;
    1549             :         zval *parameter;
    1550             : 
    1551         618 :         param.paramno = -1;
    1552             : 
    1553         618 :         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         178 :                 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         618 :         param.param_type = (int) param_type;
    1564             :         
    1565         618 :         if (param.paramno > 0) {
    1566         440 :                 --param.paramno; /* make it zero-based internally */
    1567         178 :         } 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         618 :         ZVAL_COPY(&param.parameter, parameter);
    1573         618 :         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         617 :         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         213 : static PHP_METHOD(PDOStatement, bindParam)
    1625             : {
    1626         213 :         PHP_STMT_GET_OBJ;
    1627         213 :         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         510 : static PHP_METHOD(PDOStatement, errorInfo)
    1671             : {
    1672             :         int error_count;
    1673         510 :         int error_count_diff     = 0;
    1674         510 :         int error_expected_count = 3;
    1675             : 
    1676         510 :         PHP_STMT_GET_OBJ;
    1677             : 
    1678         510 :         if (zend_parse_parameters_none() == FAILURE) {
    1679           0 :                 return;
    1680             :         }
    1681             : 
    1682         510 :         array_init(return_value);
    1683         510 :         add_next_index_string(return_value, stmt->error_code);
    1684             : 
    1685         510 :         if (stmt->dbh->methods->fetch_err) {
    1686         510 :                 stmt->dbh->methods->fetch_err(stmt->dbh, stmt, return_value TSRMLS_CC);
    1687             :         }
    1688             : 
    1689         510 :         error_count = zend_hash_num_elements(Z_ARRVAL_P(return_value));
    1690             : 
    1691         510 :         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 succeded, false otherwise */
    2020             : 
    2021          94 : static int pdo_stmt_do_next_rowset(pdo_stmt_t *stmt TSRMLS_DC)
    2022             : {
    2023             :         /* un-describe */
    2024          94 :         if (stmt->columns) {
    2025             :                 int i;
    2026          88 :                 struct pdo_column_data *cols = stmt->columns;
    2027             :                 
    2028         182 :                 for (i = 0; i < stmt->column_count; i++) {
    2029          94 :                         efree(cols[i].name);
    2030             :                 }
    2031          88 :                 efree(stmt->columns);
    2032          88 :                 stmt->columns = NULL;
    2033          88 :                 stmt->column_count = 0;
    2034             :         }
    2035             : 
    2036          94 :         if (!stmt->methods->next_rowset(stmt TSRMLS_CC)) {
    2037             :                 /* Set the executed flag to 0 to reallocate columns on next execute */
    2038          70 :                 stmt->executed = 0;
    2039          70 :                 return 0;
    2040             :         }
    2041             : 
    2042          24 :         pdo_stmt_describe_columns(stmt TSRMLS_CC);
    2043             : 
    2044          24 :         return 1;
    2045             : }
    2046             : 
    2047          67 : static PHP_METHOD(PDOStatement, nextRowset)
    2048             : {
    2049          67 :         PHP_STMT_GET_OBJ;
    2050             : 
    2051          67 :         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          67 :         PDO_STMT_CLEAR_ERR();
    2057             :         
    2058          67 :         if (!pdo_stmt_do_next_rowset(stmt TSRMLS_CC)) {
    2059          43 :                 PDO_HANDLE_STMT_ERR();
    2060          43 :                 RETURN_FALSE;
    2061             :         }
    2062             : 
    2063          24 :         RETURN_TRUE;
    2064             : }
    2065             : /* }}} */
    2066             : 
    2067             : /* {{{ proto bool PDOStatement::closeCursor()
    2068             :    Closes the cursor, leaving the statement ready for re-execution. */
    2069         426 : static PHP_METHOD(PDOStatement, closeCursor)
    2070             : {
    2071         426 :         PHP_STMT_GET_OBJ;
    2072             : 
    2073         426 :         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         399 :         PDO_STMT_CLEAR_ERR();
    2092             : 
    2093         399 :         if (!stmt->methods->cursor_closer(stmt TSRMLS_CC)) {
    2094           0 :                 PDO_HANDLE_STMT_ERR();
    2095           0 :                 RETURN_FALSE;
    2096             :         }
    2097         399 :         stmt->executed = 0;
    2098         399 :         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          61 : static void dbstmt_prop_write(zval *object, zval *member, zval *value, void **cache_slot TSRMLS_DC)
    2187             : {
    2188          61 :         pdo_stmt_t *stmt = Z_PDO_STMT_P(object);
    2189             : 
    2190          61 :         convert_to_string(member);
    2191             : 
    2192          61 :         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          61 :                 std_object_handlers.write_property(object, member, value, cache_slot TSRMLS_CC);
    2196             :         }
    2197          61 : }
    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        1960 : static union _zend_function *dbstmt_method_get(zend_object **object_pp, zend_string *method_name, const zval *key TSRMLS_DC)
    2213             : {
    2214        1960 :         zend_function *fbc = NULL;
    2215             :         zend_string *lc_method_name;
    2216        1960 :         zend_object *object = *object_pp;
    2217             : 
    2218        3920 :         lc_method_name = zend_string_alloc(method_name->len, 0);
    2219        1960 :         zend_str_tolower_copy(lc_method_name->val, method_name->val, method_name->len);
    2220             : 
    2221        3920 :         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        1960 :         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       20423 : void pdo_stmt_init(TSRMLS_D)
    2273             : {
    2274             :         zend_class_entry ce;
    2275             : 
    2276       20423 :         INIT_CLASS_ENTRY(ce, "PDOStatement", pdo_dbstmt_functions);
    2277       20423 :         pdo_dbstmt_ce = zend_register_internal_class(&ce TSRMLS_CC);
    2278       20423 :         pdo_dbstmt_ce->get_iterator = pdo_stmt_iter_get;
    2279       20423 :         pdo_dbstmt_ce->create_object = pdo_dbstmt_new;
    2280       20423 :         zend_class_implements(pdo_dbstmt_ce TSRMLS_CC, 1, zend_ce_traversable); 
    2281       20423 :         zend_declare_property_null(pdo_dbstmt_ce, "queryString", sizeof("queryString")-1, ZEND_ACC_PUBLIC TSRMLS_CC);
    2282             : 
    2283       20423 :         memcpy(&pdo_dbstmt_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
    2284       20423 :         pdo_dbstmt_object_handlers.offset = XtOffsetOf(pdo_stmt_t, std);
    2285       20423 :         pdo_dbstmt_object_handlers.dtor_obj = zend_objects_destroy_object;
    2286       20423 :         pdo_dbstmt_object_handlers.free_obj = pdo_dbstmt_free_storage;
    2287       20423 :         pdo_dbstmt_object_handlers.write_property = dbstmt_prop_write;
    2288       20423 :         pdo_dbstmt_object_handlers.unset_property = dbstmt_prop_delete;
    2289       20423 :         pdo_dbstmt_object_handlers.get_method = dbstmt_method_get;
    2290       20423 :         pdo_dbstmt_object_handlers.compare_objects = dbstmt_compare;
    2291       20423 :         pdo_dbstmt_object_handlers.clone_obj = dbstmt_clone_obj;
    2292             : 
    2293       20423 :         INIT_CLASS_ENTRY(ce, "PDORow", pdo_row_functions);
    2294       20423 :         pdo_row_ce = zend_register_internal_class(&ce TSRMLS_CC);
    2295       20423 :         pdo_row_ce->ce_flags |= ZEND_ACC_FINAL_CLASS; /* when removing this a lot of handlers need to be redone */
    2296       20423 :         pdo_row_ce->create_object = pdo_row_new;
    2297       20423 :         pdo_row_ce->serialize = pdo_row_serialize;
    2298       20423 : }
    2299             : 
    2300        2274 : static void free_statement(pdo_stmt_t *stmt TSRMLS_DC)
    2301             : {
    2302        2274 :         if (stmt->bound_params) {
    2303         901 :                 zend_hash_destroy(stmt->bound_params);
    2304         901 :                 FREE_HASHTABLE(stmt->bound_params);
    2305         901 :                 stmt->bound_params = NULL;
    2306             :         }
    2307        2274 :         if (stmt->bound_param_map) {
    2308         175 :                 zend_hash_destroy(stmt->bound_param_map);
    2309         175 :                 FREE_HASHTABLE(stmt->bound_param_map);
    2310         175 :                 stmt->bound_param_map = NULL;
    2311             :         }
    2312        2274 :         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        2274 :         if (stmt->methods && stmt->methods->dtor) {
    2319        2261 :                 stmt->methods->dtor(stmt TSRMLS_CC);
    2320             :         }
    2321        2274 :         if (stmt->query_string) {
    2322        2262 :                 efree(stmt->query_string);
    2323             :         }
    2324             : 
    2325        2274 :         if (stmt->columns) {
    2326             :                 int i;
    2327        1736 :                 struct pdo_column_data *cols = stmt->columns;
    2328             : 
    2329        3801 :                 for (i = 0; i < stmt->column_count; i++) {
    2330        2065 :                         if (cols[i].name) {
    2331        2065 :                                 efree(cols[i].name);
    2332        2065 :                                 cols[i].name = NULL;
    2333             :                         }
    2334             :                 }
    2335        1736 :                 efree(stmt->columns);
    2336        1736 :                 stmt->columns = NULL;
    2337             :         }
    2338             : 
    2339        4548 :         if (!Z_ISUNDEF(stmt->fetch.into) && stmt->default_fetch_type == PDO_FETCH_INTO) {
    2340           6 :                 ZVAL_UNDEF(&stmt->fetch.into);
    2341             :         }
    2342             :         
    2343        2274 :         do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
    2344             : 
    2345        4548 :         if (!Z_ISUNDEF(stmt->database_object_handle)) {
    2346        2262 :                 zval_ptr_dtor(&stmt->database_object_handle);
    2347             :         }
    2348        2274 :         zend_object_std_dtor(&stmt->std TSRMLS_CC);
    2349        2274 : }
    2350             : 
    2351        2274 : void pdo_dbstmt_free_storage(zend_object *std TSRMLS_DC)
    2352             : {
    2353        2274 :         pdo_stmt_t *stmt = php_pdo_stmt_fetch_object(std);
    2354        2274 :         free_statement(stmt TSRMLS_CC);
    2355        2274 : }
    2356             : 
    2357        2274 : zend_object *pdo_dbstmt_new(zend_class_entry *ce TSRMLS_DC)
    2358             : {
    2359             :         pdo_stmt_t *stmt;
    2360             : 
    2361        2274 :         stmt = ecalloc(1, sizeof(pdo_stmt_t) + sizeof(zval) * (ce->default_properties_count - 1));
    2362        2274 :         zend_object_std_init(&stmt->std, ce TSRMLS_CC);
    2363        2274 :         object_properties_init(&stmt->std, ce);
    2364             : 
    2365        2274 :         stmt->std.handlers = &pdo_dbstmt_object_handlers;
    2366             : 
    2367        2274 :         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             : 
    2490          30 :         ZVAL_NULL(rv);
    2491          30 :         if (stmt) {
    2492          30 :                 if (Z_TYPE_P(member) == IS_LONG) {
    2493           3 :                         if (Z_LVAL_P(member) >= 0 && Z_LVAL_P(member) < stmt->column_count) {
    2494           1 :                                 fetch_value(stmt, rv, Z_LVAL_P(member), NULL TSRMLS_CC);
    2495             :                         }
    2496             :                 } else {
    2497          27 :                         convert_to_string(member);
    2498             :                         /* TODO: replace this with a hash of available column names to column
    2499             :                          * numbers */
    2500          41 :                         for (colno = 0; colno < stmt->column_count; colno++) {
    2501          37 :                                 if (strcmp(stmt->columns[colno].name, Z_STRVAL_P(member)) == 0) {
    2502          23 :                                         fetch_value(stmt, rv, colno, NULL TSRMLS_CC);
    2503             :                                         //???
    2504             :                                         //Z_SET_REFCOUNT_P(rv, 0);
    2505             :                                         //Z_UNSET_ISREF_P(rv);
    2506          23 :                                         return rv;
    2507             :                                 }
    2508             :                         }
    2509           4 :                         if (strcmp(Z_STRVAL_P(member), "queryString") == 0) {
    2510           3 :                                 ZVAL_OBJ(&zobj, &stmt->std);
    2511             :                                 //zval_ptr_dtor(rv);
    2512           3 :                                 return std_object_handlers.read_property(&zobj, member, type, cache_slot, rv TSRMLS_CC);
    2513             :                         }
    2514             :                 }
    2515             :         }
    2516             : 
    2517             :         //???
    2518             :         //Z_SET_REFCOUNT_P(return_value, 0);
    2519             :         //Z_UNSET_ISREF_P(return_value);
    2520             :         
    2521           4 :         return rv;
    2522             : }
    2523             : 
    2524           1 : static zval *row_dim_read(zval *object, zval *member, int type, zval *rv TSRMLS_DC)
    2525             : {
    2526           1 :         return row_prop_read(object, member, type, NULL, rv TSRMLS_CC);
    2527             : }
    2528             : 
    2529           0 : static void row_prop_write(zval *object, zval *member, zval *value, void **cache_slot TSRMLS_DC)
    2530             : {
    2531           0 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "This PDORow is not from a writable result set");
    2532           0 : }
    2533             : 
    2534           0 : static void row_dim_write(zval *object, zval *member, zval *value TSRMLS_DC)
    2535             : {
    2536           0 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "This PDORow is not from a writable result set");
    2537           0 : }
    2538             : 
    2539           0 : static int row_prop_exists(zval *object, zval *member, int check_empty, void **cache_slot TSRMLS_DC)
    2540             : {
    2541           0 :         pdo_row_t *row = (pdo_row_t *)Z_OBJ_P(object);
    2542           0 :         pdo_stmt_t *stmt = row->stmt;
    2543           0 :         int colno = -1;
    2544             : 
    2545           0 :         if (stmt) {
    2546           0 :                 if (Z_TYPE_P(member) == IS_LONG) {
    2547           0 :                         return Z_LVAL_P(member) >= 0 && Z_LVAL_P(member) < stmt->column_count;
    2548             :                 } else {
    2549           0 :                         convert_to_string(member);
    2550             : 
    2551             :                         /* TODO: replace this with a hash of available column names to column
    2552             :                          * numbers */
    2553           0 :                         for (colno = 0; colno < stmt->column_count; colno++) {
    2554           0 :                                 if (strcmp(stmt->columns[colno].name, Z_STRVAL_P(member)) == 0) {
    2555           0 :                                         return 1;
    2556             :                                 }
    2557             :                         }
    2558             :                 }
    2559             :         }
    2560             : 
    2561           0 :         return 0;
    2562             : }
    2563             : 
    2564           0 : static int row_dim_exists(zval *object, zval *member, int check_empty TSRMLS_DC)
    2565             : {
    2566           0 :         return row_prop_exists(object, member, check_empty, NULL TSRMLS_CC);
    2567             : }
    2568             : 
    2569           0 : static void row_prop_delete(zval *object, zval *offset, void **cache_slot TSRMLS_DC)
    2570             : {
    2571           0 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a PDORow");
    2572           0 : }
    2573             : 
    2574           0 : static void row_dim_delete(zval *object, zval *offset TSRMLS_DC)
    2575             : {
    2576           0 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a PDORow");
    2577           0 : }
    2578             : 
    2579           4 : static HashTable *row_get_properties(zval *object TSRMLS_DC)
    2580             : {
    2581           4 :         pdo_row_t *row = (pdo_row_t *)Z_OBJ_P(object);
    2582           4 :         pdo_stmt_t *stmt = row->stmt;
    2583             :         int i;
    2584             : 
    2585           4 :         if (stmt == NULL) {
    2586           0 :                 return NULL;
    2587             :         }
    2588             :         
    2589           4 :         if (!stmt->std.properties) {
    2590           3 :                 rebuild_object_properties(&stmt->std);
    2591             :         }
    2592           8 :         for (i = 0; i < stmt->column_count; i++) {
    2593             :                 zval val;
    2594           4 :                 fetch_value(stmt, &val, i, NULL TSRMLS_CC);
    2595             : 
    2596           4 :                 zend_hash_str_update(stmt->std.properties, stmt->columns[i].name, stmt->columns[i].namelen, &val);
    2597             :         }
    2598             : 
    2599           4 :         return stmt->std.properties;
    2600             : }
    2601             : 
    2602           0 : static union _zend_function *row_method_get(
    2603             :         zend_object **object_pp,
    2604             :         zend_string *method_name, const zval *key TSRMLS_DC)
    2605             : {
    2606             :         zend_function *fbc;
    2607             :         zend_string *lc_method_name;
    2608             : 
    2609           0 :         lc_method_name = zend_string_alloc(method_name->len, 0);
    2610           0 :         zend_str_tolower_copy(lc_method_name->val, method_name->val, method_name->len);
    2611             : 
    2612           0 :         if ((fbc = zend_hash_find_ptr(&pdo_row_ce->function_table, lc_method_name)) == NULL) {
    2613             :                 zend_string_release(lc_method_name);
    2614           0 :                 return NULL;
    2615             :         }
    2616             :         
    2617             :         zend_string_release(lc_method_name);
    2618           0 :         return fbc;
    2619             : }
    2620             : 
    2621           0 : static int row_call_method(zend_string *method, zend_object *object, INTERNAL_FUNCTION_PARAMETERS)
    2622             : {
    2623           0 :         return FAILURE;
    2624             : }
    2625             : 
    2626          12 : static union _zend_function *row_get_ctor(zend_object *object TSRMLS_DC)
    2627             : {
    2628             :         static zend_internal_function ctor = {0};
    2629             : 
    2630          12 :         ctor.type = ZEND_INTERNAL_FUNCTION;
    2631          12 :         ctor.function_name = zend_string_init("__construct", sizeof("__construct") - 1, 0);
    2632          12 :         ctor.scope = pdo_row_ce;
    2633          12 :         ctor.handler = ZEND_FN(dbstmt_constructor);
    2634          12 :         ctor.fn_flags = ZEND_ACC_PUBLIC;
    2635             : 
    2636          12 :         return (union _zend_function*)&ctor;
    2637             : }
    2638             : 
    2639           4 : static zend_string *row_get_classname(const zend_object *object TSRMLS_DC)
    2640             : {
    2641           4 :         return zend_string_init("PDORow", sizeof("PDORow") - 1, 0);
    2642             : }
    2643             : 
    2644           0 : static int row_compare(zval *object1, zval *object2 TSRMLS_DC)
    2645             : {
    2646           0 :         return -1;
    2647             : }
    2648             : 
    2649             : zend_object_handlers pdo_row_object_handlers = {
    2650             :         0, 
    2651             :         zend_objects_destroy_object,    
    2652             :         pdo_row_free_storage,
    2653             :         NULL,
    2654             :         row_prop_read,
    2655             :         row_prop_write,
    2656             :         row_dim_read,
    2657             :         row_dim_write,
    2658             :         NULL,
    2659             :         NULL,
    2660             :         NULL,
    2661             :         row_prop_exists,
    2662             :         row_prop_delete,
    2663             :         row_dim_exists,
    2664             :         row_dim_delete,
    2665             :         row_get_properties,
    2666             :         row_method_get,
    2667             :         row_call_method,
    2668             :         row_get_ctor,
    2669             :         row_get_classname,
    2670             :         row_compare,
    2671             :         NULL, /* cast */
    2672             :         NULL
    2673             : };
    2674             : 
    2675          15 : void pdo_row_free_storage(zend_object *std TSRMLS_DC)
    2676             : {
    2677          15 :         pdo_row_t *row = (pdo_row_t *)std;
    2678          15 :         if (row->stmt) {
    2679          15 :                 ZVAL_UNDEF(&row->stmt->lazy_object_ref);
    2680          15 :                 OBJ_RELEASE(&row->stmt->std);
    2681             :         }
    2682          15 : }
    2683             : 
    2684          12 : zend_object *pdo_row_new(zend_class_entry *ce TSRMLS_DC)
    2685             : {
    2686          12 :         pdo_row_t *row = ecalloc(1, sizeof(pdo_row_t));
    2687          12 :         zend_object_std_init(&row->std, ce TSRMLS_CC);
    2688          12 :         row->std.handlers = &pdo_row_object_handlers;
    2689             : 
    2690          12 :         return &row->std;
    2691             : }
    2692             : 
    2693           0 : static int pdo_row_serialize(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data TSRMLS_DC)
    2694             : {
    2695           0 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "PDORow instances may not be serialized");
    2696           0 :         return FAILURE;
    2697             : }
    2698             : /* }}} */
    2699             : 
    2700             : /*
    2701             :  * Local variables:
    2702             :  * tab-width: 4
    2703             :  * c-basic-offset: 4
    2704             :  * End:
    2705             :  * vim600: noet sw=4 ts=4 fdm=marker
    2706             :  * vim<600: noet sw=4 ts=4
    2707             :  */

Generated by: LCOV version 1.10

Generated at Thu, 30 Oct 2014 07:41:36 +0000 (2 days ago)

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