Back to index

php5  5.3.10
pdo_stmt.c
Go to the documentation of this file.
00001 /*
00002   +----------------------------------------------------------------------+
00003   | PHP Version 5                                                        |
00004   +----------------------------------------------------------------------+
00005   | Copyright (c) 1997-2012 The PHP Group                                |
00006   +----------------------------------------------------------------------+
00007   | This source file is subject to version 3.01 of the PHP license,      |
00008   | that is bundled with this package in the file LICENSE, and is        |
00009   | available through the world-wide-web at the following url:           |
00010   | http://www.php.net/license/3_01.txt                                  |
00011   | If you did not receive a copy of the PHP license and are unable to   |
00012   | obtain it through the world-wide-web, please send a note to          |
00013   | license@php.net so we can mail you a copy immediately.               |
00014   +----------------------------------------------------------------------+
00015   | Author: Wez Furlong <wez@php.net>                                    |
00016   |         Marcus Boerger <helly@php.net>                               |
00017   |         Sterling Hughes <sterling@php.net>                           |
00018   +----------------------------------------------------------------------+
00019 */
00020 
00021 /* $Id: pdo_stmt.c 321634 2012-01-01 13:15:04Z felipe $ */
00022 
00023 /* The PDO Statement Handle Class */
00024 
00025 #ifdef HAVE_CONFIG_H
00026 #include "config.h"
00027 #endif
00028 
00029 #include "php.h"
00030 #include "php_ini.h"
00031 #include "ext/standard/info.h"
00032 #include "ext/standard/php_var.h"
00033 #include "php_pdo.h"
00034 #include "php_pdo_driver.h"
00035 #include "php_pdo_int.h"
00036 #include "zend_exceptions.h"
00037 #include "zend_interfaces.h"
00038 #include "php_memory_streams.h"
00039 
00040 /* {{{ arginfo */
00041 ZEND_BEGIN_ARG_INFO(arginfo_pdostatement__void, 0)
00042 ZEND_END_ARG_INFO()
00043 
00044 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_execute, 0, 0, 0)
00045        ZEND_ARG_INFO(0, bound_input_params) /* array */
00046 ZEND_END_ARG_INFO()
00047 
00048 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_fetch, 0, 0, 0)
00049        ZEND_ARG_INFO(0, how)
00050        ZEND_ARG_INFO(0, orientation)
00051        ZEND_ARG_INFO(0, offset)
00052 ZEND_END_ARG_INFO()
00053 
00054 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_fetchobject, 0, 0, 0)
00055        ZEND_ARG_INFO(0, class_name)
00056        ZEND_ARG_INFO(0, ctor_args) /* array */
00057 ZEND_END_ARG_INFO()
00058 
00059 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_fetchcolumn, 0, 0, 0)
00060        ZEND_ARG_INFO(0, column_number)
00061 ZEND_END_ARG_INFO()
00062 
00063 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_fetchall, 0, 0, 0)
00064        ZEND_ARG_INFO(0, how)
00065        ZEND_ARG_INFO(0, class_name)
00066        ZEND_ARG_INFO(0, ctor_args) /* array */
00067 ZEND_END_ARG_INFO()
00068 
00069 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_bindvalue, 0, 0, 2)
00070        ZEND_ARG_INFO(0, paramno)
00071        ZEND_ARG_INFO(0, param)
00072        ZEND_ARG_INFO(0, type)
00073 ZEND_END_ARG_INFO()
00074 
00075 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_bindparam, 0, 0, 2)
00076        ZEND_ARG_INFO(0, paramno)
00077        ZEND_ARG_INFO(1, param)
00078        ZEND_ARG_INFO(0, type)
00079        ZEND_ARG_INFO(0, maxlen)
00080        ZEND_ARG_INFO(0, driverdata)
00081 ZEND_END_ARG_INFO()
00082 
00083 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_bindcolumn, 0, 0, 2)
00084        ZEND_ARG_INFO(0, column)
00085        ZEND_ARG_INFO(1, param)
00086        ZEND_ARG_INFO(0, type)
00087        ZEND_ARG_INFO(0, maxlen)
00088        ZEND_ARG_INFO(0, driverdata)
00089 ZEND_END_ARG_INFO()
00090 
00091 ZEND_BEGIN_ARG_INFO(arginfo_pdostatement_setattribute, 0)
00092        ZEND_ARG_INFO(0, attribute)
00093        ZEND_ARG_INFO(0, value)
00094 ZEND_END_ARG_INFO()
00095 
00096 ZEND_BEGIN_ARG_INFO(arginfo_pdostatement_getattribute, 0)
00097        ZEND_ARG_INFO(0, attribute)
00098 ZEND_END_ARG_INFO()
00099 
00100 ZEND_BEGIN_ARG_INFO(arginfo_pdostatement_getcolumnmeta, 0)
00101        ZEND_ARG_INFO(0, column)
00102 ZEND_END_ARG_INFO()
00103 
00104 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_setfetchmode, 0, 0, 1)
00105        ZEND_ARG_INFO(0, mode)
00106        ZEND_ARG_INFO(0, params)
00107 ZEND_END_ARG_INFO()
00108 /* }}} */
00109 
00110 #define PHP_STMT_GET_OBJ    \
00111   pdo_stmt_t *stmt = (pdo_stmt_t*)zend_object_store_get_object(getThis() TSRMLS_CC);       \
00112   if (!stmt->dbh) {  \
00113     RETURN_FALSE;    \
00114   }    \
00115 
00116 static PHP_FUNCTION(dbstmt_constructor) /* {{{ */
00117 {
00118        php_error_docref(NULL TSRMLS_CC, E_ERROR, "You should not create a PDOStatement manually");
00119 }
00120 /* }}} */
00121 
00122 static inline int rewrite_name_to_position(pdo_stmt_t *stmt, struct pdo_bound_param_data *param TSRMLS_DC) /* {{{ */
00123 {
00124        if (stmt->bound_param_map) {
00125               /* rewriting :name to ? style.
00126                * We need to fixup the parameter numbers on the parameters.
00127                * If we find that a given named parameter has been used twice,
00128                * we will raise an error, as we can't be sure that it is safe
00129                * to bind multiple parameters onto the same zval in the underlying
00130                * driver */
00131               char *name;
00132               int position = 0;
00133 
00134               if (stmt->named_rewrite_template) {
00135                      /* this is not an error here */
00136                      return 1;
00137               }
00138               if (!param->name) {
00139                      /* do the reverse; map the parameter number to the name */
00140                      if (SUCCESS == zend_hash_index_find(stmt->bound_param_map, param->paramno, (void**)&name)) {
00141                             param->name = estrdup(name);
00142                             param->namelen = strlen(param->name);
00143                             return 1;
00144                      }
00145                      pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined" TSRMLS_CC);
00146                      return 0;
00147               }
00148     
00149               zend_hash_internal_pointer_reset(stmt->bound_param_map);
00150               while (SUCCESS == zend_hash_get_current_data(stmt->bound_param_map, (void**)&name)) {
00151                      if (strcmp(name, param->name)) {
00152                             position++;
00153                             zend_hash_move_forward(stmt->bound_param_map);
00154                             continue;
00155                      }
00156                      if (param->paramno >= 0) {
00157                             pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "PDO refuses to handle repeating the same :named parameter for multiple positions with this driver, as it might be unsafe to do so.  Consider using a separate name for each parameter instead" TSRMLS_CC);
00158                             return -1;
00159                      }
00160                      param->paramno = position;
00161                      return 1;
00162               }
00163               pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined" TSRMLS_CC);
00164               return 0;
00165        }
00166        return 1;     
00167 }
00168 /* }}} */
00169 
00170 /* trigger callback hook for parameters */
00171 static int dispatch_param_event(pdo_stmt_t *stmt, enum pdo_param_event event_type TSRMLS_DC) /* {{{ */
00172 {
00173        int ret = 1, is_param = 1;
00174        struct pdo_bound_param_data *param;
00175        HashTable *ht;
00176 
00177        if (!stmt->methods->param_hook) {
00178               return 1;
00179        }
00180 
00181        ht = stmt->bound_params;
00182 
00183 iterate:
00184        if (ht) {
00185               zend_hash_internal_pointer_reset(ht);
00186               while (SUCCESS == zend_hash_get_current_data(ht, (void**)&param)) {
00187                      if (!stmt->methods->param_hook(stmt, param, event_type TSRMLS_CC)) {
00188                             ret = 0;
00189                             break;
00190                      }
00191                      
00192                      zend_hash_move_forward(ht);
00193               }
00194        }
00195        if (ret && is_param) {
00196               ht = stmt->bound_columns;
00197               is_param = 0;
00198               goto iterate;
00199        }
00200 
00201        return ret;
00202 }
00203 /* }}} */
00204 
00205 int pdo_stmt_describe_columns(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
00206 {
00207        int col;
00208 
00209        stmt->columns = ecalloc(stmt->column_count, sizeof(struct pdo_column_data));
00210 
00211        for (col = 0; col < stmt->column_count; col++) {
00212               if (!stmt->methods->describer(stmt, col TSRMLS_CC)) {
00213                      return 0;
00214               }
00215 
00216               /* if we are applying case conversions on column names, do so now */
00217               if (stmt->dbh->native_case != stmt->dbh->desired_case && stmt->dbh->desired_case != PDO_CASE_NATURAL) {
00218                      char *s = stmt->columns[col].name;
00219 
00220                      switch (stmt->dbh->desired_case) {
00221                             case PDO_CASE_UPPER:
00222                                    while (*s != '\0') {
00223                                           *s = toupper(*s);
00224                                           s++;
00225                                    }
00226                                    break;
00227                             case PDO_CASE_LOWER:
00228                                    while (*s != '\0') {
00229                                           *s = tolower(*s);
00230                                           s++;
00231                                    }
00232                                    break;
00233                             default:
00234                                    ;
00235                      }
00236               }
00237 
00238 #if 0
00239               /* update the column index on named bound parameters */
00240               if (stmt->bound_params) {
00241                      struct pdo_bound_param_data *param;
00242 
00243                      if (SUCCESS == zend_hash_find(stmt->bound_params, stmt->columns[col].name,
00244                                           stmt->columns[col].namelen, (void**)&param)) {
00245                             param->paramno = col;
00246                      }
00247               }
00248 #endif
00249               if (stmt->bound_columns) {
00250                      struct pdo_bound_param_data *param;
00251 
00252                      if (SUCCESS == zend_hash_find(stmt->bound_columns, stmt->columns[col].name,
00253                                           stmt->columns[col].namelen, (void**)&param)) {
00254                             param->paramno = col;
00255                      }
00256               }
00257 
00258        }
00259        return 1;
00260 }
00261 /* }}} */
00262 
00263 static void get_lazy_object(pdo_stmt_t *stmt, zval *return_value TSRMLS_DC) /* {{{ */
00264 {
00265        if (Z_TYPE(stmt->lazy_object_ref) == IS_NULL) {
00266               Z_TYPE(stmt->lazy_object_ref) = IS_OBJECT;
00267               Z_OBJ_HANDLE(stmt->lazy_object_ref) = zend_objects_store_put(stmt, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t)pdo_row_free_storage, NULL TSRMLS_CC);
00268               Z_OBJ_HT(stmt->lazy_object_ref) = &pdo_row_object_handlers;
00269               stmt->refcount++;
00270        }
00271        Z_TYPE_P(return_value) = IS_OBJECT;
00272        Z_OBJ_HANDLE_P(return_value) = Z_OBJ_HANDLE(stmt->lazy_object_ref);
00273        Z_OBJ_HT_P(return_value) = Z_OBJ_HT(stmt->lazy_object_ref);
00274        zend_objects_store_add_ref(return_value TSRMLS_CC);
00275 }
00276 /* }}} */
00277 
00278 static void param_dtor(void *data) /* {{{ */
00279 {
00280        struct pdo_bound_param_data *param = (struct pdo_bound_param_data *)data;
00281        TSRMLS_FETCH();
00282 
00283        /* tell the driver that it is going away */
00284        if (param->stmt->methods->param_hook) {
00285               param->stmt->methods->param_hook(param->stmt, param, PDO_PARAM_EVT_FREE TSRMLS_CC);
00286        }
00287 
00288        if (param->name) {
00289               efree(param->name);
00290        }
00291 
00292        if (param->parameter) {
00293               zval_ptr_dtor(&(param->parameter));
00294               param->parameter = NULL;
00295        }
00296        if (param->driver_params) {
00297               zval_ptr_dtor(&(param->driver_params));
00298        }
00299 }
00300 /* }}} */
00301 
00302 static int really_register_bound_param(struct pdo_bound_param_data *param, pdo_stmt_t *stmt, int is_param TSRMLS_DC) /* {{{ */
00303 {
00304        HashTable *hash;
00305        struct pdo_bound_param_data *pparam = NULL;
00306 
00307        hash = is_param ? stmt->bound_params : stmt->bound_columns;
00308 
00309        if (!hash) {
00310               ALLOC_HASHTABLE(hash);
00311               zend_hash_init(hash, 13, NULL, param_dtor, 0);
00312 
00313               if (is_param) {
00314                      stmt->bound_params = hash;
00315               } else {
00316                      stmt->bound_columns = hash;
00317               }
00318        }
00319 
00320        if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_STR && param->max_value_len <= 0 && ! ZVAL_IS_NULL(param->parameter)) {
00321               if (Z_TYPE_P(param->parameter) == IS_DOUBLE) {
00322                      char *p;
00323                      int len = spprintf(&p, 0, "%.*H", (int) EG(precision), Z_DVAL_P(param->parameter));
00324                      ZVAL_STRINGL(param->parameter, p, len, 0);
00325               } else {
00326                      convert_to_string(param->parameter);
00327               }
00328        } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_INT && Z_TYPE_P(param->parameter) == IS_BOOL) {
00329               convert_to_long(param->parameter);
00330        } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_BOOL && Z_TYPE_P(param->parameter) == IS_LONG) {
00331               convert_to_boolean(param->parameter);
00332        }
00333 
00334        param->stmt = stmt;
00335        param->is_param = is_param;
00336 
00337        if (param->driver_params) {
00338               Z_ADDREF_P(param->driver_params);
00339        }
00340 
00341        if (!is_param && param->name && stmt->columns) {
00342               /* try to map the name to the column */
00343               int i;
00344 
00345               for (i = 0; i < stmt->column_count; i++) {
00346                      if (strcmp(stmt->columns[i].name, param->name) == 0) {
00347                             param->paramno = i;
00348                             break;
00349                      }
00350               }
00351 
00352               /* if you prepare and then execute passing an array of params keyed by names,
00353                * then this will trigger, and we don't want that */
00354               if (param->paramno == -1) {
00355                      char *tmp;
00356                      spprintf(&tmp, 0, "Did not find column name '%s' in the defined columns; it will not be bound", param->name);
00357                      pdo_raise_impl_error(stmt->dbh, stmt, "HY000", tmp TSRMLS_CC);
00358                      efree(tmp);
00359               }
00360        }
00361 
00362        if (param->name) {
00363               if (is_param && param->name[0] != ':') {
00364                      char *temp = emalloc(++param->namelen + 1);
00365                      temp[0] = ':';
00366                      memmove(temp+1, param->name, param->namelen);
00367                      param->name = temp;
00368               } else {
00369                      param->name = estrndup(param->name, param->namelen);
00370               }
00371        }
00372 
00373        if (is_param && !rewrite_name_to_position(stmt, param TSRMLS_CC)) {
00374               if (param->name) {
00375                      efree(param->name);
00376                      param->name = NULL;
00377               }
00378               return 0;
00379        }
00380 
00381        /* ask the driver to perform any normalization it needs on the
00382         * parameter name.  Note that it is illegal for the driver to take
00383         * a reference to param, as it resides in transient storage only
00384         * at this time. */
00385        if (stmt->methods->param_hook) {
00386               if (!stmt->methods->param_hook(stmt, param, PDO_PARAM_EVT_NORMALIZE
00387                             TSRMLS_CC)) {
00388                      if (param->name) {
00389                             efree(param->name);
00390                             param->name = NULL;
00391                      }
00392                      return 0;
00393               }
00394        }
00395 
00396        /* delete any other parameter registered with this number.
00397         * If the parameter is named, it will be removed and correctly
00398         * disposed of by the hash_update call that follows */
00399        if (param->paramno >= 0) {
00400               zend_hash_index_del(hash, param->paramno);
00401        }
00402 
00403        /* allocate storage for the parameter, keyed by its "canonical" name */
00404        if (param->name) {
00405               zend_hash_update(hash, param->name, param->namelen, param,
00406                      sizeof(*param), (void**)&pparam);
00407        } else {
00408               zend_hash_index_update(hash, param->paramno, param, sizeof(*param),
00409                      (void**)&pparam);
00410        }
00411 
00412        /* tell the driver we just created a parameter */
00413        if (stmt->methods->param_hook) {
00414               if (!stmt->methods->param_hook(stmt, pparam, PDO_PARAM_EVT_ALLOC
00415                                    TSRMLS_CC)) {
00416                      /* undo storage allocation; the hash will free the parameter
00417                       * name if required */
00418                      if (pparam->name) {
00419                             zend_hash_del(hash, pparam->name, pparam->namelen);
00420                      } else {
00421                             zend_hash_index_del(hash, pparam->paramno);
00422                      }
00423                      /* param->parameter is freed by hash dtor */
00424                      param->parameter = NULL;
00425                      return 0;
00426               }
00427        }
00428        return 1;
00429 }
00430 /* }}} */
00431 
00432 /* {{{ proto bool PDOStatement::execute([array $bound_input_params])
00433    Execute a prepared statement, optionally binding parameters */
00434 static PHP_METHOD(PDOStatement, execute)
00435 {
00436        zval *input_params = NULL;
00437        int ret = 1;
00438        PHP_STMT_GET_OBJ;
00439 
00440        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!", &input_params)) {
00441               RETURN_FALSE;
00442        }
00443 
00444        PDO_STMT_CLEAR_ERR();
00445        
00446        if (input_params) {
00447               struct pdo_bound_param_data param;
00448               zval **tmp;
00449               uint str_length;
00450               ulong num_index;
00451        
00452               if (stmt->bound_params) {   
00453                      zend_hash_destroy(stmt->bound_params);
00454                      FREE_HASHTABLE(stmt->bound_params);
00455                      stmt->bound_params = NULL;
00456               }
00457 
00458               zend_hash_internal_pointer_reset(Z_ARRVAL_P(input_params));
00459               while (SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(input_params), (void*)&tmp)) {
00460                      memset(&param, 0, sizeof(param));
00461 
00462                      if (HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(Z_ARRVAL_P(input_params),
00463                                           &param.name, &str_length, &num_index, 0, NULL)) {
00464                             /* yes this is correct.  we don't want to count the null byte.  ask wez */
00465                             param.namelen = str_length - 1;
00466                             param.paramno = -1;
00467                      } else {
00468                             /* we're okay to be zero based here */
00469                             if (num_index < 0) {
00470                                    pdo_raise_impl_error(stmt->dbh, stmt, "HY093", NULL TSRMLS_CC);
00471                                    RETURN_FALSE;
00472                             }
00473                             param.paramno = num_index;
00474                      }
00475 
00476                      param.param_type = PDO_PARAM_STR;
00477                      MAKE_STD_ZVAL(param.parameter);
00478                      MAKE_COPY_ZVAL(tmp, param.parameter);
00479 
00480                      if (!really_register_bound_param(&param, stmt, 1 TSRMLS_CC)) {
00481                             if (param.parameter) {
00482                                    zval_ptr_dtor(&param.parameter);
00483                             }
00484                             RETURN_FALSE;
00485                      }
00486 
00487                      zend_hash_move_forward(Z_ARRVAL_P(input_params));
00488               }
00489        }
00490 
00491        if (PDO_PLACEHOLDER_NONE == stmt->supports_placeholders) {
00492               /* handle the emulated parameter binding,
00493          * stmt->active_query_string holds the query with binds expanded and 
00494                * quoted.
00495          */
00496 
00497               ret = pdo_parse_params(stmt, stmt->query_string, stmt->query_stringlen,
00498                      &stmt->active_query_string, &stmt->active_query_stringlen TSRMLS_CC);
00499 
00500               if (ret == 0) {
00501                      /* no changes were made */
00502                      stmt->active_query_string = stmt->query_string;
00503                      stmt->active_query_stringlen = stmt->query_stringlen;
00504                      ret = 1;
00505               } else if (ret == -1) {
00506                      /* something broke */
00507                      PDO_HANDLE_STMT_ERR();
00508                      RETURN_FALSE;
00509               }
00510        } else if (!dispatch_param_event(stmt, PDO_PARAM_EVT_EXEC_PRE TSRMLS_CC)) {
00511               PDO_HANDLE_STMT_ERR();
00512               RETURN_FALSE;
00513        }
00514        if (stmt->methods->executer(stmt TSRMLS_CC)) {
00515               if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
00516                      efree(stmt->active_query_string);
00517               }
00518               stmt->active_query_string = NULL;
00519               if (!stmt->executed) {
00520                      /* this is the first execute */
00521 
00522                      if (stmt->dbh->alloc_own_columns && !stmt->columns) {
00523                             /* for "big boy" drivers, we need to allocate memory to fetch
00524                              * the results into, so lets do that now */
00525                             ret = pdo_stmt_describe_columns(stmt TSRMLS_CC);
00526                      }
00527 
00528                      stmt->executed = 1;
00529               }
00530 
00531               if (ret && !dispatch_param_event(stmt, PDO_PARAM_EVT_EXEC_POST TSRMLS_CC)) {
00532                      RETURN_FALSE;
00533               }
00534                      
00535               RETURN_BOOL(ret);
00536        }
00537        if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
00538               efree(stmt->active_query_string);
00539        }
00540        stmt->active_query_string = NULL;
00541        PDO_HANDLE_STMT_ERR();
00542        RETURN_FALSE;
00543 }
00544 /* }}} */
00545 
00546 static inline void fetch_value(pdo_stmt_t *stmt, zval *dest, int colno, int *type_override TSRMLS_DC) /* {{{ */
00547 {
00548        struct pdo_column_data *col;
00549        char *value = NULL;
00550        unsigned long value_len = 0;
00551        int caller_frees = 0;
00552        int type, new_type;
00553 
00554        col = &stmt->columns[colno];
00555        type = PDO_PARAM_TYPE(col->param_type);
00556        new_type =  type_override ? PDO_PARAM_TYPE(*type_override) : type;
00557 
00558        value = NULL;
00559        value_len = 0;
00560 
00561        stmt->methods->get_col(stmt, colno, &value, &value_len, &caller_frees TSRMLS_CC);
00562 
00563        switch (type) {
00564               case PDO_PARAM_ZVAL:
00565                      if (value && value_len == sizeof(zval)) {
00566                             int need_copy = (new_type != PDO_PARAM_ZVAL || stmt->dbh->stringify) ? 1 : 0;
00567                             zval *zv = *(zval**)value;
00568                             ZVAL_ZVAL(dest, zv, need_copy, 1);
00569                      } else {
00570                             ZVAL_NULL(dest);
00571                      }
00572                      
00573                      if (Z_TYPE_P(dest) == IS_NULL) {
00574                             type = new_type;
00575                      }
00576                      break;
00577                      
00578               case PDO_PARAM_INT:
00579                      if (value && value_len == sizeof(long)) {
00580                             ZVAL_LONG(dest, *(long*)value);
00581                             break;
00582                      }
00583                      ZVAL_NULL(dest);
00584                      break;
00585 
00586               case PDO_PARAM_BOOL:
00587                      if (value && value_len == sizeof(zend_bool)) {
00588                             ZVAL_BOOL(dest, *(zend_bool*)value);
00589                             break;
00590                      }
00591                      ZVAL_NULL(dest);
00592                      break;
00593 
00594               case PDO_PARAM_LOB:
00595                      if (value == NULL) {
00596                             ZVAL_NULL(dest);
00597                      } else if (value_len == 0) {
00598                             /* Warning, empty strings need to be passed as stream */
00599                             if (stmt->dbh->stringify || new_type == PDO_PARAM_STR) {
00600                                    char *buf = NULL;
00601                                    size_t len;
00602                                    len = php_stream_copy_to_mem((php_stream*)value, &buf, PHP_STREAM_COPY_ALL, 0);
00603                                    if(buf == NULL) {
00604                                           ZVAL_EMPTY_STRING(dest);
00605                                    } else {
00606                                           ZVAL_STRINGL(dest, buf, len, 0);
00607                                    }
00608                                    php_stream_close((php_stream*)value);
00609                             } else {
00610                                    php_stream_to_zval((php_stream*)value, dest);
00611                             }
00612                      } else if (!stmt->dbh->stringify && new_type != PDO_PARAM_STR) {
00613                             /* they gave us a string, but LOBs are represented as streams in PDO */
00614                             php_stream *stm;
00615 #ifdef TEMP_STREAM_TAKE_BUFFER
00616                             if (caller_frees) {
00617                                    stm = php_stream_memory_open(TEMP_STREAM_TAKE_BUFFER, value, value_len);
00618                                    if (stm) {
00619                                           caller_frees = 0;
00620                                    }
00621                             } else
00622 #endif
00623                             {
00624                                    stm = php_stream_memory_open(TEMP_STREAM_READONLY, value, value_len);
00625                             }
00626                             if (stm) {
00627                                    php_stream_to_zval(stm, dest);
00628                             } else {
00629                                    ZVAL_NULL(dest);
00630                             }
00631                      } else {
00632                             ZVAL_STRINGL(dest, value, value_len, !caller_frees);
00633                             if (caller_frees) {
00634                                    caller_frees = 0;
00635                             }
00636                      }
00637                      break;
00638               
00639               case PDO_PARAM_STR:
00640                      if (value && !(value_len == 0 && stmt->dbh->oracle_nulls == PDO_NULL_EMPTY_STRING)) {
00641                             ZVAL_STRINGL(dest, value, value_len, !caller_frees);
00642                             if (caller_frees) {
00643                                    caller_frees = 0;
00644                             }
00645                             break;
00646                      }
00647               default:
00648                      ZVAL_NULL(dest);
00649        }
00650 
00651        if (type != new_type) {
00652               switch (new_type) {
00653                      case PDO_PARAM_INT:
00654                             convert_to_long_ex(&dest);
00655                             break;
00656                      case PDO_PARAM_BOOL:
00657                             convert_to_boolean_ex(&dest);
00658                             break;
00659                      case PDO_PARAM_STR:
00660                             convert_to_string_ex(&dest);
00661                             break;
00662                      case PDO_PARAM_NULL:
00663                             convert_to_null_ex(&dest);
00664                             break;
00665                      default:
00666                             ;
00667               }
00668        }
00669        
00670        if (caller_frees && value) {
00671               efree(value);
00672        }
00673 
00674        if (stmt->dbh->stringify) {
00675               switch (Z_TYPE_P(dest)) {
00676                      case IS_LONG:
00677                      case IS_DOUBLE:
00678                             convert_to_string(dest);
00679                             break;
00680               }
00681        }
00682 
00683        if (Z_TYPE_P(dest) == IS_NULL && stmt->dbh->oracle_nulls == PDO_NULL_TO_STRING) {
00684               ZVAL_EMPTY_STRING(dest);
00685        }
00686 }
00687 /* }}} */
00688 
00689 static int do_fetch_common(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori,
00690        long offset, int do_bind TSRMLS_DC) /* {{{ */
00691 {
00692        if (!stmt->executed) {
00693               return 0;
00694        }
00695 
00696        if (!dispatch_param_event(stmt, PDO_PARAM_EVT_FETCH_PRE TSRMLS_CC)) {
00697               return 0;
00698        }
00699 
00700        if (!stmt->methods->fetcher(stmt, ori, offset TSRMLS_CC)) {
00701               return 0;
00702        }
00703 
00704        /* some drivers might need to describe the columns now */
00705        if (!stmt->columns && !pdo_stmt_describe_columns(stmt TSRMLS_CC)) {
00706               return 0;
00707        }
00708        
00709        if (!dispatch_param_event(stmt, PDO_PARAM_EVT_FETCH_POST TSRMLS_CC)) {
00710               return 0;
00711        }
00712 
00713        if (do_bind && stmt->bound_columns) {
00714               /* update those bound column variables now */
00715               struct pdo_bound_param_data *param;
00716 
00717               zend_hash_internal_pointer_reset(stmt->bound_columns);
00718               while (SUCCESS == zend_hash_get_current_data(stmt->bound_columns, (void**)&param)) {
00719                      if (param->paramno >= 0) {
00720                             convert_to_string(param->parameter);
00721 
00722                             /* delete old value */
00723                             zval_dtor(param->parameter);
00724 
00725                             /* set new value */
00726                             fetch_value(stmt, param->parameter, param->paramno, (int *)&param->param_type TSRMLS_CC);
00727 
00728                             /* TODO: some smart thing that avoids duplicating the value in the
00729                              * general loop below.  For now, if you're binding output columns,
00730                              * it's better to use LAZY or BOUND fetches if you want to shave
00731                              * off those cycles */
00732                      }
00733 
00734                      zend_hash_move_forward(stmt->bound_columns);
00735               }
00736        }
00737 
00738        return 1;
00739 }
00740 /* }}} */
00741 
00742 static int do_fetch_class_prepare(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
00743 {
00744        zend_class_entry * ce = stmt->fetch.cls.ce;
00745        zend_fcall_info * fci = &stmt->fetch.cls.fci;
00746        zend_fcall_info_cache * fcc = &stmt->fetch.cls.fcc;
00747 
00748        fci->size = sizeof(zend_fcall_info);
00749 
00750        if (!ce) {
00751               stmt->fetch.cls.ce = ZEND_STANDARD_CLASS_DEF_PTR;
00752               ce = ZEND_STANDARD_CLASS_DEF_PTR;
00753        }
00754        
00755        if (ce->constructor) {
00756               fci->function_table = &ce->function_table;
00757               fci->function_name = NULL;
00758               fci->symbol_table = NULL;
00759               fci->retval_ptr_ptr = &stmt->fetch.cls.retval_ptr;
00760               if (stmt->fetch.cls.ctor_args) {
00761                      HashTable *ht = Z_ARRVAL_P(stmt->fetch.cls.ctor_args);
00762                      Bucket *p;
00763 
00764                      fci->param_count = 0;
00765                      fci->params = safe_emalloc(sizeof(zval**), ht->nNumOfElements, 0);
00766                      p = ht->pListHead;
00767                      while (p != NULL) {
00768                             fci->params[fci->param_count++] = (zval**)p->pData;
00769                             p = p->pListNext;
00770                      }
00771               } else {
00772                      fci->param_count = 0;
00773                      fci->params = NULL;
00774               }
00775               fci->no_separation = 1;
00776 
00777               fcc->initialized = 1;
00778               fcc->function_handler = ce->constructor;
00779               fcc->calling_scope = EG(scope);
00780               fcc->called_scope = ce;
00781               return 1;
00782        } else if (stmt->fetch.cls.ctor_args) {
00783               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied class does not have a constructor, use NULL for the ctor_params parameter, or simply omit it" TSRMLS_CC);
00784               return 0;
00785        } else {
00786               return 1; /* no ctor no args is also ok */
00787        }
00788 }
00789 /* }}} */
00790 
00791 static int make_callable_ex(pdo_stmt_t *stmt, zval *callable, zend_fcall_info * fci, zend_fcall_info_cache * fcc, int num_args TSRMLS_DC) /* {{{ */
00792 {
00793        char *is_callable_error = NULL;
00794 
00795        if (zend_fcall_info_init(callable, 0, fci, fcc, NULL, &is_callable_error TSRMLS_CC) == FAILURE) { 
00796               if (is_callable_error) {
00797                      pdo_raise_impl_error(stmt->dbh, stmt, "HY000", is_callable_error TSRMLS_CC);
00798                      efree(is_callable_error);
00799               } else {
00800                      pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied function must be a valid callback" TSRMLS_CC);
00801               }
00802               return 0;
00803        }
00804        if (is_callable_error) {
00805               /* Possible E_STRICT error message */
00806               efree(is_callable_error);
00807        }
00808        
00809        fci->param_count = num_args; /* probably less */
00810        fci->params = safe_emalloc(sizeof(zval**), num_args, 0);
00811        
00812        return 1;
00813 }
00814 /* }}} */
00815 
00816 static int do_fetch_func_prepare(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
00817 {
00818        zend_fcall_info * fci = &stmt->fetch.cls.fci;
00819        zend_fcall_info_cache * fcc = &stmt->fetch.cls.fcc;
00820 
00821        if (!make_callable_ex(stmt, stmt->fetch.func.function, fci, fcc, stmt->column_count TSRMLS_CC)) {
00822               return 0;
00823        } else {
00824               stmt->fetch.func.values = safe_emalloc(sizeof(zval*), stmt->column_count, 0);
00825               return 1;
00826        }
00827 }
00828 /* }}} */
00829 
00830 static int do_fetch_opt_finish(pdo_stmt_t *stmt, int free_ctor_agrs TSRMLS_DC) /* {{{ */
00831 {
00832        /* fci.size is used to check if it is valid */
00833        if (stmt->fetch.cls.fci.size && stmt->fetch.cls.fci.params) {
00834               efree(stmt->fetch.cls.fci.params);
00835               stmt->fetch.cls.fci.params = NULL;
00836        }
00837        stmt->fetch.cls.fci.size = 0;
00838        if (stmt->fetch.cls.ctor_args && free_ctor_agrs) {
00839               zval_ptr_dtor(&stmt->fetch.cls.ctor_args);
00840               stmt->fetch.cls.ctor_args = NULL;
00841               stmt->fetch.cls.fci.param_count = 0;
00842        }
00843        if (stmt->fetch.func.values) {
00844               efree(stmt->fetch.func.values);
00845               stmt->fetch.func.values = NULL;
00846        }
00847        return 1;
00848 }
00849 /* }}} */
00850 
00851 /* perform a fetch.  If do_bind is true, update any bound columns.
00852  * If return_value is not null, store values into it according to HOW. */
00853 static int do_fetch(pdo_stmt_t *stmt, int do_bind, zval *return_value,
00854        enum pdo_fetch_type how, enum pdo_fetch_orientation ori, long offset, zval *return_all TSRMLS_DC) /* {{{ */
00855 {
00856        int flags, idx, old_arg_count = 0;
00857        zend_class_entry *ce = NULL, *old_ce = NULL;
00858        zval grp_val, *grp, **pgrp, *retval, *old_ctor_args = NULL;
00859        int colno;
00860 
00861        if (how == PDO_FETCH_USE_DEFAULT) {
00862               how = stmt->default_fetch_type;
00863        }
00864        flags = how & PDO_FETCH_FLAGS;
00865        how = how & ~PDO_FETCH_FLAGS;
00866 
00867        if (!do_fetch_common(stmt, ori, offset, do_bind TSRMLS_CC)) {
00868               return 0;
00869        }
00870 
00871        if (how == PDO_FETCH_BOUND) {
00872               RETVAL_TRUE;
00873               return 1;
00874        }
00875 
00876        if (flags & PDO_FETCH_GROUP && stmt->fetch.column == -1) {
00877               colno = 1;
00878        } else {
00879               colno = stmt->fetch.column;
00880        }
00881 
00882        if (return_value) {
00883               int i = 0;
00884 
00885               if (how == PDO_FETCH_LAZY) {
00886                      get_lazy_object(stmt, return_value TSRMLS_CC);
00887                      return 1;
00888               }
00889 
00890               RETVAL_FALSE;
00891 
00892               switch (how) {
00893                      case PDO_FETCH_USE_DEFAULT:
00894                      case PDO_FETCH_ASSOC:
00895                      case PDO_FETCH_BOTH:
00896                      case PDO_FETCH_NUM:
00897                      case PDO_FETCH_NAMED:
00898                             if (!return_all) {
00899                                    ALLOC_HASHTABLE(return_value->value.ht);
00900                                    zend_hash_init(return_value->value.ht, stmt->column_count, NULL, ZVAL_PTR_DTOR, 0);
00901                                    Z_TYPE_P(return_value) = IS_ARRAY;
00902                             } else {
00903                                    array_init(return_value);
00904                             }
00905                             break;
00906 
00907                      case PDO_FETCH_KEY_PAIR:
00908                             if (stmt->column_count != 2) {
00909                                    pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_KEY_PAIR fetch mode requires the result set to contain extactly 2 columns." TSRMLS_CC);
00910                                    return 0;
00911                             }
00912                             if (!return_all) {
00913                                    array_init(return_value);
00914                             }
00915                             break;
00916 
00917                      case PDO_FETCH_COLUMN:
00918                             if (colno >= 0 && colno < stmt->column_count) {
00919                                    if (flags == PDO_FETCH_GROUP && stmt->fetch.column == -1) {
00920                                           fetch_value(stmt, return_value, 1, NULL TSRMLS_CC);
00921                                    } else if (flags == PDO_FETCH_GROUP && colno) {
00922                                           fetch_value(stmt, return_value, 0, NULL TSRMLS_CC);
00923                                    } else {
00924                                           fetch_value(stmt, return_value, colno, NULL TSRMLS_CC); 
00925                                    }
00926                                    if (!return_all) {
00927                                           return 1;
00928                                    } else {
00929                                           break;
00930                                    }
00931                             } else {
00932                                    pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Invalid column index" TSRMLS_CC);
00933                             }
00934                             return 0;
00935 
00936                      case PDO_FETCH_OBJ:
00937                             object_init_ex(return_value, ZEND_STANDARD_CLASS_DEF_PTR);
00938                             break;
00939 
00940                      case PDO_FETCH_CLASS:
00941                             if (flags & PDO_FETCH_CLASSTYPE) {
00942                                    zval val;
00943                                    zend_class_entry **cep;
00944 
00945                                    old_ce = stmt->fetch.cls.ce;
00946                                    old_ctor_args = stmt->fetch.cls.ctor_args;
00947                                    old_arg_count = stmt->fetch.cls.fci.param_count;
00948                                    do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
00949 
00950                                    INIT_PZVAL(&val);
00951                                    fetch_value(stmt, &val, i++, NULL TSRMLS_CC);
00952                                    if (Z_TYPE(val) != IS_NULL) {
00953                                           convert_to_string(&val);
00954                                           if (zend_lookup_class(Z_STRVAL(val), Z_STRLEN(val), &cep TSRMLS_CC) == FAILURE) {
00955                                                  stmt->fetch.cls.ce = ZEND_STANDARD_CLASS_DEF_PTR;
00956                                           } else {
00957                                                  stmt->fetch.cls.ce = *cep;
00958                                           }
00959                                    }
00960 
00961                                    do_fetch_class_prepare(stmt TSRMLS_CC);
00962                                    zval_dtor(&val);
00963                             }
00964                             ce = stmt->fetch.cls.ce;
00965                             if (!ce) {
00966                                    pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch class specified" TSRMLS_CC);
00967                                    return 0;
00968                             }
00969                             if ((flags & PDO_FETCH_SERIALIZE) == 0) {
00970                                    object_init_ex(return_value, ce);
00971                                    if (!stmt->fetch.cls.fci.size) {
00972                                           if (!do_fetch_class_prepare(stmt TSRMLS_CC))
00973                                           {
00974                                                  return 0;
00975                                           }
00976                                    }
00977                                    if (ce->constructor && (flags & PDO_FETCH_PROPS_LATE)) {
00978                                           stmt->fetch.cls.fci.object_ptr = return_value;
00979                                           stmt->fetch.cls.fcc.object_ptr = return_value;
00980                                           if (zend_call_function(&stmt->fetch.cls.fci, &stmt->fetch.cls.fcc TSRMLS_CC) == FAILURE) {
00981                                                  pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call class constructor" TSRMLS_CC);
00982                                                  return 0;
00983                                           } else {
00984                                                  if (stmt->fetch.cls.retval_ptr) {
00985                                                         zval_ptr_dtor(&stmt->fetch.cls.retval_ptr);
00986                                                  }
00987                                           }
00988                                    }
00989                             }
00990                             break;
00991                      
00992                      case PDO_FETCH_INTO:
00993                             if (!stmt->fetch.into) {
00994                                    pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch-into object specified." TSRMLS_CC);
00995                                    return 0;
00996                                    break;
00997                             }
00998 
00999                             Z_TYPE_P(return_value) = IS_OBJECT;
01000                             Z_OBJ_HANDLE_P(return_value) = Z_OBJ_HANDLE_P(stmt->fetch.into);
01001                             Z_OBJ_HT_P(return_value) = Z_OBJ_HT_P(stmt->fetch.into);
01002                             zend_objects_store_add_ref(stmt->fetch.into TSRMLS_CC);
01003 
01004                             if (zend_get_class_entry(return_value TSRMLS_CC) == ZEND_STANDARD_CLASS_DEF_PTR) {
01005                                    how = PDO_FETCH_OBJ;
01006                             }
01007                             break;
01008 
01009                      case PDO_FETCH_FUNC:
01010                             if (!stmt->fetch.func.function) {
01011                                    pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch function specified" TSRMLS_CC);
01012                                    return 0;
01013                             }
01014                             if (!stmt->fetch.func.fci.size) {
01015                                    if (!do_fetch_func_prepare(stmt TSRMLS_CC))
01016                                    {
01017                                           return 0;
01018                                    }
01019                             }
01020                             break;
01021                             
01022 
01023                      default:
01024                             /* shouldn't happen */
01025                             return 0;
01026               }
01027               
01028               if (return_all && how != PDO_FETCH_KEY_PAIR) {
01029                      INIT_PZVAL(&grp_val);
01030                      if (flags == PDO_FETCH_GROUP && how == PDO_FETCH_COLUMN && stmt->fetch.column > 0) {
01031                             fetch_value(stmt, &grp_val, colno, NULL TSRMLS_CC);
01032                      } else {
01033                             fetch_value(stmt, &grp_val, i, NULL TSRMLS_CC);
01034                      }
01035                      convert_to_string(&grp_val);
01036                      if (how == PDO_FETCH_COLUMN) {
01037                             i = stmt->column_count; /* no more data to fetch */
01038                      } else {
01039                             i++;
01040                      }
01041               }
01042 
01043               for (idx = 0; i < stmt->column_count; i++, idx++) {
01044                      zval *val;
01045                      MAKE_STD_ZVAL(val);
01046                      fetch_value(stmt, val, i, NULL TSRMLS_CC);
01047 
01048                      switch (how) {
01049                             case PDO_FETCH_ASSOC:
01050                                    add_assoc_zval(return_value, stmt->columns[i].name, val);
01051                                    break;
01052                                    
01053                             case PDO_FETCH_KEY_PAIR:
01054                                    {
01055                                           zval *tmp;
01056                                           MAKE_STD_ZVAL(tmp);
01057                                           fetch_value(stmt, tmp, ++i, NULL TSRMLS_CC);
01058 
01059                                           if (Z_TYPE_P(val) == IS_LONG) {
01060                                                  zend_hash_index_update((return_all ? Z_ARRVAL_P(return_all) : Z_ARRVAL_P(return_value)), Z_LVAL_P(val), &tmp, sizeof(zval *), NULL);
01061                                           } else {
01062                                                  convert_to_string(val);
01063                                                  zend_symtable_update((return_all ? Z_ARRVAL_P(return_all) : Z_ARRVAL_P(return_value)), Z_STRVAL_P(val), Z_STRLEN_P(val) + 1, &tmp, sizeof(zval *), NULL);
01064                                           }
01065                                           zval_ptr_dtor(&val);
01066                                           return 1;
01067                                    }
01068                                    break;
01069 
01070                             case PDO_FETCH_USE_DEFAULT:
01071                             case PDO_FETCH_BOTH:
01072                                    add_assoc_zval(return_value, stmt->columns[i].name, val);
01073                                    Z_ADDREF_P(val);
01074                                    add_next_index_zval(return_value, val);
01075                                    break;
01076 
01077                             case PDO_FETCH_NAMED:
01078                                    /* already have an item with this name? */
01079                                    {
01080                                           zval **curr_val = NULL;
01081                                           if (zend_hash_find(Z_ARRVAL_P(return_value), stmt->columns[i].name,
01082                                                                strlen(stmt->columns[i].name)+1,
01083                                                                (void**)&curr_val) == SUCCESS) {
01084                                                  zval *arr;
01085                                                  if (Z_TYPE_PP(curr_val) != IS_ARRAY) {
01086                                                         /* a little bit of black magic here:
01087                                                          * we're creating a new array and swapping it for the
01088                                                          * zval that's already stored in the hash under the name
01089                                                          * we want.  We then add that zval to the array.
01090                                                          * This is effectively the same thing as:
01091                                                          * if (!is_array($hash[$name])) {
01092                                                          *   $hash[$name] = array($hash[$name]);
01093                                                          * }
01094                                                          * */
01095                                                         zval *cur;
01096 
01097                                                         MAKE_STD_ZVAL(arr);
01098                                                         array_init(arr);
01099 
01100                                                         cur = *curr_val;
01101                                                         *curr_val = arr;
01102 
01103                                                         add_next_index_zval(arr, cur);
01104                                                  } else {
01105                                                         arr = *curr_val;
01106                                                  }
01107                                                  add_next_index_zval(arr, val);
01108                                           } else {
01109                                                  add_assoc_zval(return_value, stmt->columns[i].name, val);
01110                                           }
01111                                    }
01112                                    break;
01113 
01114                             case PDO_FETCH_NUM:
01115                                    add_next_index_zval(return_value, val);
01116                                    break;
01117 
01118                             case PDO_FETCH_OBJ:
01119                             case PDO_FETCH_INTO:
01120                                    zend_update_property(NULL, return_value,
01121                                           stmt->columns[i].name, stmt->columns[i].namelen,
01122                                           val TSRMLS_CC);
01123                                    zval_ptr_dtor(&val);
01124                                    break;
01125 
01126                             case PDO_FETCH_CLASS:
01127                                    if ((flags & PDO_FETCH_SERIALIZE) == 0 || idx) {
01128                                           zend_update_property(ce, return_value,
01129                                                  stmt->columns[i].name, stmt->columns[i].namelen,
01130                                                  val TSRMLS_CC);
01131                                           zval_ptr_dtor(&val);
01132                                    } else {
01133 #ifdef MBO_0
01134                                           php_unserialize_data_t var_hash;
01135 
01136                                           PHP_VAR_UNSERIALIZE_INIT(var_hash);
01137                                           if (php_var_unserialize(&return_value, (const unsigned char**)&Z_STRVAL_P(val), Z_STRVAL_P(val)+Z_STRLEN_P(val), NULL TSRMLS_CC) == FAILURE) {
01138                                                  pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize data" TSRMLS_CC);
01139                                                  PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
01140                                                  return 0;
01141                                           }
01142                                           PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
01143 #endif
01144 #if PHP_MAJOR_VERSION > 5 || PHP_MINOR_VERSION >= 1
01145                                           if (!ce->unserialize) {
01146                                                  zval_ptr_dtor(&val);
01147                                                  pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize class" TSRMLS_CC);
01148                                                  return 0;
01149                                           } else if (ce->unserialize(&return_value, ce, Z_TYPE_P(val) == IS_STRING ? Z_STRVAL_P(val) : "", Z_TYPE_P(val) == IS_STRING ? Z_STRLEN_P(val) : 0, NULL TSRMLS_CC) == FAILURE) {
01150                                                  zval_ptr_dtor(&val);
01151                                                  pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize class" TSRMLS_CC);
01152                                                  zval_dtor(return_value);
01153                                                  ZVAL_NULL(return_value);
01154                                                  return 0;
01155                                           } else {
01156                                                  zval_ptr_dtor(&val);
01157                                           }
01158 #endif
01159                                    }
01160                                    break;
01161                             
01162                             case PDO_FETCH_FUNC:
01163                                    stmt->fetch.func.values[idx] = val;
01164                                    stmt->fetch.cls.fci.params[idx] = &stmt->fetch.func.values[idx];
01165                                    break;
01166                             
01167                             default:
01168                                    zval_ptr_dtor(&val);
01169                                    pdo_raise_impl_error(stmt->dbh, stmt, "22003", "mode is out of range" TSRMLS_CC);
01170                                    return 0;
01171                                    break;
01172                      }
01173               }
01174               
01175               switch (how) {
01176                      case PDO_FETCH_CLASS:
01177                             if (ce->constructor && !(flags & (PDO_FETCH_PROPS_LATE | PDO_FETCH_SERIALIZE))) {
01178                                    stmt->fetch.cls.fci.object_ptr = return_value;
01179                                    stmt->fetch.cls.fcc.object_ptr = return_value;
01180                                    if (zend_call_function(&stmt->fetch.cls.fci, &stmt->fetch.cls.fcc TSRMLS_CC) == FAILURE) {
01181                                           pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call class constructor" TSRMLS_CC);
01182                                           return 0;
01183                                    } else {
01184                                           if (stmt->fetch.cls.retval_ptr) {
01185                                                  zval_ptr_dtor(&stmt->fetch.cls.retval_ptr);
01186                                           }
01187                                    }
01188                             }
01189                             if (flags & PDO_FETCH_CLASSTYPE) {
01190                                    do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
01191                                    stmt->fetch.cls.ce = old_ce;
01192                                    stmt->fetch.cls.ctor_args = old_ctor_args;
01193                                    stmt->fetch.cls.fci.param_count = old_arg_count;
01194                             }
01195                             break;
01196 
01197                      case PDO_FETCH_FUNC:
01198                             stmt->fetch.func.fci.param_count = idx;
01199                             stmt->fetch.func.fci.retval_ptr_ptr = &retval;
01200                             if (zend_call_function(&stmt->fetch.func.fci, &stmt->fetch.func.fcc TSRMLS_CC) == FAILURE) {
01201                                    pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call user-supplied function" TSRMLS_CC);
01202                                    return 0;
01203                             } else {
01204                                    if (return_all) {
01205                                           zval_ptr_dtor(&return_value); /* we don't need that */
01206                                           return_value = retval;
01207                                    } else if (retval) {
01208                                           MAKE_COPY_ZVAL(&retval, return_value);
01209                                           zval_ptr_dtor(&retval);
01210                                    }
01211                             }
01212                             while(idx--) {
01213                                    zval_ptr_dtor(&stmt->fetch.func.values[idx]);
01214                             }
01215                             break;
01216                      
01217                      default:
01218                             break;
01219               }
01220 
01221               if (return_all) {
01222                      if ((flags & PDO_FETCH_UNIQUE) == PDO_FETCH_UNIQUE) {
01223                             add_assoc_zval(return_all, Z_STRVAL(grp_val), return_value);
01224                      } else {
01225                             if (zend_symtable_find(Z_ARRVAL_P(return_all), Z_STRVAL(grp_val), Z_STRLEN(grp_val)+1, (void**)&pgrp) == FAILURE) {
01226                                    MAKE_STD_ZVAL(grp);
01227                                    array_init(grp);
01228                                    add_assoc_zval(return_all, Z_STRVAL(grp_val), grp);
01229                             } else {
01230                                    grp = *pgrp;
01231                             }
01232                             add_next_index_zval(grp, return_value);
01233                      }
01234                      zval_dtor(&grp_val);
01235               }
01236 
01237        }
01238 
01239        return 1;
01240 }
01241 /* }}} */
01242 
01243 static int pdo_stmt_verify_mode(pdo_stmt_t *stmt, long mode, int fetch_all TSRMLS_DC) /* {{{ */
01244 {
01245        int flags = mode & PDO_FETCH_FLAGS;
01246 
01247        mode = mode & ~PDO_FETCH_FLAGS;
01248 
01249        if (mode < 0 || mode > PDO_FETCH__MAX) {
01250               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "invalid fetch mode" TSRMLS_CC);
01251               return 0;
01252        }
01253        
01254        if (mode == PDO_FETCH_USE_DEFAULT) {
01255               flags = stmt->default_fetch_type & PDO_FETCH_FLAGS;
01256               mode = stmt->default_fetch_type & ~PDO_FETCH_FLAGS;
01257        }
01258 
01259 #if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 1
01260        if ((flags & PDO_FETCH_SERIALIZE) == PDO_FETCH_SERIALIZE) {
01261               pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "PDO::FETCH_SERIALIZE is not supported in this PHP version" TSRMLS_CC);
01262               return 0;
01263        }
01264 #endif
01265 
01266        switch(mode) {
01267        case PDO_FETCH_FUNC:
01268               if (!fetch_all) {
01269                      pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_FUNC is only allowed in PDOStatement::fetchAll()" TSRMLS_CC);
01270                      return 0;
01271               }
01272               return 1;
01273 
01274        case PDO_FETCH_LAZY:
01275               if (fetch_all) {
01276                      pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_LAZY can't be used with PDOStatement::fetchAll()" TSRMLS_CC);
01277                      return 0;
01278               }
01279               /* fall through */
01280        
01281        default:
01282               if ((flags & PDO_FETCH_SERIALIZE) == PDO_FETCH_SERIALIZE) {
01283                      pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_SERIALIZE can only be used together with PDO::FETCH_CLASS" TSRMLS_CC);
01284                      return 0;
01285               }
01286               if ((flags & PDO_FETCH_CLASSTYPE) == PDO_FETCH_CLASSTYPE) {
01287                      pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_CLASSTYPE can only be used together with PDO::FETCH_CLASS" TSRMLS_CC);
01288                      return 0;
01289               }
01290               if (mode >= PDO_FETCH__MAX) {
01291                      pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "invalid fetch mode" TSRMLS_CC);
01292                      return 0;
01293               }
01294               /* no break; */
01295 
01296        case PDO_FETCH_CLASS:
01297               return 1;
01298        }
01299 }
01300 /* }}} */
01301 
01302 /* {{{ proto mixed PDOStatement::fetch([int $how = PDO_FETCH_BOTH [, int $orientation [, int $offset]]])
01303    Fetches the next row and returns it, or false if there are no more rows */
01304 static PHP_METHOD(PDOStatement, fetch)
01305 {
01306        long how = PDO_FETCH_USE_DEFAULT;
01307        long ori = PDO_FETCH_ORI_NEXT;
01308        long off = 0;
01309         PHP_STMT_GET_OBJ;
01310 
01311        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lll", &how,
01312                      &ori, &off)) {
01313               RETURN_FALSE;
01314        }
01315 
01316        PDO_STMT_CLEAR_ERR();
01317 
01318        if (!pdo_stmt_verify_mode(stmt, how, 0 TSRMLS_CC)) {
01319               RETURN_FALSE;
01320        }
01321 
01322        if (!do_fetch(stmt, TRUE, return_value, how, ori, off, 0 TSRMLS_CC)) {
01323               PDO_HANDLE_STMT_ERR();
01324               RETURN_FALSE;
01325        }
01326 }
01327 /* }}} */
01328 
01329 /* {{{ proto mixed PDOStatement::fetchObject([string class_name [, NULL|array ctor_args]])
01330    Fetches the next row and returns it as an object. */
01331 static PHP_METHOD(PDOStatement, fetchObject)
01332 {
01333        long how = PDO_FETCH_CLASS;
01334        long ori = PDO_FETCH_ORI_NEXT;
01335        long off = 0;
01336        char *class_name;
01337        int class_name_len;
01338        zend_class_entry *old_ce;
01339        zval *old_ctor_args, *ctor_args;
01340        int error = 0, old_arg_count;
01341 
01342        PHP_STMT_GET_OBJ;
01343 
01344        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sz", 
01345               &class_name, &class_name_len, &ctor_args)) {
01346               RETURN_FALSE;
01347        }
01348 
01349        PDO_STMT_CLEAR_ERR();
01350 
01351        if (!pdo_stmt_verify_mode(stmt, how, 0 TSRMLS_CC)) {
01352               RETURN_FALSE;
01353        }
01354 
01355        old_ce = stmt->fetch.cls.ce;
01356        old_ctor_args = stmt->fetch.cls.ctor_args;
01357        old_arg_count = stmt->fetch.cls.fci.param_count;
01358        
01359        do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
01360        
01361        switch(ZEND_NUM_ARGS()) {
01362        case 0:
01363               stmt->fetch.cls.ce = zend_standard_class_def;
01364               break;
01365        case 2:
01366               if (Z_TYPE_P(ctor_args) != IS_NULL && Z_TYPE_P(ctor_args) != IS_ARRAY) {
01367                      pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array" TSRMLS_CC);
01368                      error = 1;
01369                      break;
01370               }
01371               if (Z_TYPE_P(ctor_args) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(ctor_args))) {
01372                      ALLOC_ZVAL(stmt->fetch.cls.ctor_args);
01373                      *stmt->fetch.cls.ctor_args = *ctor_args;
01374                      zval_copy_ctor(stmt->fetch.cls.ctor_args);
01375               } else {
01376                      stmt->fetch.cls.ctor_args = NULL;
01377               }
01378               /* no break */
01379        case 1:
01380               stmt->fetch.cls.ce = zend_fetch_class(class_name, class_name_len, ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
01381 
01382               if (!stmt->fetch.cls.ce) {
01383                      pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Could not find user-supplied class" TSRMLS_CC);
01384                      error = 1;
01385                      break;
01386               }
01387        }
01388 
01389        if (!error && !do_fetch(stmt, TRUE, return_value, how, ori, off, 0 TSRMLS_CC)) {
01390               error = 1;
01391        }
01392        if (error) {
01393               PDO_HANDLE_STMT_ERR();
01394        }
01395        do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
01396 
01397        stmt->fetch.cls.ce = old_ce;
01398        stmt->fetch.cls.ctor_args = old_ctor_args;
01399        stmt->fetch.cls.fci.param_count = old_arg_count;
01400        if (error) {
01401               RETURN_FALSE;
01402        }
01403 }
01404 /* }}} */
01405 
01406 /* {{{ proto string PDOStatement::fetchColumn([int column_number])
01407    Returns a data of the specified column in the result set. */
01408 static PHP_METHOD(PDOStatement, fetchColumn)
01409 {
01410        long col_n = 0;
01411        PHP_STMT_GET_OBJ;
01412 
01413        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &col_n)) {
01414               RETURN_FALSE;
01415        }
01416 
01417        PDO_STMT_CLEAR_ERR();
01418 
01419        if (!do_fetch_common(stmt, PDO_FETCH_ORI_NEXT, 0, TRUE TSRMLS_CC)) {
01420               PDO_HANDLE_STMT_ERR();
01421               RETURN_FALSE;
01422        }
01423 
01424        fetch_value(stmt, return_value, col_n, NULL TSRMLS_CC);
01425 }
01426 /* }}} */
01427 
01428 /* {{{ proto array PDOStatement::fetchAll([int $how = PDO_FETCH_BOTH [, string class_name [, NULL|array ctor_args]]])
01429    Returns an array of all of the results. */
01430 static PHP_METHOD(PDOStatement, fetchAll)
01431 {
01432        long how = PDO_FETCH_USE_DEFAULT;
01433        zval *data, *return_all;
01434        zval *arg2;
01435        zend_class_entry *old_ce;
01436        zval *old_ctor_args, *ctor_args = NULL;
01437        int error = 0, flags, old_arg_count;
01438        PHP_STMT_GET_OBJ;             
01439 
01440        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lzz", &how, &arg2, &ctor_args)) {
01441               RETURN_FALSE;
01442        }
01443 
01444        if (!pdo_stmt_verify_mode(stmt, how, 1 TSRMLS_CC)) {
01445               RETURN_FALSE;
01446        }
01447 
01448        old_ce = stmt->fetch.cls.ce;
01449        old_ctor_args = stmt->fetch.cls.ctor_args;
01450        old_arg_count = stmt->fetch.cls.fci.param_count;
01451 
01452        do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
01453 
01454        switch(how & ~PDO_FETCH_FLAGS) {
01455        case PDO_FETCH_CLASS:
01456               switch(ZEND_NUM_ARGS()) {
01457               case 0:
01458               case 1:
01459                      stmt->fetch.cls.ce = zend_standard_class_def;
01460                      break;
01461               case 3:
01462                      if (Z_TYPE_P(ctor_args) != IS_NULL && Z_TYPE_P(ctor_args) != IS_ARRAY) {
01463                             pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array" TSRMLS_CC);
01464                             error = 1;
01465                             break;
01466                      }
01467                      if (Z_TYPE_P(ctor_args) != IS_ARRAY || !zend_hash_num_elements(Z_ARRVAL_P(ctor_args))) {
01468                             ctor_args = NULL;
01469                      }
01470                      /* no break */
01471               case 2:
01472                      stmt->fetch.cls.ctor_args = ctor_args; /* we're not going to free these */
01473                      if (Z_TYPE_P(arg2) != IS_STRING) {
01474                             pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Invalid class name (should be a string)" TSRMLS_CC);
01475                             error = 1;
01476                             break;
01477                      } else {
01478                             stmt->fetch.cls.ce = zend_fetch_class(Z_STRVAL_P(arg2), Z_STRLEN_P(arg2), ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
01479                             if (!stmt->fetch.cls.ce) {
01480                                    pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not find user-specified class" TSRMLS_CC);
01481                                    error = 1;
01482                                    break;
01483                             }
01484                      }
01485               }
01486               if (!error) {
01487                      do_fetch_class_prepare(stmt TSRMLS_CC);
01488               }
01489               break;
01490 
01491        case PDO_FETCH_FUNC:
01492               switch(ZEND_NUM_ARGS()) {
01493               case 0:
01494               case 1:
01495                      pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "no fetch function specified" TSRMLS_CC);
01496                      error = 1;
01497                      break;
01498               case 3:
01499               case 2:
01500                      stmt->fetch.func.function = arg2;
01501                      if (do_fetch_func_prepare(stmt TSRMLS_CC) == 0) {
01502                             error = 1;
01503                      }
01504                      break;
01505               }
01506               break;
01507        
01508        case PDO_FETCH_COLUMN:
01509               switch(ZEND_NUM_ARGS()) {
01510               case 0:
01511               case 1:
01512                      stmt->fetch.column = how & PDO_FETCH_GROUP ? -1 : 0;
01513                      break;
01514               case 2:
01515                      convert_to_long(arg2);
01516                      stmt->fetch.column = Z_LVAL_P(arg2);
01517                      break;
01518               case 3:
01519                      pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Third parameter not allowed for PDO::FETCH_COLUMN" TSRMLS_CC);
01520                      error = 1;
01521               }
01522               break;
01523 
01524        default:
01525               if (ZEND_NUM_ARGS() > 1) {
01526                      pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Extraneous additional parameters" TSRMLS_CC);
01527                      error = 1;
01528               }
01529        }
01530 
01531        flags = how & PDO_FETCH_FLAGS;
01532        
01533        if ((how & ~PDO_FETCH_FLAGS) == PDO_FETCH_USE_DEFAULT) {
01534               flags |= stmt->default_fetch_type & PDO_FETCH_FLAGS;
01535               how |= stmt->default_fetch_type & ~PDO_FETCH_FLAGS;
01536        }
01537 
01538        if (!error)   {
01539               PDO_STMT_CLEAR_ERR();
01540               MAKE_STD_ZVAL(data);
01541               if (   (how & PDO_FETCH_GROUP) || how == PDO_FETCH_KEY_PAIR || 
01542                      (how == PDO_FETCH_USE_DEFAULT && stmt->default_fetch_type == PDO_FETCH_KEY_PAIR)
01543               ) {
01544                      array_init(return_value);
01545                      return_all = return_value;
01546               } else {
01547                      return_all = 0;
01548               }
01549               if (!do_fetch(stmt, TRUE, data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all TSRMLS_CC)) {
01550                      FREE_ZVAL(data);
01551                      error = 2;
01552               }
01553        }
01554        if (!error) {
01555               if ((how & PDO_FETCH_GROUP)) {
01556                      do {
01557                             MAKE_STD_ZVAL(data);
01558                      } while (do_fetch(stmt, TRUE, data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all TSRMLS_CC));
01559               } else if (how == PDO_FETCH_KEY_PAIR || (how == PDO_FETCH_USE_DEFAULT && stmt->default_fetch_type == PDO_FETCH_KEY_PAIR)) {
01560                      while (do_fetch(stmt, TRUE, data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all TSRMLS_CC));
01561               } else {
01562                      array_init(return_value);
01563                      do {
01564                             add_next_index_zval(return_value, data);
01565                             MAKE_STD_ZVAL(data);
01566                      } while (do_fetch(stmt, TRUE, data, how | flags, PDO_FETCH_ORI_NEXT, 0, 0 TSRMLS_CC));
01567               }
01568               FREE_ZVAL(data);
01569        }
01570        
01571        do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
01572 
01573        stmt->fetch.cls.ce = old_ce;
01574        stmt->fetch.cls.ctor_args = old_ctor_args;
01575        stmt->fetch.cls.fci.param_count = old_arg_count;
01576        
01577        if (error) {
01578               PDO_HANDLE_STMT_ERR();
01579               if (error != 2) {
01580                      RETURN_FALSE;
01581               } else { /* on no results, return an empty array */
01582                      if (Z_TYPE_P(return_value) != IS_ARRAY) {
01583                             array_init(return_value);
01584                      }
01585                      return;
01586               }
01587        }
01588 }
01589 /* }}} */
01590 
01591 static int register_bound_param(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int is_param) /* {{{ */
01592 {
01593        struct pdo_bound_param_data param = {0};
01594        long param_type = PDO_PARAM_STR;
01595 
01596        param.paramno = -1;
01597 
01598        if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC,
01599                      "lz|llz!", &param.paramno, &param.parameter, &param_type, &param.max_value_len,
01600                      &param.driver_params)) {
01601               if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|llz!", &param.name,
01602                             &param.namelen, &param.parameter, &param_type, &param.max_value_len, 
01603                             &param.driver_params)) {
01604                      return 0;
01605               }      
01606        }
01607        
01608        param.param_type = (int) param_type;
01609        
01610        if (param.paramno > 0) {
01611               --param.paramno; /* make it zero-based internally */
01612        } else if (!param.name) {
01613               pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "Columns/Parameters are 1-based" TSRMLS_CC);
01614               return 0;
01615        }
01616 
01617        Z_ADDREF_P(param.parameter);
01618        if (!really_register_bound_param(&param, stmt, is_param TSRMLS_CC)) {
01619               if (param.parameter) {
01620                      zval_ptr_dtor(&(param.parameter));
01621                      param.parameter = NULL;
01622               }
01623               return 0;
01624        }
01625        return 1;
01626 } /* }}} */
01627 
01628 /* {{{ proto bool PDOStatement::bindValue(mixed $paramno, mixed $param [, int $type ])
01629    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(). */
01630 static PHP_METHOD(PDOStatement, bindValue)
01631 {
01632        struct pdo_bound_param_data param = {0};
01633        long param_type = PDO_PARAM_STR;
01634        PHP_STMT_GET_OBJ;
01635 
01636        param.paramno = -1;
01637        
01638        if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC,
01639                      "lz/|l", &param.paramno, &param.parameter, &param_type)) {
01640               if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz/|l", &param.name,
01641                             &param.namelen, &param.parameter, &param_type)) {
01642                      RETURN_FALSE;
01643               }
01644        }
01645 
01646        param.param_type = (int) param_type;
01647        
01648        if (param.paramno > 0) {
01649               --param.paramno; /* make it zero-based internally */
01650        } else if (!param.name) {
01651               pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "Columns/Parameters are 1-based" TSRMLS_CC);
01652               RETURN_FALSE;
01653        }
01654        
01655        Z_ADDREF_P(param.parameter);
01656        if (!really_register_bound_param(&param, stmt, TRUE TSRMLS_CC)) {
01657               if (param.parameter) {
01658                      zval_ptr_dtor(&(param.parameter));
01659                      param.parameter = NULL;
01660               }
01661               RETURN_FALSE;
01662        }
01663        RETURN_TRUE;
01664 }
01665 /* }}} */
01666 
01667 
01668 /* {{{ proto bool PDOStatement::bindParam(mixed $paramno, mixed &$param [, int $type [, int $maxlen [, mixed $driverdata]]])
01669    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(). */
01670 static PHP_METHOD(PDOStatement, bindParam)
01671 {
01672        PHP_STMT_GET_OBJ;
01673        RETURN_BOOL(register_bound_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, TRUE));
01674 }
01675 /* }}} */
01676 
01677 /* {{{ proto bool PDOStatement::bindColumn(mixed $column, mixed &$param [, int $type [, int $maxlen [, mixed $driverdata]]])
01678    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(). */
01679 static PHP_METHOD(PDOStatement, bindColumn)
01680 {
01681        PHP_STMT_GET_OBJ;
01682        RETURN_BOOL(register_bound_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, FALSE));
01683 }
01684 /* }}} */
01685 
01686 /* {{{ proto int PDOStatement::rowCount()
01687    Returns the number of rows in a result set, or the number of rows affected by the last execute().  It is not always meaningful. */
01688 static PHP_METHOD(PDOStatement, rowCount)
01689 {
01690        PHP_STMT_GET_OBJ;
01691 
01692        RETURN_LONG(stmt->row_count);
01693 }
01694 /* }}} */
01695 
01696 /* {{{ proto string PDOStatement::errorCode()
01697    Fetch the error code associated with the last operation on the statement handle */
01698 static PHP_METHOD(PDOStatement, errorCode)
01699 {
01700        PHP_STMT_GET_OBJ;
01701 
01702        if (zend_parse_parameters_none() == FAILURE) {
01703               return;
01704        }
01705 
01706        if (stmt->error_code[0] == '\0') {
01707               RETURN_NULL();
01708        }
01709 
01710        RETURN_STRING(stmt->error_code, 1);
01711 }
01712 /* }}} */
01713 
01714 /* {{{ proto array PDOStatement::errorInfo()
01715    Fetch extended error information associated with the last operation on the statement handle */
01716 static PHP_METHOD(PDOStatement, errorInfo)
01717 {
01718        int error_count;
01719        int error_count_diff     = 0;
01720        int error_expected_count = 3;
01721 
01722        PHP_STMT_GET_OBJ;
01723 
01724        if (zend_parse_parameters_none() == FAILURE) {
01725               return;
01726        }
01727 
01728        array_init(return_value);
01729        add_next_index_string(return_value, stmt->error_code, 1);
01730 
01731        if (stmt->dbh->methods->fetch_err) {
01732               stmt->dbh->methods->fetch_err(stmt->dbh, stmt, return_value TSRMLS_CC);
01733        }
01734 
01735        error_count = zend_hash_num_elements(Z_ARRVAL_P(return_value));
01736 
01737        if (error_expected_count > error_count) {
01738               int current_index;
01739 
01740               error_count_diff = error_expected_count - error_count;
01741               for (current_index = 0; current_index < error_count_diff; current_index++) {
01742                      add_next_index_null(return_value);
01743               }
01744        }
01745 }
01746 /* }}} */
01747 
01748 /* {{{ proto bool PDOStatement::setAttribute(long attribute, mixed value)
01749    Set an attribute */
01750 static PHP_METHOD(PDOStatement, setAttribute)
01751 {
01752        long attr;
01753        zval *value = NULL;
01754        PHP_STMT_GET_OBJ;
01755 
01756        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz!", &attr, &value)) {
01757               RETURN_FALSE;
01758        }
01759 
01760        if (!stmt->methods->set_attribute) {
01761               goto fail;
01762        }
01763 
01764        PDO_STMT_CLEAR_ERR();
01765        if (stmt->methods->set_attribute(stmt, attr, value TSRMLS_CC)) {
01766               RETURN_TRUE;
01767        }
01768 
01769 fail:
01770        if (!stmt->methods->set_attribute) {
01771               pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "This driver doesn't support setting attributes" TSRMLS_CC);
01772        } else {
01773               PDO_HANDLE_STMT_ERR();
01774        }
01775        RETURN_FALSE;
01776 }
01777 /* }}} */
01778 
01779 /* {{{ proto mixed PDOStatement::getAttribute(long attribute)
01780    Get an attribute */
01781 
01782 static int generic_stmt_attr_get(pdo_stmt_t *stmt, zval *return_value, long attr)
01783 {
01784        switch (attr) {
01785               case PDO_ATTR_EMULATE_PREPARES:
01786                      RETVAL_BOOL(stmt->supports_placeholders == PDO_PLACEHOLDER_NONE);
01787                      return 1;
01788        }
01789        return 0;
01790 }
01791    
01792 static PHP_METHOD(PDOStatement, getAttribute)
01793 {
01794        long attr;
01795        PHP_STMT_GET_OBJ;
01796 
01797        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &attr)) {
01798               RETURN_FALSE;
01799        }
01800 
01801        if (!stmt->methods->get_attribute) {
01802               if (!generic_stmt_attr_get(stmt, return_value, attr)) {
01803                      pdo_raise_impl_error(stmt->dbh, stmt, "IM001",
01804                             "This driver doesn't support getting attributes" TSRMLS_CC);
01805                      RETURN_FALSE;
01806               }
01807               return;
01808        }
01809 
01810        PDO_STMT_CLEAR_ERR();
01811        switch (stmt->methods->get_attribute(stmt, attr, return_value TSRMLS_CC)) {
01812               case -1:
01813                      PDO_HANDLE_STMT_ERR();
01814                      RETURN_FALSE;
01815 
01816               case 0:
01817                      if (!generic_stmt_attr_get(stmt, return_value, attr)) {
01818                             /* XXX: should do something better here */
01819                             pdo_raise_impl_error(stmt->dbh, stmt, "IM001",
01820                                    "driver doesn't support getting that attribute" TSRMLS_CC);
01821                             RETURN_FALSE;
01822                      }
01823                      return;
01824 
01825               default:
01826                      return;
01827        }
01828 }
01829 /* }}} */
01830 
01831 /* {{{ proto int PDOStatement::columnCount()
01832    Returns the number of columns in the result set */
01833 static PHP_METHOD(PDOStatement, columnCount)
01834 {
01835        PHP_STMT_GET_OBJ;
01836        if (zend_parse_parameters_none() == FAILURE) {
01837               return;
01838        }
01839        RETURN_LONG(stmt->column_count);
01840 }
01841 /* }}} */
01842 
01843 /* {{{ proto array PDOStatement::getColumnMeta(int $column)
01844    Returns meta data for a numbered column */
01845 static PHP_METHOD(PDOStatement, getColumnMeta)
01846 {
01847        long colno;
01848        struct pdo_column_data *col;
01849        PHP_STMT_GET_OBJ;
01850 
01851        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &colno)) {
01852               RETURN_FALSE;
01853        }
01854        if(colno < 0) {
01855               pdo_raise_impl_error(stmt->dbh, stmt, "42P10", "column number must be non-negative" TSRMLS_CC);
01856               RETURN_FALSE;
01857        }
01858 
01859        if (!stmt->methods->get_column_meta) {
01860               pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "driver doesn't support meta data" TSRMLS_CC);
01861               RETURN_FALSE;
01862        }
01863 
01864        PDO_STMT_CLEAR_ERR();
01865        if (FAILURE == stmt->methods->get_column_meta(stmt, colno, return_value TSRMLS_CC)) {
01866               PDO_HANDLE_STMT_ERR();
01867               RETURN_FALSE;
01868        }
01869 
01870        /* add stock items */
01871        col = &stmt->columns[colno];
01872        add_assoc_string(return_value, "name", col->name, 1);
01873        add_assoc_long(return_value, "len", col->maxlen); /* FIXME: unsigned ? */
01874        add_assoc_long(return_value, "precision", col->precision);
01875        if (col->param_type != PDO_PARAM_ZVAL) {
01876               /* if param_type is PDO_PARAM_ZVAL the driver has to provide correct data */
01877               add_assoc_long(return_value, "pdo_type", col->param_type);
01878        }
01879 }
01880 /* }}} */
01881 
01882 /* {{{ proto bool PDOStatement::setFetchMode(int mode [mixed* params])
01883    Changes the default fetch mode for subsequent fetches (params have different meaning for different fetch modes) */
01884 
01885 int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int skip)
01886 {
01887        long mode = PDO_FETCH_BOTH;
01888        int flags, argc = ZEND_NUM_ARGS() - skip;
01889        zval ***args;
01890        zend_class_entry **cep;
01891        int retval;
01892        
01893        do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
01894 
01895        switch (stmt->default_fetch_type) {
01896               case PDO_FETCH_INTO:
01897                      if (stmt->fetch.into) {
01898                             zval_ptr_dtor(&stmt->fetch.into);
01899                             stmt->fetch.into = NULL;
01900                      }
01901                      break;
01902               default:
01903                      ;
01904        }
01905        
01906        stmt->default_fetch_type = PDO_FETCH_BOTH;
01907 
01908        if (argc == 0) {
01909               return SUCCESS;
01910        }
01911 
01912        args = safe_emalloc(ZEND_NUM_ARGS(), sizeof(zval*), 0);
01913 
01914        retval = zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args);
01915        
01916        if (SUCCESS == retval) {
01917               if (Z_TYPE_PP(args[skip]) != IS_LONG) {
01918                      pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "mode must be an integer" TSRMLS_CC);
01919                      retval = FAILURE;
01920               } else {
01921                      mode = Z_LVAL_PP(args[skip]);
01922                      flags = mode & PDO_FETCH_FLAGS;
01923        
01924                      retval = pdo_stmt_verify_mode(stmt, mode, 0 TSRMLS_CC);
01925               }
01926        }
01927        
01928        if (FAILURE == retval) {
01929               PDO_STMT_CLEAR_ERR();
01930               efree(args);
01931               return FAILURE;
01932        }
01933 
01934        retval = FAILURE;
01935        switch (mode & ~PDO_FETCH_FLAGS) {
01936               case PDO_FETCH_USE_DEFAULT:
01937               case PDO_FETCH_LAZY:
01938               case PDO_FETCH_ASSOC:
01939               case PDO_FETCH_NUM:
01940               case PDO_FETCH_BOTH:
01941               case PDO_FETCH_OBJ:
01942               case PDO_FETCH_BOUND:
01943               case PDO_FETCH_NAMED:
01944               case PDO_FETCH_KEY_PAIR:
01945                      if (argc != 1) {
01946                             pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode doesn't allow any extra arguments" TSRMLS_CC);
01947                      } else {
01948                             retval = SUCCESS;
01949                      }
01950                      break;
01951 
01952               case PDO_FETCH_COLUMN:
01953                      if (argc != 2) {
01954                             pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the colno argument" TSRMLS_CC);
01955                      } else if (Z_TYPE_PP(args[skip+1]) != IS_LONG) {
01956                             pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "colno must be an integer" TSRMLS_CC);
01957                      } else {
01958                             stmt->fetch.column = Z_LVAL_PP(args[skip+1]);
01959                             retval = SUCCESS;
01960                      }
01961                      break;
01962 
01963               case PDO_FETCH_CLASS:
01964                      /* Gets its class name from 1st column */
01965                      if ((flags & PDO_FETCH_CLASSTYPE) == PDO_FETCH_CLASSTYPE) {
01966                             if (argc != 1) {
01967                                    pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode doesn't allow any extra arguments" TSRMLS_CC);
01968                             } else {
01969                                    stmt->fetch.cls.ce = NULL;
01970                                    retval = SUCCESS;
01971                             }
01972                      } else {
01973                             if (argc < 2) {
01974                                    pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the classname argument" TSRMLS_CC);
01975                             } else if (argc > 3) {
01976                                    pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "too many arguments" TSRMLS_CC);
01977                             } else if (Z_TYPE_PP(args[skip+1]) != IS_STRING) {
01978                                    pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "classname must be a string" TSRMLS_CC);
01979                             } else {
01980                                    retval = zend_lookup_class(Z_STRVAL_PP(args[skip+1]),
01981                                           Z_STRLEN_PP(args[skip+1]), &cep TSRMLS_CC);
01982 
01983                                    if (SUCCESS == retval && cep && *cep) {
01984                                           stmt->fetch.cls.ce = *cep;
01985                                    }
01986                             }
01987                      }
01988 
01989                      if (SUCCESS == retval) {
01990                             stmt->fetch.cls.ctor_args = NULL;
01991 #ifdef ilia_0 /* we'll only need this when we have persistent statements, if ever */
01992                             if (stmt->dbh->is_persistent) {
01993                                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "PHP might crash if you don't call $stmt->setFetchMode() to reset to defaults on this persistent statement.  This will be fixed in a later release");
01994                             }
01995 #endif
01996                             if (argc == 3) {
01997                                    if (Z_TYPE_PP(args[skip+2]) != IS_NULL && Z_TYPE_PP(args[skip+2]) != IS_ARRAY) {
01998                                           pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array" TSRMLS_CC);
01999                                           retval = FAILURE;
02000                                    } else if (Z_TYPE_PP(args[skip+2]) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_PP(args[skip+2]))) {
02001                                           ALLOC_ZVAL(stmt->fetch.cls.ctor_args);
02002                                           *stmt->fetch.cls.ctor_args = **args[skip+2];
02003                                           zval_copy_ctor(stmt->fetch.cls.ctor_args);
02004                                    }
02005                             }
02006 
02007                             if (SUCCESS == retval) {
02008                                    do_fetch_class_prepare(stmt TSRMLS_CC);
02009                             }
02010                      }
02011                      
02012                      break;
02013 
02014               case PDO_FETCH_INTO:
02015                      if (argc != 2) {
02016                             pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the object parameter" TSRMLS_CC);
02017                      } else if (Z_TYPE_PP(args[skip+1]) != IS_OBJECT) {
02018                             pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "object must be an object" TSRMLS_CC);
02019                      } else {
02020                             retval = SUCCESS;
02021                      }
02022                      
02023                      if (SUCCESS == retval) {
02024 #ifdef ilia_0 /* we'll only need this when we have persistent statements, if ever */
02025                             if (stmt->dbh->is_persistent) {
02026                                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "PHP might crash if you don't call $stmt->setFetchMode() to reset to defaults on this persistent statement.  This will be fixed in a later release");
02027                             }
02028 #endif 
02029                             MAKE_STD_ZVAL(stmt->fetch.into);
02030 
02031                             Z_TYPE_P(stmt->fetch.into) = IS_OBJECT;
02032                             Z_OBJ_HANDLE_P(stmt->fetch.into) = Z_OBJ_HANDLE_PP(args[skip+1]);
02033                             Z_OBJ_HT_P(stmt->fetch.into) = Z_OBJ_HT_PP(args[skip+1]);
02034                             zend_objects_store_add_ref(stmt->fetch.into TSRMLS_CC);
02035                      }
02036                      
02037                      break;
02038               
02039               default:
02040                      pdo_raise_impl_error(stmt->dbh, stmt, "22003", "Invalid fetch mode specified" TSRMLS_CC);
02041        }
02042 
02043        if (SUCCESS == retval) {
02044               stmt->default_fetch_type = mode;
02045        }
02046 
02047        /*
02048         * PDO error (if any) has already been raised at this point.
02049         *
02050         * The error_code is cleared, otherwise the caller will read the
02051         * last error message from the driver.
02052         *
02053         */
02054        PDO_STMT_CLEAR_ERR();
02055 
02056        efree(args);
02057               
02058        return retval;
02059 }
02060    
02061 static PHP_METHOD(PDOStatement, setFetchMode)
02062 {
02063        PHP_STMT_GET_OBJ;
02064 
02065        RETVAL_BOOL(
02066               pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAM_PASSTHRU,
02067                      stmt, 0) == SUCCESS ? 1 : 0
02068               );
02069 }
02070 /* }}} */
02071 
02072 /* {{{ proto bool PDOStatement::nextRowset()
02073    Advances to the next rowset in a multi-rowset statement handle. Returns true if it succeded, false otherwise */
02074 
02075 static int pdo_stmt_do_next_rowset(pdo_stmt_t *stmt TSRMLS_DC)
02076 {
02077        /* un-describe */
02078        if (stmt->columns) {
02079               int i;
02080               struct pdo_column_data *cols = stmt->columns;
02081               
02082               for (i = 0; i < stmt->column_count; i++) {
02083                      efree(cols[i].name);
02084               }
02085               efree(stmt->columns);
02086               stmt->columns = NULL;
02087               stmt->column_count = 0;
02088        }
02089 
02090        if (!stmt->methods->next_rowset(stmt TSRMLS_CC)) {
02091               /* Set the executed flag to 0 to reallocate columns on next execute */
02092               stmt->executed = 0;
02093               return 0;
02094        }
02095 
02096        pdo_stmt_describe_columns(stmt TSRMLS_CC);
02097 
02098        return 1;
02099 }
02100 
02101 static PHP_METHOD(PDOStatement, nextRowset)
02102 {
02103        PHP_STMT_GET_OBJ;
02104 
02105        if (!stmt->methods->next_rowset) {
02106               pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "driver does not support multiple rowsets" TSRMLS_CC);
02107               RETURN_FALSE;
02108        }
02109 
02110        PDO_STMT_CLEAR_ERR();
02111        
02112        if (!pdo_stmt_do_next_rowset(stmt TSRMLS_CC)) {
02113               PDO_HANDLE_STMT_ERR();
02114               RETURN_FALSE;
02115        }
02116 
02117        RETURN_TRUE;
02118 }
02119 /* }}} */
02120 
02121 /* {{{ proto bool PDOStatement::closeCursor()
02122    Closes the cursor, leaving the statement ready for re-execution. */
02123 static PHP_METHOD(PDOStatement, closeCursor)
02124 {
02125        PHP_STMT_GET_OBJ;
02126 
02127        if (!stmt->methods->cursor_closer) {
02128               /* emulate it by fetching and discarding rows */
02129               do {
02130                      while (stmt->methods->fetcher(stmt, PDO_FETCH_ORI_NEXT, 0 TSRMLS_CC))
02131                             ;
02132                      if (!stmt->methods->next_rowset) {
02133                             break;
02134                      }
02135 
02136                      if (!pdo_stmt_do_next_rowset(stmt TSRMLS_CC)) {
02137                             break;
02138                      }
02139                             
02140               } while (1);
02141               stmt->executed = 0;
02142               RETURN_TRUE;
02143        }
02144 
02145        PDO_STMT_CLEAR_ERR();
02146 
02147        if (!stmt->methods->cursor_closer(stmt TSRMLS_CC)) {
02148               PDO_HANDLE_STMT_ERR();
02149               RETURN_FALSE;
02150        }
02151        stmt->executed = 0;
02152        RETURN_TRUE;
02153 }
02154 /* }}} */
02155 
02156 /* {{{ proto void PDOStatement::debugDumpParams()
02157    A utility for internals hackers to debug parameter internals */
02158 static PHP_METHOD(PDOStatement, debugDumpParams)
02159 {
02160        php_stream *out = php_stream_open_wrapper("php://output", "w", 0, NULL);
02161        HashPosition pos;
02162        struct pdo_bound_param_data *param;
02163        PHP_STMT_GET_OBJ;
02164 
02165        if (out == NULL) {
02166               RETURN_FALSE;
02167        }
02168        
02169        php_stream_printf(out TSRMLS_CC, "SQL: [%d] %.*s\n",
02170               stmt->query_stringlen,
02171               stmt->query_stringlen, stmt->query_string);
02172 
02173        php_stream_printf(out TSRMLS_CC, "Params:  %d\n",
02174               stmt->bound_params ? zend_hash_num_elements(stmt->bound_params) : 0);
02175        
02176        if (stmt->bound_params) {
02177               zend_hash_internal_pointer_reset_ex(stmt->bound_params, &pos);
02178               while (SUCCESS == zend_hash_get_current_data_ex(stmt->bound_params,
02179                             (void**)&param, &pos)) {
02180                      char *str;
02181                      uint len;
02182                      ulong num;
02183                      int res;
02184 
02185                      res = zend_hash_get_current_key_ex(stmt->bound_params, &str, &len, &num, 0, &pos);
02186                      if (res == HASH_KEY_IS_LONG) {
02187                             php_stream_printf(out TSRMLS_CC, "Key: Position #%ld:\n", num);
02188                      } else if (res == HASH_KEY_IS_STRING) {
02189                             php_stream_printf(out TSRMLS_CC, "Key: Name: [%d] %.*s\n", len, len, str);
02190                      }
02191 
02192                      php_stream_printf(out TSRMLS_CC, "paramno=%ld\nname=[%d] \"%.*s\"\nis_param=%d\nparam_type=%d\n",
02193                             param->paramno, param->namelen, param->namelen, param->name ? param->name : "",
02194                             param->is_param,
02195                             param->param_type);
02196                      
02197                      zend_hash_move_forward_ex(stmt->bound_params, &pos);
02198               }
02199        }
02200 
02201        php_stream_close(out);
02202 }
02203 /* }}} */
02204 
02205 /* {{{ proto int PDOStatement::__wakeup()
02206    Prevents use of a PDOStatement instance that has been unserialized */
02207 static PHP_METHOD(PDOStatement, __wakeup)
02208 {
02209        zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "You cannot serialize or unserialize PDOStatement instances");
02210 }
02211 /* }}} */
02212 
02213 /* {{{ proto int PDOStatement::__sleep()
02214    Prevents serialization of a PDOStatement instance */
02215 static PHP_METHOD(PDOStatement, __sleep)
02216 {
02217        zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "You cannot serialize or unserialize PDOStatement instances");
02218 }
02219 /* }}} */
02220 
02221 const zend_function_entry pdo_dbstmt_functions[] = {
02222        PHP_ME(PDOStatement, execute,             arginfo_pdostatement_execute,             ZEND_ACC_PUBLIC)
02223        PHP_ME(PDOStatement, fetch,               arginfo_pdostatement_fetch,               ZEND_ACC_PUBLIC)
02224        PHP_ME(PDOStatement, bindParam,           arginfo_pdostatement_bindparam,           ZEND_ACC_PUBLIC)
02225        PHP_ME(PDOStatement, bindColumn,   arginfo_pdostatement_bindcolumn,   ZEND_ACC_PUBLIC)
02226        PHP_ME(PDOStatement, bindValue,           arginfo_pdostatement_bindvalue,           ZEND_ACC_PUBLIC)
02227        PHP_ME(PDOStatement, rowCount,            arginfo_pdostatement__void,               ZEND_ACC_PUBLIC)
02228        PHP_ME(PDOStatement, fetchColumn,  arginfo_pdostatement_fetchcolumn,  ZEND_ACC_PUBLIC)
02229        PHP_ME(PDOStatement, fetchAll,            arginfo_pdostatement_fetchall,            ZEND_ACC_PUBLIC)
02230        PHP_ME(PDOStatement, fetchObject,  arginfo_pdostatement_fetchobject,  ZEND_ACC_PUBLIC)
02231        PHP_ME(PDOStatement, errorCode,           arginfo_pdostatement__void,               ZEND_ACC_PUBLIC)
02232        PHP_ME(PDOStatement, errorInfo,           arginfo_pdostatement__void,               ZEND_ACC_PUBLIC)
02233        PHP_ME(PDOStatement, setAttribute, arginfo_pdostatement_setattribute, ZEND_ACC_PUBLIC)
02234        PHP_ME(PDOStatement, getAttribute, arginfo_pdostatement_getattribute, ZEND_ACC_PUBLIC)
02235        PHP_ME(PDOStatement, columnCount,  arginfo_pdostatement__void,               ZEND_ACC_PUBLIC)
02236        PHP_ME(PDOStatement, getColumnMeta,       arginfo_pdostatement_getcolumnmeta,       ZEND_ACC_PUBLIC)
02237        PHP_ME(PDOStatement, setFetchMode, arginfo_pdostatement_setfetchmode, ZEND_ACC_PUBLIC)
02238        PHP_ME(PDOStatement, nextRowset,   arginfo_pdostatement__void,               ZEND_ACC_PUBLIC)
02239        PHP_ME(PDOStatement, closeCursor,  arginfo_pdostatement__void,               ZEND_ACC_PUBLIC)
02240        PHP_ME(PDOStatement, debugDumpParams, arginfo_pdostatement__void,            ZEND_ACC_PUBLIC)
02241        PHP_ME(PDOStatement, __wakeup,            arginfo_pdostatement__void,               ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
02242        PHP_ME(PDOStatement, __sleep,             arginfo_pdostatement__void,               ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
02243        {NULL, NULL, NULL}
02244 };
02245 
02246 /* {{{ overloaded handlers for PDOStatement class */
02247 static void dbstmt_prop_write(zval *object, zval *member, zval *value TSRMLS_DC)
02248 {
02249        pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
02250 
02251        convert_to_string(member);
02252 
02253        if(strcmp(Z_STRVAL_P(member), "queryString") == 0) {
02254               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "property queryString is read only" TSRMLS_CC);
02255        } else {
02256               std_object_handlers.write_property(object, member, value TSRMLS_CC);
02257        }
02258 }
02259 
02260 static void dbstmt_prop_delete(zval *object, zval *member TSRMLS_DC)
02261 {
02262        pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
02263 
02264        convert_to_string(member);
02265 
02266        if(strcmp(Z_STRVAL_P(member), "queryString") == 0) {
02267               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "property queryString is read only" TSRMLS_CC);
02268        } else {
02269               std_object_handlers.unset_property(object, member TSRMLS_CC);
02270        }
02271 }
02272 
02273 static union _zend_function *dbstmt_method_get(
02274 #if PHP_API_VERSION >= 20041225
02275        zval **object_pp,
02276 #else
02277        zval *object,
02278 #endif
02279        char *method_name, int method_len TSRMLS_DC)
02280 {
02281        zend_function *fbc = NULL;
02282        char *lc_method_name;
02283 #if PHP_API_VERSION >= 20041225
02284        zval *object = *object_pp;
02285 #endif
02286 
02287        lc_method_name = emalloc(method_len + 1);
02288        zend_str_tolower_copy(lc_method_name, method_name, method_len);
02289 
02290        if (zend_hash_find(&Z_OBJCE_P(object)->function_table, lc_method_name, 
02291                      method_len+1, (void**)&fbc) == FAILURE) {
02292               pdo_stmt_t *stmt = (pdo_stmt_t*)zend_object_store_get_object(object TSRMLS_CC);
02293               /* instance not created by PDO object */
02294               if (!stmt->dbh) {
02295                      goto out;
02296               }
02297               /* not a pre-defined method, nor a user-defined method; check
02298                * the driver specific methods */
02299               if (!stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT]) {
02300                      if (!pdo_hash_methods(stmt->dbh, 
02301                             PDO_DBH_DRIVER_METHOD_KIND_STMT TSRMLS_CC)
02302                             || !stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT]) {
02303                             goto out;
02304                      }
02305               }
02306 
02307               if (zend_hash_find(stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT],
02308                             lc_method_name, method_len+1, (void**)&fbc) == FAILURE) {
02309                      fbc = NULL;
02310                      goto out;
02311               }
02312               /* got it */
02313        }
02314        
02315 out:
02316        efree(lc_method_name);
02317        return fbc;
02318 }
02319 
02320 static int dbstmt_compare(zval *object1, zval *object2 TSRMLS_DC)
02321 {
02322        return -1;
02323 }
02324 
02325 static zend_object_value dbstmt_clone_obj(zval *zobject TSRMLS_DC)
02326 {
02327        zend_object_value retval;
02328        zval *tmp;
02329        pdo_stmt_t *stmt;
02330        pdo_stmt_t *old_stmt;
02331        zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
02332 
02333        stmt = ecalloc(1, sizeof(*stmt));
02334        stmt->ce = Z_OBJCE_P(zobject);
02335        stmt->refcount = 1;
02336        ALLOC_HASHTABLE(stmt->properties);
02337        zend_hash_init(stmt->properties, 0, NULL, ZVAL_PTR_DTOR, 0);
02338        zend_hash_copy(stmt->properties, &stmt->ce->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
02339 
02340        old_stmt = (pdo_stmt_t *)zend_object_store_get_object(zobject TSRMLS_CC);
02341        
02342        retval.handle = zend_objects_store_put(stmt, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t)pdo_dbstmt_free_storage, (zend_objects_store_clone_t)dbstmt_clone_obj TSRMLS_CC);
02343        retval.handlers = Z_OBJ_HT_P(zobject);
02344 
02345        zend_objects_clone_members((zend_object *)stmt, retval, (zend_object *)old_stmt, handle TSRMLS_CC);
02346        
02347        zend_objects_store_add_ref(&old_stmt->database_object_handle TSRMLS_CC);
02348        stmt->database_object_handle = old_stmt->database_object_handle;
02349                      
02350        return retval;
02351 }
02352 
02353 zend_object_handlers pdo_dbstmt_object_handlers;
02354 static int pdo_row_serialize(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC);
02355 
02356 void pdo_stmt_init(TSRMLS_D)
02357 {
02358        zend_class_entry ce;
02359 
02360        INIT_CLASS_ENTRY(ce, "PDOStatement", pdo_dbstmt_functions);
02361        pdo_dbstmt_ce = zend_register_internal_class(&ce TSRMLS_CC);
02362        pdo_dbstmt_ce->get_iterator = pdo_stmt_iter_get;
02363        pdo_dbstmt_ce->create_object = pdo_dbstmt_new;
02364        zend_class_implements(pdo_dbstmt_ce TSRMLS_CC, 1, zend_ce_traversable); 
02365        zend_declare_property_null(pdo_dbstmt_ce, "queryString", sizeof("queryString")-1, ZEND_ACC_PUBLIC TSRMLS_CC);
02366 
02367        memcpy(&pdo_dbstmt_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
02368        pdo_dbstmt_object_handlers.write_property = dbstmt_prop_write;
02369        pdo_dbstmt_object_handlers.unset_property = dbstmt_prop_delete;
02370        pdo_dbstmt_object_handlers.get_method = dbstmt_method_get;
02371        pdo_dbstmt_object_handlers.compare_objects = dbstmt_compare;
02372        pdo_dbstmt_object_handlers.clone_obj = dbstmt_clone_obj;
02373 
02374        INIT_CLASS_ENTRY(ce, "PDORow", pdo_row_functions);
02375        pdo_row_ce = zend_register_internal_class(&ce TSRMLS_CC);
02376        pdo_row_ce->ce_flags |= ZEND_ACC_FINAL_CLASS; /* when removing this a lot of handlers need to be redone */
02377        pdo_row_ce->create_object = pdo_row_new;
02378        pdo_row_ce->serialize = pdo_row_serialize;
02379 }
02380 
02381 static void free_statement(pdo_stmt_t *stmt TSRMLS_DC)
02382 {
02383        if (stmt->properties) {
02384               zend_hash_destroy(stmt->properties);
02385               efree(stmt->properties);
02386               stmt->properties = NULL;
02387        }
02388 
02389        if (stmt->bound_params) {
02390               zend_hash_destroy(stmt->bound_params);
02391               FREE_HASHTABLE(stmt->bound_params);
02392               stmt->bound_params = NULL;
02393        }
02394        if (stmt->bound_param_map) {
02395               zend_hash_destroy(stmt->bound_param_map);
02396               FREE_HASHTABLE(stmt->bound_param_map);
02397               stmt->bound_param_map = NULL;
02398        }
02399        if (stmt->bound_columns) {
02400               zend_hash_destroy(stmt->bound_columns);
02401               FREE_HASHTABLE(stmt->bound_columns);
02402               stmt->bound_columns = NULL;
02403        }
02404 
02405        if (stmt->methods && stmt->methods->dtor) {
02406               stmt->methods->dtor(stmt TSRMLS_CC);
02407        }
02408        if (stmt->query_string) {
02409               efree(stmt->query_string);
02410        }
02411 
02412        if (stmt->columns) {
02413               int i;
02414               struct pdo_column_data *cols = stmt->columns;
02415 
02416               for (i = 0; i < stmt->column_count; i++) {
02417                      if (cols[i].name) {
02418                             efree(cols[i].name);
02419                             cols[i].name = NULL;
02420                      }
02421               }
02422               efree(stmt->columns);
02423               stmt->columns = NULL;
02424        }
02425 
02426        if (stmt->fetch.into && stmt->default_fetch_type == PDO_FETCH_INTO) {
02427               FREE_ZVAL(stmt->fetch.into);
02428               stmt->fetch.into = NULL;
02429        }
02430        
02431        do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
02432 
02433        zend_objects_store_del_ref(&stmt->database_object_handle TSRMLS_CC);
02434        if (stmt->dbh) {
02435               php_pdo_dbh_delref(stmt->dbh TSRMLS_CC);
02436        }
02437        efree(stmt);
02438 }
02439 
02440 PDO_API void php_pdo_stmt_addref(pdo_stmt_t *stmt TSRMLS_DC)
02441 {
02442        stmt->refcount++;
02443 }
02444 
02445 PDO_API void php_pdo_stmt_delref(pdo_stmt_t *stmt TSRMLS_DC)
02446 {
02447        if (--stmt->refcount == 0) {
02448               free_statement(stmt TSRMLS_CC);
02449        }
02450 }
02451 
02452 void pdo_dbstmt_free_storage(pdo_stmt_t *stmt TSRMLS_DC)
02453 {
02454        php_pdo_stmt_delref(stmt TSRMLS_CC);
02455 }
02456 
02457 zend_object_value pdo_dbstmt_new(zend_class_entry *ce TSRMLS_DC)
02458 {
02459        zend_object_value retval;
02460        zval *tmp;
02461 
02462        pdo_stmt_t *stmt;
02463        stmt = emalloc(sizeof(*stmt));
02464        memset(stmt, 0, sizeof(*stmt));
02465        stmt->ce = ce;
02466        stmt->refcount = 1;
02467        ALLOC_HASHTABLE(stmt->properties);
02468        zend_hash_init(stmt->properties, 0, NULL, ZVAL_PTR_DTOR, 0);
02469        zend_hash_copy(stmt->properties, &ce->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
02470 
02471        retval.handle = zend_objects_store_put(stmt, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t)pdo_dbstmt_free_storage, (zend_objects_store_clone_t)dbstmt_clone_obj TSRMLS_CC);
02472        retval.handlers = &pdo_dbstmt_object_handlers;
02473 
02474        return retval;
02475 }
02476 /* }}} */
02477 
02478 /* {{{ statement iterator */
02479 
02480 struct php_pdo_iterator {
02481        zend_object_iterator iter;
02482        pdo_stmt_t *stmt;
02483        ulong key;
02484        zval *fetch_ahead;
02485 };
02486 
02487 static void pdo_stmt_iter_dtor(zend_object_iterator *iter TSRMLS_DC)
02488 {
02489        struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
02490 
02491        if (--I->stmt->refcount == 0) {
02492               free_statement(I->stmt TSRMLS_CC);
02493        }
02494               
02495        if (I->fetch_ahead) {
02496               zval_ptr_dtor(&I->fetch_ahead);
02497        }
02498 
02499        efree(I);
02500 }
02501 
02502 static int pdo_stmt_iter_valid(zend_object_iterator *iter TSRMLS_DC)
02503 {
02504        struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
02505 
02506        return I->fetch_ahead ? SUCCESS : FAILURE;
02507 }
02508 
02509 static void pdo_stmt_iter_get_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
02510 {
02511        struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
02512 
02513        /* sanity */
02514        if (!I->fetch_ahead) {
02515               *data = NULL;
02516               return;
02517        }
02518 
02519        *data = &I->fetch_ahead;
02520 }
02521 
02522 static int pdo_stmt_iter_get_key(zend_object_iterator *iter, char **str_key, uint *str_key_len,
02523        ulong *int_key TSRMLS_DC)
02524 {
02525        struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
02526 
02527        if (I->key == (ulong)-1) {
02528               return HASH_KEY_NON_EXISTANT;
02529        }
02530        *int_key = I->key;
02531        return HASH_KEY_IS_LONG;
02532 }
02533 
02534 static void pdo_stmt_iter_move_forwards(zend_object_iterator *iter TSRMLS_DC)
02535 {
02536        struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
02537 
02538        if (I->fetch_ahead) {
02539               zval_ptr_dtor(&I->fetch_ahead);
02540               I->fetch_ahead = NULL;
02541        }
02542 
02543        MAKE_STD_ZVAL(I->fetch_ahead);
02544 
02545        if (!do_fetch(I->stmt, TRUE, I->fetch_ahead, PDO_FETCH_USE_DEFAULT,
02546                      PDO_FETCH_ORI_NEXT, 0, 0 TSRMLS_CC)) {
02547               pdo_stmt_t *stmt = I->stmt; /* for PDO_HANDLE_STMT_ERR() */
02548 
02549               PDO_HANDLE_STMT_ERR();
02550               I->key = (ulong)-1;
02551               FREE_ZVAL(I->fetch_ahead);
02552               I->fetch_ahead = NULL;
02553 
02554               return;
02555        }
02556 
02557        I->key++;
02558 }
02559 
02560 static zend_object_iterator_funcs pdo_stmt_iter_funcs = {
02561        pdo_stmt_iter_dtor,
02562        pdo_stmt_iter_valid,
02563        pdo_stmt_iter_get_data,
02564        pdo_stmt_iter_get_key,
02565        pdo_stmt_iter_move_forwards,
02566        NULL
02567 };
02568 
02569 zend_object_iterator *pdo_stmt_iter_get(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
02570 {
02571        pdo_stmt_t *stmt = (pdo_stmt_t*)zend_object_store_get_object(object TSRMLS_CC);
02572        struct php_pdo_iterator *I;
02573 
02574        if (by_ref) {
02575               zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
02576        }
02577 
02578        I = ecalloc(1, sizeof(*I));
02579        I->iter.funcs = &pdo_stmt_iter_funcs;
02580        I->iter.data = I;
02581        I->stmt = stmt;
02582        stmt->refcount++;
02583 
02584        MAKE_STD_ZVAL(I->fetch_ahead);
02585        if (!do_fetch(I->stmt, TRUE, I->fetch_ahead, PDO_FETCH_USE_DEFAULT,
02586                      PDO_FETCH_ORI_NEXT, 0, 0 TSRMLS_CC)) {
02587               PDO_HANDLE_STMT_ERR();
02588               I->key = (ulong)-1;
02589               FREE_ZVAL(I->fetch_ahead);
02590               I->fetch_ahead = NULL;
02591        }
02592 
02593        return &I->iter;
02594 }
02595 
02596 /* }}} */
02597 
02598 /* {{{ overloaded handlers for PDORow class (used by PDO_FETCH_LAZY) */
02599 
02600 const zend_function_entry pdo_row_functions[] = {
02601        {NULL, NULL, NULL}
02602 };
02603 
02604 static zval *row_prop_or_dim_read(zval *object, zval *member, int type TSRMLS_DC)
02605 {
02606        zval *return_value;
02607        pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
02608        int colno = -1;
02609 
02610        MAKE_STD_ZVAL(return_value);
02611        RETVAL_NULL();
02612 
02613        if (stmt) {
02614               if (Z_TYPE_P(member) == IS_LONG) {
02615                      if (Z_LVAL_P(member) >= 0 && Z_LVAL_P(member) < stmt->column_count) {
02616                             fetch_value(stmt, return_value, Z_LVAL_P(member), NULL TSRMLS_CC);
02617                      }
02618               } else {
02619                      convert_to_string(member);
02620                      /* TODO: replace this with a hash of available column names to column
02621                       * numbers */
02622                      for (colno = 0; colno < stmt->column_count; colno++) {
02623                             if (strcmp(stmt->columns[colno].name, Z_STRVAL_P(member)) == 0) {
02624                                    fetch_value(stmt, return_value, colno, NULL TSRMLS_CC);
02625                                    Z_SET_REFCOUNT_P(return_value, 0);
02626                                    Z_UNSET_ISREF_P(return_value);
02627                                    return return_value;
02628                             }
02629                      }
02630                      if (strcmp(Z_STRVAL_P(member), "queryString") == 0) {
02631                             zval_ptr_dtor(&return_value);
02632                             return std_object_handlers.read_property(object, member, type TSRMLS_CC);
02633                      }
02634               }
02635        }
02636 
02637        Z_SET_REFCOUNT_P(return_value, 0);
02638        Z_UNSET_ISREF_P(return_value);
02639        
02640        return return_value;
02641 }
02642 
02643 static void row_prop_or_dim_write(zval *object, zval *member, zval *value TSRMLS_DC)
02644 {
02645        php_error_docref(NULL TSRMLS_CC, E_WARNING, "This PDORow is not from a writable result set");
02646 }
02647 
02648 static int row_prop_or_dim_exists(zval *object, zval *member, int check_empty TSRMLS_DC)
02649 {
02650        pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
02651        int colno = -1;
02652 
02653        if (stmt) {
02654               if (Z_TYPE_P(member) == IS_LONG) {
02655                      return Z_LVAL_P(member) >= 0 && Z_LVAL_P(member) < stmt->column_count;
02656               } else {
02657                      convert_to_string(member);
02658 
02659                      /* TODO: replace this with a hash of available column names to column
02660                       * numbers */
02661                      for (colno = 0; colno < stmt->column_count; colno++) {
02662                             if (strcmp(stmt->columns[colno].name, Z_STRVAL_P(member)) == 0) {
02663                                    return 1;
02664                             }
02665                      }
02666               }
02667        }
02668 
02669        return 0;
02670 }
02671 
02672 static void row_prop_or_dim_delete(zval *object, zval *offset TSRMLS_DC)
02673 {
02674        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a PDORow");
02675 }
02676 
02677 static HashTable *row_get_properties(zval *object TSRMLS_DC)
02678 {
02679        pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
02680        int i;
02681 
02682        if (stmt == NULL) {
02683               return NULL;
02684        }
02685        
02686        for (i = 0; i < stmt->column_count; i++) {
02687               zval *val;
02688               MAKE_STD_ZVAL(val);
02689               fetch_value(stmt, val, i, NULL TSRMLS_CC);
02690 
02691               zend_hash_update(stmt->properties, stmt->columns[i].name, stmt->columns[i].namelen + 1, (void *)&val, sizeof(zval *), NULL);
02692        }
02693 
02694        return stmt->properties;
02695 }
02696 
02697 static union _zend_function *row_method_get(
02698 #if PHP_API_VERSION >= 20041225
02699        zval **object_pp,
02700 #else
02701        zval *object,
02702 #endif
02703        char *method_name, int method_len TSRMLS_DC)
02704 {
02705        zend_function *fbc;
02706        char *lc_method_name;
02707 
02708        lc_method_name = emalloc(method_len + 1);
02709        zend_str_tolower_copy(lc_method_name, method_name, method_len);
02710 
02711        if (zend_hash_find(&pdo_row_ce->function_table, lc_method_name, method_len+1, (void**)&fbc) == FAILURE) {
02712               efree(lc_method_name);
02713               return NULL;
02714        }
02715        
02716        efree(lc_method_name);
02717        return fbc;
02718 }
02719 
02720 static int row_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
02721 {
02722        return FAILURE;
02723 }
02724 
02725 static union _zend_function *row_get_ctor(zval *object TSRMLS_DC)
02726 {
02727        static zend_internal_function ctor = {0};
02728 
02729        ctor.type = ZEND_INTERNAL_FUNCTION;
02730        ctor.function_name = "__construct";
02731        ctor.scope = pdo_row_ce;
02732        ctor.handler = ZEND_FN(dbstmt_constructor);
02733 
02734        return (union _zend_function*)&ctor;
02735 }
02736 
02737 static zend_class_entry *row_get_ce(const zval *object TSRMLS_DC)
02738 {
02739        return pdo_row_ce;
02740 }
02741 
02742 static int row_get_classname(const zval *object, char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC)
02743 {
02744        if (parent) {
02745               return FAILURE;
02746        } else {
02747               *class_name = estrndup("PDORow", sizeof("PDORow")-1);
02748               *class_name_len = sizeof("PDORow")-1;
02749               return SUCCESS;
02750        }
02751 }
02752 
02753 static int row_compare(zval *object1, zval *object2 TSRMLS_DC)
02754 {
02755        return -1;
02756 }
02757 
02758 zend_object_handlers pdo_row_object_handlers = {
02759        ZEND_OBJECTS_STORE_HANDLERS,
02760        row_prop_or_dim_read,
02761        row_prop_or_dim_write,
02762        row_prop_or_dim_read,
02763        row_prop_or_dim_write,
02764        NULL,
02765        NULL,
02766        NULL,
02767        row_prop_or_dim_exists,
02768        row_prop_or_dim_delete,
02769        row_prop_or_dim_exists,
02770        row_prop_or_dim_delete,
02771        row_get_properties,
02772        row_method_get,
02773        row_call_method,
02774        row_get_ctor,
02775        row_get_ce,
02776        row_get_classname,
02777        row_compare,
02778        NULL, /* cast */
02779        NULL
02780 };
02781 
02782 void pdo_row_free_storage(pdo_stmt_t *stmt TSRMLS_DC)
02783 {
02784        if (stmt) {
02785               ZVAL_NULL(&stmt->lazy_object_ref);
02786               
02787               if (--stmt->refcount == 0) {
02788                      free_statement(stmt TSRMLS_CC);
02789               }
02790        }
02791 }
02792 
02793 zend_object_value pdo_row_new(zend_class_entry *ce TSRMLS_DC)
02794 {
02795        zend_object_value retval;
02796 
02797        retval.handle = zend_objects_store_put(NULL, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t)pdo_row_free_storage, NULL TSRMLS_CC);
02798        retval.handlers = &pdo_row_object_handlers;
02799 
02800        return retval;
02801 }
02802 
02803 static int pdo_row_serialize(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC)
02804 {
02805        php_error_docref(NULL TSRMLS_CC, E_WARNING, "PDORow instances may not be serialized");
02806        return FAILURE;
02807 }
02808 /* }}} */
02809 
02810 /*
02811  * Local variables:
02812  * tab-width: 4
02813  * c-basic-offset: 4
02814  * End:
02815  * vim600: noet sw=4 ts=4 fdm=marker
02816  * vim<600: noet sw=4 ts=4
02817  */