PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LTP GCOV extension - code coverage report
Current view: directory - pdo - pdo_stmt.c
Test: PHP Code Coverage
Date: 2009-11-23 Instrumented lines: 1340
Code covered: 73.1 % Executed lines: 979
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5

Generated at Mon, 23 Nov 2009 17:39:34 +0000 (33 hours ago)

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