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. php_pdo_free_statement
  48. pdo_dbstmt_free_storage
  49. pdo_dbstmt_new
  50. pdo_stmt_iter_dtor
  51. pdo_stmt_iter_valid
  52. pdo_stmt_iter_get_data
  53. pdo_stmt_iter_get_key
  54. pdo_stmt_iter_move_forwards
  55. pdo_stmt_iter_get
  56. row_prop_read
  57. row_dim_read
  58. row_prop_write
  59. row_dim_write
  60. row_prop_exists
  61. row_dim_exists
  62. row_prop_delete
  63. row_dim_delete
  64. row_get_properties
  65. row_method_get
  66. row_call_method
  67. row_get_ctor
  68. row_get_classname
  69. row_compare
  70. pdo_row_free_storage
  71. pdo_row_new
  72. pdo_row_serialize

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

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