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

Generated by: LTP GCOV extension version 1.5

Generated at Thu, 19 Nov 2009 08:20:14 +0000 (5 days ago)

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