Back to index

php5  5.3.10
pdo_dbh.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_dbh.c 321634 2012-01-01 13:15:04Z felipe $ */
00022 
00023 /* The PDO Database 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 "php_pdo.h"
00033 #include "php_pdo_driver.h"
00034 #include "php_pdo_int.h"
00035 #include "zend_exceptions.h"
00036 #include "zend_object_handlers.h"
00037 #include "zend_hash.h"
00038 
00039 static int pdo_dbh_attribute_set(pdo_dbh_t *dbh, long attr, zval *value TSRMLS_DC);
00040 
00041 void pdo_raise_impl_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *sqlstate, const char *supp TSRMLS_DC) /* {{{ */
00042 {
00043        pdo_error_type *pdo_err = &dbh->error_code;
00044        char *message = NULL;
00045        const char *msg;
00046 
00047        if (dbh && dbh->error_mode == PDO_ERRMODE_SILENT) {
00048 #if 0
00049               /* BUG: if user is running in silent mode and hits an error at the driver level
00050                * when they use the PDO methods to call up the error information, they may
00051                * get bogus information */
00052               return;
00053 #endif
00054        }
00055        
00056        if (stmt) {
00057               pdo_err = &stmt->error_code;
00058        }
00059 
00060        strncpy(*pdo_err, sqlstate, 6);
00061 
00062        /* hash sqlstate to error messages */
00063        msg = pdo_sqlstate_state_to_description(*pdo_err);
00064        if (!msg) {
00065               msg = "<<Unknown error>>";
00066        }
00067 
00068        if (supp) {
00069               spprintf(&message, 0, "SQLSTATE[%s]: %s: %s", *pdo_err, msg, supp);
00070        } else {
00071               spprintf(&message, 0, "SQLSTATE[%s]: %s", *pdo_err, msg);
00072        }
00073 
00074        if (dbh && dbh->error_mode != PDO_ERRMODE_EXCEPTION) {
00075               php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", message);
00076        } else {
00077               zval *ex, *info;
00078               zend_class_entry *def_ex = php_pdo_get_exception_base(1 TSRMLS_CC), *pdo_ex = php_pdo_get_exception();
00079 
00080               MAKE_STD_ZVAL(ex);
00081               object_init_ex(ex, pdo_ex);
00082 
00083               zend_update_property_string(def_ex, ex, "message", sizeof("message")-1, message TSRMLS_CC);
00084               zend_update_property_string(def_ex, ex, "code", sizeof("code")-1, *pdo_err TSRMLS_CC);
00085               
00086               MAKE_STD_ZVAL(info);
00087               array_init(info);
00088 
00089               add_next_index_string(info, *pdo_err, 1);
00090               add_next_index_long(info, 0);
00091 
00092               zend_update_property(pdo_ex, ex, "errorInfo", sizeof("errorInfo")-1, info TSRMLS_CC);
00093               zval_ptr_dtor(&info);
00094 
00095               zend_throw_exception_object(ex TSRMLS_CC);
00096        }
00097        
00098        if (message) {
00099               efree(message);
00100        }
00101 }
00102 /* }}} */
00103 
00104 void pdo_handle_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
00105 {
00106        pdo_error_type *pdo_err = &dbh->error_code;
00107        const char *msg = "<<Unknown>>";
00108        char *supp = NULL;
00109        long native_code = 0;
00110        char *message = NULL;
00111        zval *info = NULL;
00112 
00113        if (dbh == NULL || dbh->error_mode == PDO_ERRMODE_SILENT) {
00114               return;
00115        }
00116        
00117        if (stmt) {
00118               pdo_err = &stmt->error_code;
00119        }
00120 
00121        /* hash sqlstate to error messages */
00122        msg = pdo_sqlstate_state_to_description(*pdo_err);
00123        if (!msg) {
00124               msg = "<<Unknown error>>";
00125        }
00126 
00127        if (dbh->methods->fetch_err) {
00128               MAKE_STD_ZVAL(info);
00129               array_init(info);
00130 
00131               add_next_index_string(info, *pdo_err, 1);
00132               
00133               if (dbh->methods->fetch_err(dbh, stmt, info TSRMLS_CC)) {
00134                      zval **item;
00135 
00136                      if (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(info), 1, (void**)&item)) {
00137                             native_code = Z_LVAL_PP(item);
00138                      }
00139                      
00140                      if (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(info), 2, (void**)&item)) {
00141                             supp = estrndup(Z_STRVAL_PP(item), Z_STRLEN_PP(item));
00142                      }
00143               }
00144        }
00145 
00146        if (supp) {
00147               spprintf(&message, 0, "SQLSTATE[%s]: %s: %ld %s", *pdo_err, msg, native_code, supp);
00148        } else {
00149               spprintf(&message, 0, "SQLSTATE[%s]: %s", *pdo_err, msg);
00150        }
00151 
00152        if (dbh->error_mode == PDO_ERRMODE_WARNING) {
00153               php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", message);
00154        } else if (EG(exception) == NULL) {
00155               zval *ex;
00156               zend_class_entry *def_ex = php_pdo_get_exception_base(1 TSRMLS_CC), *pdo_ex = php_pdo_get_exception();
00157 
00158               MAKE_STD_ZVAL(ex);
00159               object_init_ex(ex, pdo_ex);
00160 
00161               zend_update_property_string(def_ex, ex, "message", sizeof("message")-1, message TSRMLS_CC);
00162               zend_update_property_string(def_ex, ex, "code", sizeof("code")-1, *pdo_err TSRMLS_CC);
00163               
00164               if (info) {
00165                      zend_update_property(pdo_ex, ex, "errorInfo", sizeof("errorInfo")-1, info TSRMLS_CC);
00166               }
00167 
00168               zend_throw_exception_object(ex TSRMLS_CC);
00169        }
00170 
00171        if (info) {
00172               zval_ptr_dtor(&info);
00173        }
00174 
00175        if (message) {
00176               efree(message);
00177        }
00178 
00179        if (supp) {
00180               efree(supp);
00181        }
00182 }
00183 /* }}} */
00184 
00185 static char *dsn_from_uri(char *uri, char *buf, size_t buflen TSRMLS_DC) /* {{{ */
00186 {
00187        php_stream *stream;
00188        char *dsn = NULL;
00189 
00190        stream = php_stream_open_wrapper(uri, "rb", ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL);
00191        if (stream) {
00192               dsn = php_stream_get_line(stream, buf, buflen, NULL);
00193               php_stream_close(stream);
00194        }
00195        return dsn;
00196 }
00197 /* }}} */
00198 
00199 /* {{{ proto void PDO::__construct(string dsn, string username, string passwd [, array options])
00200    */
00201 static PHP_METHOD(PDO, dbh_constructor)
00202 {
00203        zval *object = getThis();
00204        pdo_dbh_t *dbh = NULL;
00205        zend_bool is_persistent = FALSE;
00206        char *data_source;
00207        int data_source_len;
00208        char *colon;
00209        char *username=NULL, *password=NULL;
00210        int usernamelen, passwordlen;
00211        pdo_driver_t *driver = NULL;
00212        zval *options = NULL;
00213        char alt_dsn[512];
00214        int call_factory = 1;
00215 
00216        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!s!a!", &data_source, &data_source_len,
00217                             &username, &usernamelen, &password, &passwordlen, &options)) {
00218               ZVAL_NULL(object);
00219               return;
00220        }
00221 
00222        /* parse the data source name */
00223        colon = strchr(data_source, ':');
00224 
00225        if (!colon) {
00226               /* let's see if this string has a matching dsn in the php.ini */
00227               char *ini_dsn = NULL;
00228 
00229               snprintf(alt_dsn, sizeof(alt_dsn), "pdo.dsn.%s", data_source);
00230               if (FAILURE == cfg_get_string(alt_dsn, &ini_dsn)) {
00231                      zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "invalid data source name");
00232                      ZVAL_NULL(object);
00233                      return;
00234               }
00235 
00236               data_source = ini_dsn;
00237               colon = strchr(data_source, ':');
00238               
00239               if (!colon) {
00240                      zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "invalid data source name (via INI: %s)", alt_dsn);
00241                      ZVAL_NULL(object);
00242                      return;
00243               }
00244        }
00245 
00246        if (!strncmp(data_source, "uri:", sizeof("uri:")-1)) {
00247               /* the specified URI holds connection details */
00248               data_source = dsn_from_uri(data_source + sizeof("uri:")-1, alt_dsn, sizeof(alt_dsn) TSRMLS_CC);
00249               if (!data_source) {
00250                      zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "invalid data source URI");
00251                      ZVAL_NULL(object);
00252                      return;
00253               }
00254               colon = strchr(data_source, ':');
00255               if (!colon) {
00256                      zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "invalid data source name (via URI)");
00257                      ZVAL_NULL(object);
00258                      return;
00259               }
00260        }
00261 
00262        driver = pdo_find_driver(data_source, colon - data_source);
00263 
00264        if (!driver) {
00265               /* NB: don't want to include the data_source in the error message as
00266                * it might contain a password */
00267               zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "could not find driver");
00268               ZVAL_NULL(object);
00269               return;
00270        }
00271        
00272        dbh = (pdo_dbh_t *) zend_object_store_get_object(object TSRMLS_CC);
00273 
00274        /* is this supposed to be a persistent connection ? */
00275        if (options) {
00276               zval **v;
00277               int plen = 0;
00278               char *hashkey = NULL;
00279               zend_rsrc_list_entry *le;
00280               pdo_dbh_t *pdbh = NULL;
00281 
00282               if (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(options), PDO_ATTR_PERSISTENT, (void**)&v)) {
00283                      if (Z_TYPE_PP(v) == IS_STRING && !is_numeric_string(Z_STRVAL_PP(v), Z_STRLEN_PP(v), NULL, NULL, 0) && Z_STRLEN_PP(v) > 0) {
00284                             /* user specified key */
00285                             plen = spprintf(&hashkey, 0, "PDO:DBH:DSN=%s:%s:%s:%s", data_source,
00286                                           username ? username : "",
00287                                           password ? password : "",
00288                                           Z_STRVAL_PP(v));
00289                             is_persistent = 1;
00290                      } else {
00291                             convert_to_long_ex(v);
00292                             is_persistent = Z_LVAL_PP(v) ? 1 : 0;
00293                             plen = spprintf(&hashkey, 0, "PDO:DBH:DSN=%s:%s:%s", data_source,
00294                                           username ? username : "",
00295                                           password ? password : "");
00296                      }
00297               }
00298 
00299               if (is_persistent) {
00300                      /* let's see if we have one cached.... */
00301                      if (SUCCESS == zend_hash_find(&EG(persistent_list), hashkey, plen+1, (void*)&le)) {
00302                             if (Z_TYPE_P(le) == php_pdo_list_entry()) {
00303                                    pdbh = (pdo_dbh_t*)le->ptr;
00304 
00305                                    /* is the connection still alive ? */
00306                                    if (pdbh->methods->check_liveness && FAILURE == (pdbh->methods->check_liveness)(pdbh TSRMLS_CC)) {
00307                                           /* nope... need to kill it */
00308                                           pdbh = NULL;
00309                                    }
00310                             }
00311                      }
00312 
00313                      if (pdbh) {
00314                             call_factory = 0;
00315                      } else {
00316                             /* need a brand new pdbh */
00317                             pdbh = pecalloc(1, sizeof(*pdbh), 1);
00318 
00319                             if (!pdbh) {
00320                                    php_error_docref(NULL TSRMLS_CC, E_ERROR, "out of memory while allocating PDO handle");
00321                                    /* NOTREACHED */
00322                             }
00323 
00324                             pdbh->is_persistent = 1;
00325                             if (!(pdbh->persistent_id = pemalloc(plen + 1, 1))) {
00326                                    php_error_docref(NULL TSRMLS_CC, E_ERROR, "out of memory while allocating PDO handle");
00327                             }
00328                             memcpy((char *)pdbh->persistent_id, hashkey, plen+1);
00329                             pdbh->persistent_id_len = plen+1;
00330                             pdbh->refcount = 1;
00331                             pdbh->properties = NULL;
00332                      }
00333               }
00334 
00335               if (pdbh) {
00336                      /* let's copy the emalloc bits over from the other handle */
00337                      if (pdbh->properties) {
00338                             zend_hash_destroy(dbh->properties);       
00339                             efree(dbh->properties);
00340                      } else {
00341                             pdbh->ce = dbh->ce;
00342                             pdbh->def_stmt_ce = dbh->def_stmt_ce;
00343                             pdbh->def_stmt_ctor_args = dbh->def_stmt_ctor_args;
00344                             pdbh->properties = dbh->properties;
00345                      }
00346                      /* kill the non-persistent thingamy */
00347                      efree(dbh);
00348                      /* switch over to the persistent one */
00349                      dbh = pdbh;
00350                      zend_object_store_set_object(object, dbh TSRMLS_CC);
00351                      dbh->refcount++;
00352               }
00353 
00354               if (hashkey) {
00355                      efree(hashkey);
00356               }
00357        }
00358        
00359        if (call_factory) {
00360               dbh->data_source_len = strlen(colon + 1);
00361               dbh->data_source = (const char*)pestrdup(colon + 1, is_persistent);
00362               dbh->username = username ? pestrdup(username, is_persistent) : NULL;
00363               dbh->password = password ? pestrdup(password, is_persistent) : NULL;
00364               dbh->default_fetch_type = PDO_FETCH_BOTH;
00365        }      
00366 
00367        dbh->auto_commit = pdo_attr_lval(options, PDO_ATTR_AUTOCOMMIT, 1 TSRMLS_CC);
00368 
00369        if (!dbh->data_source || (username && !dbh->username) || (password && !dbh->password)) {
00370               php_error_docref(NULL TSRMLS_CC, E_ERROR, "out of memory");
00371        }
00372 
00373        if (!call_factory) {
00374               /* we got a persistent guy from our cache */
00375               goto options;
00376        }
00377 
00378        if (driver->db_handle_factory(dbh, options TSRMLS_CC)) {
00379               /* all set */
00380 
00381               if (is_persistent) {
00382                      zend_rsrc_list_entry le;
00383 
00384                      /* register in the persistent list etc. */
00385                      /* we should also need to replace the object store entry,
00386                         since it was created with emalloc */
00387 
00388                      le.type = php_pdo_list_entry();
00389                      le.ptr = dbh;
00390 
00391                      if (FAILURE == zend_hash_update(&EG(persistent_list),
00392                                    (char*)dbh->persistent_id, dbh->persistent_id_len, (void*)&le,
00393                                    sizeof(le), NULL)) {
00394                             php_error_docref(NULL TSRMLS_CC, E_ERROR, "Failed to register persistent entry");
00395                      }
00396               }
00397 
00398               dbh->driver = driver;
00399 options:
00400               if (options) {
00401                      zval **attr_value;
00402                      char *str_key;
00403                      long long_key;
00404                      
00405                      zend_hash_internal_pointer_reset(Z_ARRVAL_P(options));
00406                      while (SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(options), (void**)&attr_value) 
00407                             && HASH_KEY_IS_LONG == zend_hash_get_current_key(Z_ARRVAL_P(options), &str_key, &long_key, 0)) {
00408                             
00409                             pdo_dbh_attribute_set(dbh, long_key, *attr_value TSRMLS_CC);
00410                             zend_hash_move_forward(Z_ARRVAL_P(options));
00411                      }
00412               }
00413 
00414               return;
00415        }
00416 
00417        /* the connection failed; things will tidy up in free_storage */
00418        /* XXX raise exception */
00419        ZVAL_NULL(object);
00420 }
00421 /* }}} */
00422 
00423 static zval *pdo_stmt_instantiate(pdo_dbh_t *dbh, zval *object, zend_class_entry *dbstmt_ce, zval *ctor_args TSRMLS_DC) /* {{{ */
00424 {
00425        if (ctor_args) {
00426               if (Z_TYPE_P(ctor_args) != IS_ARRAY) {
00427                      pdo_raise_impl_error(dbh, NULL, "HY000", "constructor arguments must be passed as an array" TSRMLS_CC);
00428                      return NULL;
00429               }
00430               if (!dbstmt_ce->constructor) {
00431                      pdo_raise_impl_error(dbh, NULL, "HY000", "user-supplied statement does not accept constructor arguments" TSRMLS_CC);
00432                      return NULL;
00433               }
00434        }
00435 
00436        Z_TYPE_P(object) = IS_OBJECT;
00437        object_init_ex(object, dbstmt_ce);
00438        Z_SET_REFCOUNT_P(object, 1);
00439        Z_SET_ISREF_P(object);
00440        
00441        return object;
00442 } /* }}} */
00443 
00444 static void pdo_stmt_construct(pdo_stmt_t *stmt, zval *object, zend_class_entry *dbstmt_ce, zval *ctor_args TSRMLS_DC) /* {{{ */
00445 {      
00446        zval *query_string;
00447        zval z_key;
00448 
00449        MAKE_STD_ZVAL(query_string);
00450        ZVAL_STRINGL(query_string, stmt->query_string, stmt->query_stringlen, 1);
00451        ZVAL_STRINGL(&z_key, "queryString", sizeof("queryString")-1, 0);
00452        std_object_handlers.write_property(object, &z_key, query_string TSRMLS_CC);
00453        zval_ptr_dtor(&query_string);
00454 
00455        if (dbstmt_ce->constructor) {
00456               zend_fcall_info fci;
00457               zend_fcall_info_cache fcc;
00458               zval *retval;
00459 
00460               fci.size = sizeof(zend_fcall_info);
00461               fci.function_table = &dbstmt_ce->function_table;
00462               fci.function_name = NULL;
00463               fci.object_ptr = object;
00464               fci.symbol_table = NULL;
00465               fci.retval_ptr_ptr = &retval;
00466               if (ctor_args) {
00467                      HashTable *ht = Z_ARRVAL_P(ctor_args);
00468                      Bucket *p;
00469 
00470                      fci.param_count = 0;
00471                      fci.params = safe_emalloc(sizeof(zval*), ht->nNumOfElements, 0);
00472                      p = ht->pListHead;
00473                      while (p != NULL) {
00474                             fci.params[fci.param_count++] = (zval**)p->pData;
00475                             p = p->pListNext;
00476                      }
00477               } else {
00478                      fci.param_count = 0;
00479                      fci.params = NULL;
00480               }
00481               fci.no_separation = 1;
00482 
00483               fcc.initialized = 1;
00484               fcc.function_handler = dbstmt_ce->constructor;
00485               fcc.calling_scope = EG(scope);
00486               fcc.called_scope = Z_OBJCE_P(object);
00487               fcc.object_ptr = object;
00488 
00489               if (zend_call_function(&fci, &fcc TSRMLS_CC) == FAILURE) {
00490                      zval_dtor(object);
00491                      ZVAL_NULL(object);
00492                      object = NULL; /* marks failure */
00493               } else {
00494                      zval_ptr_dtor(&retval);
00495               }
00496                      
00497               if (fci.params) {
00498                      efree(fci.params);
00499               }
00500        }
00501 }
00502 /* }}} */
00503 
00504 /* {{{ proto object PDO::prepare(string statment [, array options])
00505    Prepares a statement for execution and returns a statement object */
00506 static PHP_METHOD(PDO, prepare)
00507 {
00508        pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
00509        pdo_stmt_t *stmt;
00510        char *statement;
00511        int statement_len;
00512        zval *options = NULL, **opt, **item, *ctor_args;
00513        zend_class_entry *dbstmt_ce, **pce;
00514 
00515        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a", &statement,
00516                      &statement_len, &options)) {
00517               RETURN_FALSE;
00518        }
00519        
00520        PDO_DBH_CLEAR_ERR();
00521        PDO_CONSTRUCT_CHECK;
00522 
00523        if (ZEND_NUM_ARGS() > 1 && SUCCESS == zend_hash_index_find(Z_ARRVAL_P(options), PDO_ATTR_STATEMENT_CLASS, (void**)&opt)) {
00524               if (Z_TYPE_PP(opt) != IS_ARRAY || zend_hash_index_find(Z_ARRVAL_PP(opt), 0, (void**)&item) == FAILURE
00525                      || Z_TYPE_PP(item) != IS_STRING
00526                      || zend_lookup_class(Z_STRVAL_PP(item), Z_STRLEN_PP(item), &pce TSRMLS_CC) == FAILURE
00527               ) {
00528                      pdo_raise_impl_error(dbh, NULL, "HY000", 
00529                             "PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); "
00530                             "the classname must be a string specifying an existing class"
00531                             TSRMLS_CC);
00532                      PDO_HANDLE_DBH_ERR();
00533                      RETURN_FALSE;
00534               }
00535               dbstmt_ce = *pce;
00536               if (!instanceof_function(dbstmt_ce, pdo_dbstmt_ce TSRMLS_CC)) {
00537                      pdo_raise_impl_error(dbh, NULL, "HY000", 
00538                             "user-supplied statement class must be derived from PDOStatement" TSRMLS_CC);
00539                      PDO_HANDLE_DBH_ERR();
00540                      RETURN_FALSE;
00541               }
00542               if (dbstmt_ce->constructor && !(dbstmt_ce->constructor->common.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED))) {
00543                      pdo_raise_impl_error(dbh, NULL, "HY000", 
00544                             "user-supplied statement class cannot have a public constructor" TSRMLS_CC);
00545                      PDO_HANDLE_DBH_ERR();
00546                      RETURN_FALSE;
00547               }
00548               if (zend_hash_index_find(Z_ARRVAL_PP(opt), 1, (void**)&item) == SUCCESS) {
00549                      if (Z_TYPE_PP(item) != IS_ARRAY) {
00550                             pdo_raise_impl_error(dbh, NULL, "HY000", 
00551                                    "PDO::ATTR_STATEMENT_CLASS requires format array(classname, ctor_args); "
00552                                    "ctor_args must be an array"
00553                             TSRMLS_CC);
00554                             PDO_HANDLE_DBH_ERR();
00555                             RETURN_FALSE;
00556                      }
00557                      ctor_args = *item;
00558               } else {
00559                      ctor_args = NULL;
00560               }
00561        } else {
00562               dbstmt_ce = dbh->def_stmt_ce;
00563               ctor_args = dbh->def_stmt_ctor_args;
00564        }
00565 
00566        if (!pdo_stmt_instantiate(dbh, return_value, dbstmt_ce, ctor_args TSRMLS_CC)) {
00567               pdo_raise_impl_error(dbh, NULL, "HY000", 
00568                      "failed to instantiate user-supplied statement class"
00569                      TSRMLS_CC);
00570               PDO_HANDLE_DBH_ERR();
00571               RETURN_FALSE;
00572        }
00573        stmt = (pdo_stmt_t*)zend_object_store_get_object(return_value TSRMLS_CC);
00574        
00575        /* unconditionally keep this for later reference */
00576        stmt->query_string = estrndup(statement, statement_len);
00577        stmt->query_stringlen = statement_len;
00578        stmt->default_fetch_type = dbh->default_fetch_type;
00579        stmt->dbh = dbh;
00580        /* give it a reference to me */
00581        zend_objects_store_add_ref(getThis() TSRMLS_CC);
00582        php_pdo_dbh_addref(dbh TSRMLS_CC);
00583        stmt->database_object_handle = *getThis();
00584        /* we haven't created a lazy object yet */
00585        ZVAL_NULL(&stmt->lazy_object_ref);
00586 
00587        if (dbh->methods->preparer(dbh, statement, statement_len, stmt, options TSRMLS_CC)) {
00588               pdo_stmt_construct(stmt, return_value, dbstmt_ce, ctor_args TSRMLS_CC);
00589               return;
00590        }
00591 
00592        PDO_HANDLE_DBH_ERR();
00593 
00594        /* kill the object handle for the stmt here */
00595        zval_dtor(return_value);
00596 
00597        RETURN_FALSE;
00598 }
00599 /* }}} */
00600 
00601 /* {{{ proto bool PDO::beginTransaction()
00602    Initiates a transaction */
00603 static PHP_METHOD(PDO, beginTransaction)
00604 {
00605        pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
00606 
00607        if (zend_parse_parameters_none() == FAILURE) {
00608               return;
00609        }
00610        PDO_CONSTRUCT_CHECK;
00611 
00612        if (dbh->in_txn) {
00613               zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "There is already an active transaction");
00614               RETURN_FALSE;
00615        }
00616        
00617        if (!dbh->methods->begin) {
00618               /* TODO: this should be an exception; see the auto-commit mode
00619                * comments below */
00620               zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "This driver doesn't support transactions");
00621               RETURN_FALSE;
00622        }
00623 
00624        if (dbh->methods->begin(dbh TSRMLS_CC)) {
00625               dbh->in_txn = 1;
00626               RETURN_TRUE;
00627        }
00628 
00629        PDO_HANDLE_DBH_ERR();
00630        RETURN_FALSE;
00631 }
00632 /* }}} */
00633 
00634 /* {{{ proto bool PDO::commit()
00635    Commit a transaction */
00636 static PHP_METHOD(PDO, commit)
00637 {
00638        pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
00639 
00640        if (zend_parse_parameters_none() == FAILURE) {
00641               return;
00642        }
00643        PDO_CONSTRUCT_CHECK;
00644 
00645        if (!dbh->in_txn) {
00646               zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "There is no active transaction");
00647               RETURN_FALSE;
00648        }
00649 
00650        if (dbh->methods->commit(dbh TSRMLS_CC)) {
00651               dbh->in_txn = 0;
00652               RETURN_TRUE;
00653        }
00654        
00655        PDO_HANDLE_DBH_ERR();
00656        RETURN_FALSE;
00657 }
00658 /* }}} */
00659 
00660 /* {{{ proto bool PDO::rollBack()
00661    roll back a transaction */
00662 static PHP_METHOD(PDO, rollBack)
00663 {
00664        pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
00665 
00666        if (zend_parse_parameters_none() == FAILURE) {
00667               return;
00668        }
00669        PDO_CONSTRUCT_CHECK;
00670 
00671        if (!dbh->in_txn) {
00672               zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "There is no active transaction");
00673               RETURN_FALSE;
00674        }
00675 
00676        if (dbh->methods->rollback(dbh TSRMLS_CC)) {
00677               dbh->in_txn = 0;
00678               RETURN_TRUE;
00679        }
00680               
00681        PDO_HANDLE_DBH_ERR();
00682        RETURN_FALSE;
00683 }
00684 /* }}} */
00685 
00686 /* {{{ proto bool PDO::inTransaction()
00687    determine if inside a transaction */
00688 static PHP_METHOD(PDO, inTransaction)
00689 {
00690        pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
00691 
00692        if (zend_parse_parameters_none() == FAILURE) {
00693               return;
00694        }
00695        PDO_CONSTRUCT_CHECK;
00696 
00697        RETURN_LONG(dbh->in_txn);
00698 }
00699 /* }}} */
00700 
00701 static int pdo_dbh_attribute_set(pdo_dbh_t *dbh, long attr, zval *value TSRMLS_DC) /* {{{ */
00702 {
00703 
00704 #define PDO_LONG_PARAM_CHECK \
00705        if (Z_TYPE_P(value) != IS_LONG && Z_TYPE_P(value) != IS_STRING && Z_TYPE_P(value) != IS_BOOL) { \
00706               pdo_raise_impl_error(dbh, NULL, "HY000", "attribute value must be an integer" TSRMLS_CC); \
00707               PDO_HANDLE_DBH_ERR(); \
00708               return FAILURE; \
00709        } \
00710 
00711        switch (attr) {
00712               case PDO_ATTR_ERRMODE:
00713                      PDO_LONG_PARAM_CHECK;
00714                      convert_to_long(value);
00715                      switch (Z_LVAL_P(value)) {
00716                             case PDO_ERRMODE_SILENT:
00717                             case PDO_ERRMODE_WARNING:
00718                             case PDO_ERRMODE_EXCEPTION:
00719                                    dbh->error_mode = Z_LVAL_P(value);
00720                                    return SUCCESS;
00721                             default:
00722                                    pdo_raise_impl_error(dbh, NULL, "HY000", "invalid error mode" TSRMLS_CC);
00723                                    PDO_HANDLE_DBH_ERR();
00724                                    return FAILURE;
00725                      }
00726                      return FAILURE;
00727 
00728               case PDO_ATTR_CASE:
00729                      PDO_LONG_PARAM_CHECK;
00730                      convert_to_long(value);
00731                      switch (Z_LVAL_P(value)) {
00732                             case PDO_CASE_NATURAL:
00733                             case PDO_CASE_UPPER:
00734                             case PDO_CASE_LOWER:
00735                                    dbh->desired_case = Z_LVAL_P(value);
00736                                    return SUCCESS;
00737                             default:
00738                                    pdo_raise_impl_error(dbh, NULL, "HY000", "invalid case folding mode" TSRMLS_CC);
00739                                    PDO_HANDLE_DBH_ERR();
00740                                    return FAILURE;
00741                      }
00742                      return FAILURE;
00743 
00744               case PDO_ATTR_ORACLE_NULLS:
00745                      PDO_LONG_PARAM_CHECK;
00746                      convert_to_long(value);
00747                      dbh->oracle_nulls = Z_LVAL_P(value);
00748                      return SUCCESS;
00749 
00750               case PDO_ATTR_DEFAULT_FETCH_MODE:
00751                      if (Z_TYPE_P(value) == IS_ARRAY) {
00752                             zval **tmp;
00753                             if (zend_hash_index_find(Z_ARRVAL_P(value), 0, (void**)&tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_LONG) {
00754                                    if (Z_LVAL_PP(tmp) == PDO_FETCH_INTO || Z_LVAL_PP(tmp) == PDO_FETCH_CLASS) {
00755                                           pdo_raise_impl_error(dbh, NULL, "HY000", "FETCH_INTO and FETCH_CLASS are not yet supported as default fetch modes" TSRMLS_CC);
00756                                           return FAILURE;
00757                                    }
00758                             }
00759                      } else {
00760                             PDO_LONG_PARAM_CHECK;
00761                      }
00762                      convert_to_long(value);
00763                      if (Z_LVAL_P(value) == PDO_FETCH_USE_DEFAULT) {
00764                             pdo_raise_impl_error(dbh, NULL, "HY000", "invalid fetch mode type" TSRMLS_CC);
00765                             return FAILURE;
00766                      }
00767                      dbh->default_fetch_type = Z_LVAL_P(value);
00768                      return SUCCESS;
00769 
00770               case PDO_ATTR_STRINGIFY_FETCHES:
00771                      PDO_LONG_PARAM_CHECK;
00772                      convert_to_long(value);
00773                      dbh->stringify = Z_LVAL_P(value) ? 1 : 0;
00774                      return SUCCESS;
00775                      
00776               case PDO_ATTR_STATEMENT_CLASS: {
00777                      /* array(string classname, array(mixed ctor_args)) */
00778                      zend_class_entry **pce;
00779                      zval **item;
00780 
00781                      if (dbh->is_persistent) {
00782                             pdo_raise_impl_error(dbh, NULL, "HY000", 
00783                                    "PDO::ATTR_STATEMENT_CLASS cannot be used with persistent PDO instances"
00784                                    TSRMLS_CC);
00785                             PDO_HANDLE_DBH_ERR();
00786                             return FAILURE;
00787                      }
00788                      if (Z_TYPE_P(value) != IS_ARRAY
00789                             || zend_hash_index_find(Z_ARRVAL_P(value), 0, (void**)&item) == FAILURE
00790                             || Z_TYPE_PP(item) != IS_STRING
00791                             || zend_lookup_class(Z_STRVAL_PP(item), Z_STRLEN_PP(item), &pce TSRMLS_CC) == FAILURE
00792                      ) {
00793                             pdo_raise_impl_error(dbh, NULL, "HY000", 
00794                                    "PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); "
00795                                    "the classname must be a string specifying an existing class"
00796                                    TSRMLS_CC);
00797                             PDO_HANDLE_DBH_ERR();
00798                             return FAILURE;
00799                      }
00800                      if (!instanceof_function(*pce, pdo_dbstmt_ce TSRMLS_CC)) {
00801                             pdo_raise_impl_error(dbh, NULL, "HY000", 
00802                                    "user-supplied statement class must be derived from PDOStatement" TSRMLS_CC);
00803                             PDO_HANDLE_DBH_ERR();
00804                             return FAILURE;
00805                      }
00806                      if ((*pce)->constructor && !((*pce)->constructor->common.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED))) {
00807                             pdo_raise_impl_error(dbh, NULL, "HY000", 
00808                                    "user-supplied statement class cannot have a public constructor" TSRMLS_CC);
00809                             PDO_HANDLE_DBH_ERR();
00810                             return FAILURE;
00811                      }
00812                      dbh->def_stmt_ce = *pce;
00813                      if (dbh->def_stmt_ctor_args) {
00814                             zval_ptr_dtor(&dbh->def_stmt_ctor_args);
00815                             dbh->def_stmt_ctor_args = NULL;
00816                      }
00817                      if (zend_hash_index_find(Z_ARRVAL_P(value), 1, (void**)&item) == SUCCESS) {
00818                             if (Z_TYPE_PP(item) != IS_ARRAY) {
00819                                    pdo_raise_impl_error(dbh, NULL, "HY000", 
00820                                           "PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); "
00821                                           "ctor_args must be an array"
00822                                    TSRMLS_CC);
00823                                    PDO_HANDLE_DBH_ERR();
00824                                    return FAILURE;
00825                             }
00826                             Z_ADDREF_PP(item);
00827                             dbh->def_stmt_ctor_args = *item;
00828                      }
00829                      return SUCCESS;
00830               }
00831                      
00832               default:
00833                      ;
00834        }
00835 
00836        if (!dbh->methods->set_attribute) {
00837               goto fail;
00838        }
00839 
00840        PDO_DBH_CLEAR_ERR();
00841        if (dbh->methods->set_attribute(dbh, attr, value TSRMLS_CC)) {
00842               return SUCCESS;
00843        }
00844 
00845 fail:
00846        if (attr == PDO_ATTR_AUTOCOMMIT) {
00847               zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "The auto-commit mode cannot be changed for this driver");
00848        } else if (!dbh->methods->set_attribute) {
00849               pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support setting attributes" TSRMLS_CC);
00850        } else {
00851               PDO_HANDLE_DBH_ERR();
00852        }
00853        return FAILURE;
00854 }
00855 /* }}} */
00856  
00857 /* {{{ proto bool PDO::setAttribute(long attribute, mixed value)
00858    Set an attribute */
00859 static PHP_METHOD(PDO, setAttribute)
00860 {
00861        pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
00862        long attr;
00863        zval *value;
00864 
00865        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz", &attr, &value)) {
00866               RETURN_FALSE;
00867        }
00868 
00869        PDO_DBH_CLEAR_ERR();
00870        PDO_CONSTRUCT_CHECK;
00871 
00872        if (pdo_dbh_attribute_set(dbh, attr, value TSRMLS_CC) != FAILURE) {
00873               RETURN_TRUE;
00874        }
00875        RETURN_FALSE;
00876 }
00877 /* }}} */
00878 
00879 /* {{{ proto mixed PDO::getAttribute(long attribute)
00880    Get an attribute */
00881 static PHP_METHOD(PDO, getAttribute)
00882 {
00883        pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
00884        long attr;
00885 
00886        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &attr)) {
00887               RETURN_FALSE;
00888        }
00889 
00890        PDO_DBH_CLEAR_ERR();
00891        PDO_CONSTRUCT_CHECK;
00892 
00893        /* handle generic PDO-level atributes */
00894        switch (attr) {
00895               case PDO_ATTR_PERSISTENT:
00896                      RETURN_BOOL(dbh->is_persistent);
00897                      
00898               case PDO_ATTR_CASE:
00899                      RETURN_LONG(dbh->desired_case);
00900 
00901               case PDO_ATTR_ORACLE_NULLS:
00902                      RETURN_LONG(dbh->oracle_nulls);
00903 
00904               case PDO_ATTR_ERRMODE:
00905                      RETURN_LONG(dbh->error_mode);
00906 
00907               case PDO_ATTR_DRIVER_NAME:
00908                      RETURN_STRINGL((char*)dbh->driver->driver_name, dbh->driver->driver_name_len, 1);
00909 
00910               case PDO_ATTR_STATEMENT_CLASS:
00911                      array_init(return_value);
00912                      add_next_index_string(return_value, dbh->def_stmt_ce->name, 1);
00913                      if (dbh->def_stmt_ctor_args) {
00914                             Z_ADDREF_P(dbh->def_stmt_ctor_args);
00915                             add_next_index_zval(return_value, dbh->def_stmt_ctor_args);
00916                      }
00917                      return;
00918               case PDO_ATTR_DEFAULT_FETCH_MODE:
00919                      RETURN_LONG(dbh->default_fetch_type);
00920 
00921        }
00922        
00923        if (!dbh->methods->get_attribute) {
00924               pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support getting attributes" TSRMLS_CC);
00925               RETURN_FALSE;
00926        }
00927 
00928        switch (dbh->methods->get_attribute(dbh, attr, return_value TSRMLS_CC)) {
00929               case -1:
00930                      PDO_HANDLE_DBH_ERR();
00931                      RETURN_FALSE;
00932 
00933               case 0:
00934                      pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support that attribute" TSRMLS_CC);
00935                      RETURN_FALSE;
00936 
00937               default:
00938                      return;
00939        }
00940 }
00941 /* }}} */
00942 
00943 /* {{{ proto long PDO::exec(string query)
00944    Execute a query that does not return a row set, returning the number of affected rows */
00945 static PHP_METHOD(PDO, exec)
00946 {
00947        pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
00948        char *statement;
00949        int statement_len;
00950        long ret;
00951 
00952        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &statement, &statement_len)) {
00953               RETURN_FALSE;
00954        }
00955 
00956        if (!statement_len) {
00957               pdo_raise_impl_error(dbh, NULL, "HY000",  "trying to execute an empty query" TSRMLS_CC);
00958               RETURN_FALSE;
00959        }
00960        PDO_DBH_CLEAR_ERR();
00961        PDO_CONSTRUCT_CHECK;
00962        ret = dbh->methods->doer(dbh, statement, statement_len TSRMLS_CC);
00963        if(ret == -1) {
00964               PDO_HANDLE_DBH_ERR();
00965               RETURN_FALSE;
00966        } else {
00967               RETURN_LONG(ret);
00968        }
00969 }
00970 /* }}} */
00971 
00972 
00973 /* {{{ proto string PDO::lastInsertId([string seqname])
00974    Returns the id of the last row that we affected on this connection.  Some databases require a sequence or table name to be passed in.  Not always meaningful. */
00975 static PHP_METHOD(PDO, lastInsertId)
00976 {
00977        pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
00978        char *name = NULL;
00979        int namelen;
00980 
00981        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &name, &namelen)) {
00982               RETURN_FALSE;
00983        }
00984 
00985        PDO_DBH_CLEAR_ERR();
00986        PDO_CONSTRUCT_CHECK;
00987        if (!dbh->methods->last_id) {
00988               pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support lastInsertId()" TSRMLS_CC);
00989               RETURN_FALSE;
00990        } else {
00991               Z_STRVAL_P(return_value) = dbh->methods->last_id(dbh, name, &Z_STRLEN_P(return_value) TSRMLS_CC);
00992               if (!Z_STRVAL_P(return_value)) {
00993                      PDO_HANDLE_DBH_ERR();
00994                      RETURN_FALSE;
00995               } else {
00996                      Z_TYPE_P(return_value) = IS_STRING;
00997               }
00998        }
00999 }
01000 /* }}} */
01001 
01002 /* {{{ proto string PDO::errorCode()
01003    Fetch the error code associated with the last operation on the database handle */
01004 static PHP_METHOD(PDO, errorCode)
01005 {
01006        pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
01007 
01008        if (zend_parse_parameters_none() == FAILURE) {
01009               return;
01010        }
01011        PDO_CONSTRUCT_CHECK;
01012 
01013        if (dbh->query_stmt) {
01014               RETURN_STRING(dbh->query_stmt->error_code, 1);
01015        }
01016        
01017        if (dbh->error_code[0] == '\0') {
01018               RETURN_NULL();
01019        }
01020 
01025        RETURN_STRING(dbh->error_code, 1);
01026 }
01027 /* }}} */
01028 
01029 /* {{{ proto int PDO::errorInfo()
01030    Fetch extended error information associated with the last operation on the database handle */
01031 static PHP_METHOD(PDO, errorInfo)
01032 {
01033        int error_count;
01034        int error_count_diff         = 0;
01035        int error_expected_count = 3;
01036 
01037        pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
01038 
01039        if (zend_parse_parameters_none() == FAILURE) {
01040               return;
01041        }
01042 
01043        PDO_CONSTRUCT_CHECK;
01044 
01045        array_init(return_value);
01046 
01047        if (dbh->query_stmt) {
01048               add_next_index_string(return_value, dbh->query_stmt->error_code, 1);
01049        } else {
01050               add_next_index_string(return_value, dbh->error_code, 1);
01051        }
01052 
01053        if (dbh->methods->fetch_err) {
01054               dbh->methods->fetch_err(dbh, dbh->query_stmt, return_value TSRMLS_CC);
01055        }
01056        
01062        error_count = zend_hash_num_elements(Z_ARRVAL_P(return_value));
01063 
01064        if (error_expected_count > error_count) {
01065               int current_index;
01066 
01067               error_count_diff = error_expected_count - error_count;
01068               for (current_index = 0; current_index < error_count_diff; current_index++) {
01069                      add_next_index_null(return_value);
01070               }
01071        }
01072 }
01073 /* }}} */
01074 
01075 /* {{{ proto object PDO::query(string sql [, PDOStatement::setFetchMode() args])
01076    Prepare and execute $sql; returns the statement object for iteration */
01077 static PHP_METHOD(PDO, query)
01078 {
01079        pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
01080        pdo_stmt_t *stmt;
01081        char *statement;
01082        int statement_len;
01083 
01084        /* Return a meaningful error when no parameters were passed */
01085        if (!ZEND_NUM_ARGS()) {
01086               zend_parse_parameters(0 TSRMLS_CC, "z|z", NULL, NULL);
01087               RETURN_FALSE;
01088        }
01089        
01090        if (FAILURE == zend_parse_parameters(1 TSRMLS_CC, "s", &statement,
01091                      &statement_len)) {
01092               RETURN_FALSE;
01093        }
01094        
01095        PDO_DBH_CLEAR_ERR();
01096        PDO_CONSTRUCT_CHECK;
01097 
01098        if (!pdo_stmt_instantiate(dbh, return_value, dbh->def_stmt_ce, dbh->def_stmt_ctor_args TSRMLS_CC)) {
01099               pdo_raise_impl_error(dbh, NULL, "HY000", "failed to instantiate user supplied statement class" TSRMLS_CC);
01100               return;
01101        }
01102        stmt = (pdo_stmt_t*)zend_object_store_get_object(return_value TSRMLS_CC);
01103        
01104        /* unconditionally keep this for later reference */
01105        stmt->query_string = estrndup(statement, statement_len);
01106        stmt->query_stringlen = statement_len;
01107 
01108        stmt->default_fetch_type = dbh->default_fetch_type;
01109        stmt->active_query_string = stmt->query_string;
01110        stmt->active_query_stringlen = statement_len;
01111        stmt->dbh = dbh;
01112        /* give it a reference to me */
01113        zend_objects_store_add_ref(getThis() TSRMLS_CC);
01114        php_pdo_dbh_addref(dbh TSRMLS_CC);
01115        stmt->database_object_handle = *getThis();
01116        /* we haven't created a lazy object yet */
01117        ZVAL_NULL(&stmt->lazy_object_ref);
01118 
01119        if (dbh->methods->preparer(dbh, statement, statement_len, stmt, NULL TSRMLS_CC)) {
01120               PDO_STMT_CLEAR_ERR();
01121               if (ZEND_NUM_ARGS() == 1 || SUCCESS == pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, 1)) {
01122 
01123                      /* now execute the statement */
01124                      PDO_STMT_CLEAR_ERR();
01125                      if (stmt->methods->executer(stmt TSRMLS_CC)) {
01126                             int ret = 1;
01127                             if (!stmt->executed) {
01128                                    if (stmt->dbh->alloc_own_columns) {
01129                                           ret = pdo_stmt_describe_columns(stmt TSRMLS_CC);
01130                                    }
01131                                    stmt->executed = 1;
01132                             }
01133                             if (ret) {
01134                                    pdo_stmt_construct(stmt, return_value, dbh->def_stmt_ce, dbh->def_stmt_ctor_args TSRMLS_CC);
01135                                    return;
01136                             }
01137                      }
01138               }
01139               /* something broke */
01140               dbh->query_stmt = stmt;
01141               dbh->query_stmt_zval = *return_value;
01142               PDO_HANDLE_STMT_ERR();
01143        } else {
01144               PDO_HANDLE_DBH_ERR();
01145               zval_dtor(return_value);
01146        }
01147 
01148        RETURN_FALSE;
01149 }
01150 /* }}} */
01151 
01152 /* {{{ proto string PDO::quote(string string [, int paramtype])
01153    quotes string for use in a query.  The optional paramtype acts as a hint for drivers that have alternate quoting styles.  The default value is PDO_PARAM_STR */
01154 static PHP_METHOD(PDO, quote)
01155 {
01156        pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
01157        char *str;
01158        int str_len;
01159        long paramtype = PDO_PARAM_STR;
01160        char *qstr;
01161        int qlen;
01162 
01163        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &str, &str_len, &paramtype)) {
01164               RETURN_FALSE;
01165        }
01166        
01167        PDO_DBH_CLEAR_ERR();
01168        PDO_CONSTRUCT_CHECK;
01169        if (!dbh->methods->quoter) {
01170               pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support quoting" TSRMLS_CC);
01171               RETURN_FALSE;
01172        }
01173 
01174        if (dbh->methods->quoter(dbh, str, str_len, &qstr, &qlen, paramtype TSRMLS_CC)) {
01175               RETURN_STRINGL(qstr, qlen, 0);
01176        }
01177        PDO_HANDLE_DBH_ERR();
01178        RETURN_FALSE;
01179 }
01180 /* }}} */
01181 
01182 /* {{{ proto int PDO::__wakeup()
01183    Prevents use of a PDO instance that has been unserialized */
01184 static PHP_METHOD(PDO, __wakeup)
01185 {
01186        zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "You cannot serialize or unserialize PDO instances");
01187 }
01188 /* }}} */
01189 
01190 /* {{{ proto int PDO::__sleep()
01191    Prevents serialization of a PDO instance */
01192 static PHP_METHOD(PDO, __sleep)
01193 {
01194        zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "You cannot serialize or unserialize PDO instances");
01195 }
01196 /* }}} */
01197 
01198 /* {{{ proto array PDO::getAvailableDrivers()
01199    Return array of available PDO drivers */
01200 static PHP_METHOD(PDO, getAvailableDrivers)
01201 {
01202        HashPosition pos;
01203        pdo_driver_t **pdriver;
01204 
01205        if (zend_parse_parameters_none() == FAILURE) {
01206               return;
01207        }
01208        
01209        array_init(return_value);
01210 
01211        zend_hash_internal_pointer_reset_ex(&pdo_driver_hash, &pos);
01212        while (SUCCESS == zend_hash_get_current_data_ex(&pdo_driver_hash, (void**)&pdriver, &pos)) {
01213               add_next_index_stringl(return_value, (char*)(*pdriver)->driver_name, (*pdriver)->driver_name_len, 1);
01214               zend_hash_move_forward_ex(&pdo_driver_hash, &pos);
01215        }
01216 }
01217 /* }}} */
01218 
01219 /* {{{ arginfo */
01220 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdo___construct, 0, 0, 3)
01221        ZEND_ARG_INFO(0, dsn)
01222        ZEND_ARG_INFO(0, username)
01223        ZEND_ARG_INFO(0, passwd)
01224        ZEND_ARG_INFO(0, options) /* array */
01225 ZEND_END_ARG_INFO()
01226 
01227 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdo_prepare, 0, 0, 1)
01228        ZEND_ARG_INFO(0, statment)
01229        ZEND_ARG_INFO(0, options) /* array */
01230 ZEND_END_ARG_INFO()
01231 
01232 ZEND_BEGIN_ARG_INFO(arginfo_pdo_setattribute, 0)
01233        ZEND_ARG_INFO(0, attribute)
01234        ZEND_ARG_INFO(0, value)
01235 ZEND_END_ARG_INFO()
01236 
01237 ZEND_BEGIN_ARG_INFO(arginfo_pdo_getattribute, 0)
01238        ZEND_ARG_INFO(0, attribute)
01239 ZEND_END_ARG_INFO()
01240 
01241 ZEND_BEGIN_ARG_INFO(arginfo_pdo_exec, 0)
01242        ZEND_ARG_INFO(0, query)
01243 ZEND_END_ARG_INFO()
01244 
01245 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdo_lastinsertid, 0, 0, 0)
01246        ZEND_ARG_INFO(0, seqname)
01247 ZEND_END_ARG_INFO()
01248 
01249 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdo_quote, 0, 0, 1)
01250        ZEND_ARG_INFO(0, string)
01251        ZEND_ARG_INFO(0, paramtype)
01252 ZEND_END_ARG_INFO()
01253 
01254 ZEND_BEGIN_ARG_INFO(arginfo_pdo__void, 0)
01255 ZEND_END_ARG_INFO()
01256 /* }}} */
01257 
01258 const zend_function_entry pdo_dbh_functions[] = {
01259        ZEND_MALIAS(PDO, __construct, dbh_constructor,   arginfo_pdo___construct,    ZEND_ACC_PUBLIC)
01260        PHP_ME(PDO, prepare,                             arginfo_pdo_prepare,        ZEND_ACC_PUBLIC)
01261        PHP_ME(PDO, beginTransaction,       arginfo_pdo__void,         ZEND_ACC_PUBLIC)
01262        PHP_ME(PDO, commit,                 arginfo_pdo__void,         ZEND_ACC_PUBLIC)
01263        PHP_ME(PDO, rollBack,               arginfo_pdo__void,         ZEND_ACC_PUBLIC)
01264        PHP_ME(PDO, inTransaction,          arginfo_pdo__void,         ZEND_ACC_PUBLIC)
01265        PHP_ME(PDO, setAttribute,   arginfo_pdo_setattribute,   ZEND_ACC_PUBLIC)
01266        PHP_ME(PDO, exec,                  arginfo_pdo_exec,           ZEND_ACC_PUBLIC)
01267        PHP_ME(PDO, query,                 NULL,                              ZEND_ACC_PUBLIC)
01268        PHP_ME(PDO, lastInsertId,   arginfo_pdo_lastinsertid,   ZEND_ACC_PUBLIC)
01269        PHP_ME(PDO, errorCode,              arginfo_pdo__void,         ZEND_ACC_PUBLIC)
01270        PHP_ME(PDO, errorInfo,              arginfo_pdo__void,         ZEND_ACC_PUBLIC)
01271        PHP_ME(PDO, getAttribute,   arginfo_pdo_getattribute,   ZEND_ACC_PUBLIC)
01272        PHP_ME(PDO, quote,                 arginfo_pdo_quote,          ZEND_ACC_PUBLIC)
01273        PHP_ME(PDO, __wakeup,               arginfo_pdo__void,         ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
01274        PHP_ME(PDO, __sleep,                arginfo_pdo__void,         ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
01275        PHP_ME(PDO, getAvailableDrivers,    arginfo_pdo__void,         ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
01276        {NULL, NULL, NULL}
01277 };
01278 
01279 /* {{{ overloaded object handlers for PDO class */
01280 int pdo_hash_methods(pdo_dbh_t *dbh, int kind TSRMLS_DC)
01281 {
01282        const zend_function_entry *funcs;
01283        zend_function func;
01284        zend_internal_function *ifunc = (zend_internal_function*)&func;
01285        int namelen;
01286        char *lc_name;
01287 
01288        if (!dbh || !dbh->methods || !dbh->methods->get_driver_methods) {
01289               return 0;
01290        }
01291        funcs =       dbh->methods->get_driver_methods(dbh, kind TSRMLS_CC);
01292        if (!funcs) {
01293               return 0;
01294        }
01295 
01296        if (!(dbh->cls_methods[kind] = pemalloc(sizeof(HashTable), dbh->is_persistent))) {
01297               php_error_docref(NULL TSRMLS_CC, E_ERROR, "out of memory while allocating PDO methods.");
01298        }
01299        zend_hash_init_ex(dbh->cls_methods[kind], 8, NULL, NULL, dbh->is_persistent, 0);
01300 
01301        while (funcs->fname) {
01302               ifunc->type = ZEND_INTERNAL_FUNCTION;
01303               ifunc->handler = funcs->handler;
01304               ifunc->function_name = (char*)funcs->fname;
01305               ifunc->scope = dbh->ce;
01306               ifunc->prototype = NULL;
01307               if (funcs->arg_info) {
01308                      ifunc->arg_info = (zend_arg_info*)funcs->arg_info + 1;
01309                      ifunc->num_args = funcs->num_args;
01310                      if (funcs->arg_info[0].required_num_args == -1) {
01311                             ifunc->required_num_args = funcs->num_args;
01312                      } else {
01313                             ifunc->required_num_args = funcs->arg_info[0].required_num_args;
01314                      }
01315                      ifunc->pass_rest_by_reference = funcs->arg_info[0].pass_by_reference;
01316                      ifunc->return_reference = funcs->arg_info[0].return_reference;
01317               } else {
01318                      ifunc->arg_info = NULL;
01319                      ifunc->num_args = 0;
01320                      ifunc->required_num_args = 0;
01321                      ifunc->pass_rest_by_reference = 0;
01322                      ifunc->return_reference = 0;
01323               }
01324               if (funcs->flags) {
01325                      ifunc->fn_flags = funcs->flags;
01326               } else {
01327                      ifunc->fn_flags = ZEND_ACC_PUBLIC;
01328               }
01329               namelen = strlen(funcs->fname);
01330               lc_name = emalloc(namelen+1);
01331               zend_str_tolower_copy(lc_name, funcs->fname, namelen);
01332               zend_hash_add(dbh->cls_methods[kind], lc_name, namelen+1, &func, sizeof(func), NULL);
01333               efree(lc_name);
01334               funcs++;
01335        }
01336 
01337        return 1;
01338 }
01339 
01340 static union _zend_function *dbh_method_get(
01341 #if PHP_API_VERSION >= 20041225
01342        zval **object_pp,
01343 #else
01344        zval *object,
01345 #endif
01346        char *method_name, int method_len TSRMLS_DC)
01347 {
01348        zend_function *fbc = NULL;
01349        char *lc_method_name;
01350 #if PHP_API_VERSION >= 20041225
01351        zval *object = *object_pp;
01352 #endif
01353        pdo_dbh_t *dbh = zend_object_store_get_object(object TSRMLS_CC);
01354 
01355        lc_method_name = emalloc(method_len + 1);
01356        zend_str_tolower_copy(lc_method_name, method_name, method_len);
01357 
01358        if ((fbc = std_object_handlers.get_method(object_pp, method_name, method_len TSRMLS_CC)) == NULL) {
01359               /* not a pre-defined method, nor a user-defined method; check
01360                * the driver specific methods */
01361               if (!dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH]) {
01362                      if (!pdo_hash_methods(dbh,
01363                             PDO_DBH_DRIVER_METHOD_KIND_DBH TSRMLS_CC)
01364                             || !dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH]) {
01365                             goto out;
01366                      }
01367               }
01368 
01369               if (zend_hash_find(dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH],
01370                             lc_method_name, method_len+1, (void**)&fbc) == FAILURE) {
01371                      if (!fbc) {
01372                             fbc = NULL;
01373                      }
01374               }
01375        }
01376 
01377 out:
01378        efree(lc_method_name);
01379        return fbc;
01380 }
01381 
01382 static int dbh_compare(zval *object1, zval *object2 TSRMLS_DC)
01383 {
01384        return -1;
01385 }
01386 
01387 static zend_object_handlers pdo_dbh_object_handlers;
01388 
01389 void pdo_dbh_init(TSRMLS_D)
01390 {
01391        zend_class_entry ce;
01392 
01393        INIT_CLASS_ENTRY(ce, "PDO", pdo_dbh_functions);
01394        pdo_dbh_ce = zend_register_internal_class(&ce TSRMLS_CC);
01395        pdo_dbh_ce->create_object = pdo_dbh_new;
01396 
01397        memcpy(&pdo_dbh_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
01398        pdo_dbh_object_handlers.get_method = dbh_method_get;
01399        pdo_dbh_object_handlers.compare_objects = dbh_compare;
01400        
01401        REGISTER_PDO_CLASS_CONST_LONG("PARAM_BOOL", (long)PDO_PARAM_BOOL);
01402        REGISTER_PDO_CLASS_CONST_LONG("PARAM_NULL", (long)PDO_PARAM_NULL);
01403        REGISTER_PDO_CLASS_CONST_LONG("PARAM_INT",  (long)PDO_PARAM_INT);
01404        REGISTER_PDO_CLASS_CONST_LONG("PARAM_STR",  (long)PDO_PARAM_STR);
01405        REGISTER_PDO_CLASS_CONST_LONG("PARAM_LOB",  (long)PDO_PARAM_LOB);
01406        REGISTER_PDO_CLASS_CONST_LONG("PARAM_STMT", (long)PDO_PARAM_STMT);
01407        REGISTER_PDO_CLASS_CONST_LONG("PARAM_INPUT_OUTPUT", (long)PDO_PARAM_INPUT_OUTPUT);
01408 
01409        REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_ALLOC",        (long)PDO_PARAM_EVT_ALLOC);
01410        REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_FREE",                (long)PDO_PARAM_EVT_FREE);
01411        REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_EXEC_PRE",            (long)PDO_PARAM_EVT_EXEC_PRE);
01412        REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_EXEC_POST",    (long)PDO_PARAM_EVT_EXEC_POST);
01413        REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_FETCH_PRE",    (long)PDO_PARAM_EVT_FETCH_PRE);
01414        REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_FETCH_POST",   (long)PDO_PARAM_EVT_FETCH_POST);
01415        REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_NORMALIZE",    (long)PDO_PARAM_EVT_NORMALIZE);
01416 
01417        REGISTER_PDO_CLASS_CONST_LONG("FETCH_LAZY", (long)PDO_FETCH_LAZY);
01418        REGISTER_PDO_CLASS_CONST_LONG("FETCH_ASSOC",(long)PDO_FETCH_ASSOC);
01419        REGISTER_PDO_CLASS_CONST_LONG("FETCH_NUM",  (long)PDO_FETCH_NUM);
01420        REGISTER_PDO_CLASS_CONST_LONG("FETCH_BOTH", (long)PDO_FETCH_BOTH);
01421        REGISTER_PDO_CLASS_CONST_LONG("FETCH_OBJ",  (long)PDO_FETCH_OBJ);
01422        REGISTER_PDO_CLASS_CONST_LONG("FETCH_BOUND",(long)PDO_FETCH_BOUND);
01423        REGISTER_PDO_CLASS_CONST_LONG("FETCH_COLUMN",(long)PDO_FETCH_COLUMN);
01424        REGISTER_PDO_CLASS_CONST_LONG("FETCH_CLASS",(long)PDO_FETCH_CLASS);
01425        REGISTER_PDO_CLASS_CONST_LONG("FETCH_INTO", (long)PDO_FETCH_INTO);
01426        REGISTER_PDO_CLASS_CONST_LONG("FETCH_FUNC", (long)PDO_FETCH_FUNC);
01427        REGISTER_PDO_CLASS_CONST_LONG("FETCH_GROUP",(long)PDO_FETCH_GROUP);
01428        REGISTER_PDO_CLASS_CONST_LONG("FETCH_UNIQUE",(long)PDO_FETCH_UNIQUE);
01429        REGISTER_PDO_CLASS_CONST_LONG("FETCH_KEY_PAIR",(long)PDO_FETCH_KEY_PAIR);
01430        REGISTER_PDO_CLASS_CONST_LONG("FETCH_CLASSTYPE",(long)PDO_FETCH_CLASSTYPE);
01431 #if PHP_MAJOR_VERSION > 5 || PHP_MINOR_VERSION >= 1
01432        REGISTER_PDO_CLASS_CONST_LONG("FETCH_SERIALIZE",(long)PDO_FETCH_SERIALIZE);
01433 #endif
01434        REGISTER_PDO_CLASS_CONST_LONG("FETCH_PROPS_LATE",(long)PDO_FETCH_PROPS_LATE);
01435        REGISTER_PDO_CLASS_CONST_LONG("FETCH_NAMED",(long)PDO_FETCH_NAMED);
01436 
01437        REGISTER_PDO_CLASS_CONST_LONG("ATTR_AUTOCOMMIT", (long)PDO_ATTR_AUTOCOMMIT);
01438        REGISTER_PDO_CLASS_CONST_LONG("ATTR_PREFETCH",          (long)PDO_ATTR_PREFETCH);
01439        REGISTER_PDO_CLASS_CONST_LONG("ATTR_TIMEOUT",           (long)PDO_ATTR_TIMEOUT);
01440        REGISTER_PDO_CLASS_CONST_LONG("ATTR_ERRMODE",           (long)PDO_ATTR_ERRMODE);
01441        REGISTER_PDO_CLASS_CONST_LONG("ATTR_SERVER_VERSION",    (long)PDO_ATTR_SERVER_VERSION);
01442        REGISTER_PDO_CLASS_CONST_LONG("ATTR_CLIENT_VERSION",    (long)PDO_ATTR_CLIENT_VERSION);
01443        REGISTER_PDO_CLASS_CONST_LONG("ATTR_SERVER_INFO",              (long)PDO_ATTR_SERVER_INFO);
01444        REGISTER_PDO_CLASS_CONST_LONG("ATTR_CONNECTION_STATUS",        (long)PDO_ATTR_CONNECTION_STATUS);
01445        REGISTER_PDO_CLASS_CONST_LONG("ATTR_CASE",                     (long)PDO_ATTR_CASE);
01446        REGISTER_PDO_CLASS_CONST_LONG("ATTR_CURSOR_NAME",       (long)PDO_ATTR_CURSOR_NAME);
01447        REGISTER_PDO_CLASS_CONST_LONG("ATTR_CURSOR",            (long)PDO_ATTR_CURSOR);
01448        REGISTER_PDO_CLASS_CONST_LONG("ATTR_ORACLE_NULLS",      (long)PDO_ATTR_ORACLE_NULLS);
01449        REGISTER_PDO_CLASS_CONST_LONG("ATTR_PERSISTENT", (long)PDO_ATTR_PERSISTENT);
01450        REGISTER_PDO_CLASS_CONST_LONG("ATTR_STATEMENT_CLASS",          (long)PDO_ATTR_STATEMENT_CLASS);
01451        REGISTER_PDO_CLASS_CONST_LONG("ATTR_FETCH_TABLE_NAMES",        (long)PDO_ATTR_FETCH_TABLE_NAMES);
01452        REGISTER_PDO_CLASS_CONST_LONG("ATTR_FETCH_CATALOG_NAMES",             (long)PDO_ATTR_FETCH_CATALOG_NAMES);
01453        REGISTER_PDO_CLASS_CONST_LONG("ATTR_DRIVER_NAME",              (long)PDO_ATTR_DRIVER_NAME);
01454        REGISTER_PDO_CLASS_CONST_LONG("ATTR_STRINGIFY_FETCHES",(long)PDO_ATTR_STRINGIFY_FETCHES);
01455        REGISTER_PDO_CLASS_CONST_LONG("ATTR_MAX_COLUMN_LEN",(long)PDO_ATTR_MAX_COLUMN_LEN);
01456        REGISTER_PDO_CLASS_CONST_LONG("ATTR_EMULATE_PREPARES",(long)PDO_ATTR_EMULATE_PREPARES);
01457        REGISTER_PDO_CLASS_CONST_LONG("ATTR_DEFAULT_FETCH_MODE",(long)PDO_ATTR_DEFAULT_FETCH_MODE);
01458        
01459        REGISTER_PDO_CLASS_CONST_LONG("ERRMODE_SILENT",  (long)PDO_ERRMODE_SILENT);
01460        REGISTER_PDO_CLASS_CONST_LONG("ERRMODE_WARNING", (long)PDO_ERRMODE_WARNING);
01461        REGISTER_PDO_CLASS_CONST_LONG("ERRMODE_EXCEPTION",      (long)PDO_ERRMODE_EXCEPTION);
01462 
01463        REGISTER_PDO_CLASS_CONST_LONG("CASE_NATURAL",    (long)PDO_CASE_NATURAL);
01464        REGISTER_PDO_CLASS_CONST_LONG("CASE_LOWER",      (long)PDO_CASE_LOWER);
01465        REGISTER_PDO_CLASS_CONST_LONG("CASE_UPPER",      (long)PDO_CASE_UPPER);
01466 
01467        REGISTER_PDO_CLASS_CONST_LONG("NULL_NATURAL",    (long)PDO_NULL_NATURAL);
01468        REGISTER_PDO_CLASS_CONST_LONG("NULL_EMPTY_STRING",      (long)PDO_NULL_EMPTY_STRING);
01469        REGISTER_PDO_CLASS_CONST_LONG("NULL_TO_STRING",  (long)PDO_NULL_TO_STRING);
01470                      
01471        REGISTER_PDO_CLASS_CONST_STRING("ERR_NONE",      PDO_ERR_NONE);
01472 
01473        REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_NEXT", (long)PDO_FETCH_ORI_NEXT);
01474        REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_PRIOR", (long)PDO_FETCH_ORI_PRIOR);
01475        REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_FIRST", (long)PDO_FETCH_ORI_FIRST);
01476        REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_LAST", (long)PDO_FETCH_ORI_LAST);
01477        REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_ABS", (long)PDO_FETCH_ORI_ABS);
01478        REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_REL", (long)PDO_FETCH_ORI_REL);
01479        
01480        REGISTER_PDO_CLASS_CONST_LONG("CURSOR_FWDONLY", (long)PDO_CURSOR_FWDONLY);
01481        REGISTER_PDO_CLASS_CONST_LONG("CURSOR_SCROLL", (long)PDO_CURSOR_SCROLL);
01482 
01483 #if 0
01484        REGISTER_PDO_CLASS_CONST_LONG("ERR_CANT_MAP",           (long)PDO_ERR_CANT_MAP);
01485        REGISTER_PDO_CLASS_CONST_LONG("ERR_SYNTAX",             (long)PDO_ERR_SYNTAX);
01486        REGISTER_PDO_CLASS_CONST_LONG("ERR_CONSTRAINT",  (long)PDO_ERR_CONSTRAINT);
01487        REGISTER_PDO_CLASS_CONST_LONG("ERR_NOT_FOUND",          (long)PDO_ERR_NOT_FOUND);
01488        REGISTER_PDO_CLASS_CONST_LONG("ERR_ALREADY_EXISTS",     (long)PDO_ERR_ALREADY_EXISTS);
01489        REGISTER_PDO_CLASS_CONST_LONG("ERR_NOT_IMPLEMENTED",    (long)PDO_ERR_NOT_IMPLEMENTED);
01490        REGISTER_PDO_CLASS_CONST_LONG("ERR_MISMATCH",           (long)PDO_ERR_MISMATCH);
01491        REGISTER_PDO_CLASS_CONST_LONG("ERR_TRUNCATED",          (long)PDO_ERR_TRUNCATED);
01492        REGISTER_PDO_CLASS_CONST_LONG("ERR_DISCONNECTED",       (long)PDO_ERR_DISCONNECTED);
01493        REGISTER_PDO_CLASS_CONST_LONG("ERR_NO_PERM",            (long)PDO_ERR_NO_PERM);
01494 #endif
01495 
01496 }
01497 
01498 static void dbh_free(pdo_dbh_t *dbh TSRMLS_DC)
01499 {
01500        int i;
01501 
01502        if (--dbh->refcount)
01503               return;
01504 
01505        if (dbh->query_stmt) {
01506               zval_dtor(&dbh->query_stmt_zval);
01507               dbh->query_stmt = NULL;
01508        }
01509 
01510        if (dbh->methods) {
01511               dbh->methods->closer(dbh TSRMLS_CC);
01512        }
01513 
01514        if (dbh->data_source) {
01515               pefree((char *)dbh->data_source, dbh->is_persistent);
01516        }
01517        if (dbh->username) {
01518               pefree(dbh->username, dbh->is_persistent);
01519        }
01520        if (dbh->password) {
01521               pefree(dbh->password, dbh->is_persistent);
01522        }
01523        
01524        if (dbh->persistent_id) {
01525               pefree((char *)dbh->persistent_id, dbh->is_persistent);
01526        }
01527 
01528        if (dbh->def_stmt_ctor_args) {
01529               zval_ptr_dtor(&dbh->def_stmt_ctor_args);
01530        }
01531        
01532        for (i = 0; i < PDO_DBH_DRIVER_METHOD_KIND__MAX; i++) {
01533               if (dbh->cls_methods[i]) {
01534                      zend_hash_destroy(dbh->cls_methods[i]);
01535                      pefree(dbh->cls_methods[i], dbh->is_persistent);
01536               }
01537        }
01538 
01539        pefree(dbh, dbh->is_persistent);
01540 }
01541 
01542 PDO_API void php_pdo_dbh_addref(pdo_dbh_t *dbh TSRMLS_DC)
01543 {
01544        dbh->refcount++;
01545 }
01546 
01547 PDO_API void php_pdo_dbh_delref(pdo_dbh_t *dbh TSRMLS_DC)
01548 {
01549        dbh_free(dbh TSRMLS_CC);
01550 }
01551 
01552 static void pdo_dbh_free_storage(pdo_dbh_t *dbh TSRMLS_DC)
01553 {
01554        if (dbh->in_txn && dbh->methods && dbh->methods->rollback) {
01555               dbh->methods->rollback(dbh TSRMLS_CC);
01556               dbh->in_txn = 0;
01557        }
01558 
01559        if (dbh->properties) {
01560               zend_hash_destroy(dbh->properties);
01561               efree(dbh->properties);
01562               dbh->properties = NULL;
01563        }
01564        
01565        if (dbh->is_persistent && dbh->methods && dbh->methods->persistent_shutdown) {
01566               dbh->methods->persistent_shutdown(dbh TSRMLS_CC);
01567        }
01568        dbh_free(dbh TSRMLS_CC);
01569 }
01570 
01571 zend_object_value pdo_dbh_new(zend_class_entry *ce TSRMLS_DC)
01572 {
01573        zend_object_value retval;
01574        pdo_dbh_t *dbh;
01575        zval *tmp;
01576 
01577        dbh = emalloc(sizeof(*dbh));
01578        memset(dbh, 0, sizeof(*dbh));
01579        dbh->ce = ce;
01580        dbh->refcount = 1;
01581        ALLOC_HASHTABLE(dbh->properties);
01582        zend_hash_init(dbh->properties, 0, NULL, ZVAL_PTR_DTOR, 0);
01583        zend_hash_copy(dbh->properties, &ce->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
01584        dbh->def_stmt_ce = pdo_dbstmt_ce;
01585        
01586        retval.handle = zend_objects_store_put(dbh, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t)pdo_dbh_free_storage, NULL TSRMLS_CC);
01587        retval.handlers = &pdo_dbh_object_handlers;
01588        
01589        return retval;
01590 }
01591 
01592 /* }}} */
01593 
01594 ZEND_RSRC_DTOR_FUNC(php_pdo_pdbh_dtor)
01595 {
01596        if (rsrc->ptr) {
01597               pdo_dbh_t *dbh = (pdo_dbh_t*)rsrc->ptr;
01598               dbh_free(dbh TSRMLS_CC);
01599               rsrc->ptr = NULL;
01600        }
01601 }
01602 
01603 /*
01604  * Local variables:
01605  * tab-width: 4
01606  * c-basic-offset: 4
01607  * End:
01608  * vim600: noet sw=4 ts=4 fdm=marker
01609  * vim<600: noet sw=4 ts=4
01610  */