root/ext/pdo/pdo_stmt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. PHP_FUNCTION
  2. rewrite_name_to_position
  3. dispatch_param_event
  4. pdo_stmt_describe_columns
  5. get_lazy_object
  6. param_dtor
  7. really_register_bound_param
  8. PHP_METHOD
  9. fetch_value
  10. do_fetch_common
  11. do_fetch_class_prepare
  12. make_callable_ex
  13. do_fetch_func_prepare
  14. do_fetch_opt_finish
  15. do_fetch
  16. pdo_stmt_verify_mode
  17. PHP_METHOD
  18. PHP_METHOD
  19. PHP_METHOD
  20. PHP_METHOD
  21. register_bound_param
  22. PHP_METHOD
  23. PHP_METHOD
  24. PHP_METHOD
  25. PHP_METHOD
  26. PHP_METHOD
  27. PHP_METHOD
  28. PHP_METHOD
  29. generic_stmt_attr_get
  30. PHP_METHOD
  31. PHP_METHOD
  32. PHP_METHOD
  33. pdo_stmt_setup_fetch_mode
  34. PHP_METHOD
  35. pdo_stmt_do_next_rowset
  36. PHP_METHOD
  37. PHP_METHOD
  38. PHP_METHOD
  39. PHP_METHOD
  40. PHP_METHOD
  41. dbstmt_prop_write
  42. dbstmt_prop_delete
  43. dbstmt_method_get
  44. dbstmt_compare
  45. dbstmt_clone_obj
  46. pdo_stmt_init
  47. free_statement
  48. php_pdo_stmt_addref
  49. php_pdo_stmt_delref
  50. pdo_dbstmt_free_storage
  51. pdo_dbstmt_new
  52. pdo_stmt_iter_dtor
  53. pdo_stmt_iter_valid
  54. pdo_stmt_iter_get_data
  55. pdo_stmt_iter_get_key
  56. pdo_stmt_iter_move_forwards
  57. pdo_stmt_iter_get
  58. row_prop_read
  59. row_dim_read
  60. row_prop_write
  61. row_dim_write
  62. row_prop_exists
  63. row_dim_exists
  64. row_prop_delete
  65. row_dim_delete
  66. row_get_properties
  67. row_method_get
  68. row_call_method
  69. row_get_ctor
  70. row_get_ce
  71. row_get_classname
  72. row_compare
  73. pdo_row_free_storage
  74. pdo_row_new
  75. pdo_row_serialize

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

/* [<][>][^][v][top][bottom][index][help] */