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-21 Instrumented lines: 1345
Code covered: 79.7 % Executed lines: 1072
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5

Generated at Sat, 21 Nov 2009 12:27:05 +0000 (3 days ago)

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