root/ext/pdo/pdo_dbh.c

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

DEFINITIONS

This source file includes following definitions.
  1. pdo_raise_impl_error
  2. pdo_handle_error
  3. dsn_from_uri
  4. PHP_METHOD
  5. pdo_stmt_instantiate
  6. pdo_stmt_construct
  7. PHP_METHOD
  8. PHP_METHOD
  9. PHP_METHOD
  10. PHP_METHOD
  11. PHP_METHOD
  12. pdo_dbh_attribute_set
  13. PHP_METHOD
  14. PHP_METHOD
  15. PHP_METHOD
  16. PHP_METHOD
  17. PHP_METHOD
  18. PHP_METHOD
  19. PHP_METHOD
  20. PHP_METHOD
  21. PHP_METHOD
  22. PHP_METHOD
  23. PHP_METHOD
  24. cls_method_dtor
  25. cls_method_pdtor
  26. pdo_hash_methods
  27. dbh_method_get
  28. dbh_compare
  29. dbh_get_gc
  30. pdo_dbh_init
  31. dbh_free
  32. pdo_dbh_free_storage
  33. pdo_dbh_new
  34. ZEND_RSRC_DTOR_FUNC

   1 /*
   2   +----------------------------------------------------------------------+
   3   | PHP Version 7                                                        |
   4   +----------------------------------------------------------------------+
   5   | Copyright (c) 1997-2016 The PHP Group                                |
   6   +----------------------------------------------------------------------+
   7   | This source file is subject to version 3.01 of the PHP license,      |
   8   | that is bundled with this package in the file LICENSE, and is        |
   9   | available through the world-wide-web at the following url:           |
  10   | http://www.php.net/license/3_01.txt                                  |
  11   | If you did not receive a copy of the PHP license and are unable to   |
  12   | obtain it through the world-wide-web, please send a note to          |
  13   | license@php.net so we can mail you a copy immediately.               |
  14   +----------------------------------------------------------------------+
  15   | Author: Wez Furlong <wez@php.net>                                    |
  16   |         Marcus Boerger <helly@php.net>                               |
  17   |         Sterling Hughes <sterling@php.net>                           |
  18   +----------------------------------------------------------------------+
  19 */
  20 
  21 /* $Id$ */
  22 
  23 /* The PDO Database Handle Class */
  24 
  25 #ifdef HAVE_CONFIG_H
  26 #include "config.h"
  27 #endif
  28 
  29 #include "php.h"
  30 #include "php_ini.h"
  31 #include "ext/standard/info.h"
  32 #include "php_pdo.h"
  33 #include "php_pdo_driver.h"
  34 #include "php_pdo_int.h"
  35 #include "zend_exceptions.h"
  36 #include "zend_object_handlers.h"
  37 #include "zend_hash.h"
  38 
  39 static int pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value);
  40 
  41 void pdo_raise_impl_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *sqlstate, const char *supp) /* {{{ */
  42 {
  43         pdo_error_type *pdo_err = &dbh->error_code;
  44         char *message = NULL;
  45         const char *msg;
  46 
  47         if (dbh && dbh->error_mode == PDO_ERRMODE_SILENT) {
  48 #if 0
  49                 /* BUG: if user is running in silent mode and hits an error at the driver level
  50                  * when they use the PDO methods to call up the error information, they may
  51                  * get bogus information */
  52                 return;
  53 #endif
  54         }
  55 
  56         if (stmt) {
  57                 pdo_err = &stmt->error_code;
  58         }
  59 
  60         strncpy(*pdo_err, sqlstate, 6);
  61 
  62         /* hash sqlstate to error messages */
  63         msg = pdo_sqlstate_state_to_description(*pdo_err);
  64         if (!msg) {
  65                 msg = "<<Unknown error>>";
  66         }
  67 
  68         if (supp) {
  69                 spprintf(&message, 0, "SQLSTATE[%s]: %s: %s", *pdo_err, msg, supp);
  70         } else {
  71                 spprintf(&message, 0, "SQLSTATE[%s]: %s", *pdo_err, msg);
  72         }
  73 
  74         if (dbh && dbh->error_mode != PDO_ERRMODE_EXCEPTION) {
  75                 php_error_docref(NULL, E_WARNING, "%s", message);
  76         } else {
  77                 zval ex, info;
  78                 zend_class_entry *def_ex = php_pdo_get_exception_base(1), *pdo_ex = php_pdo_get_exception();
  79 
  80                 object_init_ex(&ex, pdo_ex);
  81 
  82                 zend_update_property_string(def_ex, &ex, "message", sizeof("message")-1, message);
  83                 zend_update_property_string(def_ex, &ex, "code", sizeof("code")-1, *pdo_err);
  84 
  85                 array_init(&info);
  86 
  87                 add_next_index_string(&info, *pdo_err);
  88                 add_next_index_long(&info, 0);
  89                 zend_update_property(pdo_ex, &ex, "errorInfo", sizeof("errorInfo")-1, &info);
  90                 zval_ptr_dtor(&info);
  91 
  92                 zend_throw_exception_object(&ex);
  93         }
  94 
  95         if (message) {
  96                 efree(message);
  97         }
  98 }
  99 /* }}} */
 100 
 101 PDO_API void pdo_handle_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt) /* {{{ */
 102 {
 103         pdo_error_type *pdo_err = &dbh->error_code;
 104         const char *msg = "<<Unknown>>";
 105         char *supp = NULL;
 106         zend_long native_code = 0;
 107         zend_string *message = NULL;
 108         zval info;
 109 
 110         if (dbh == NULL || dbh->error_mode == PDO_ERRMODE_SILENT) {
 111                 return;
 112         }
 113 
 114         if (stmt) {
 115                 pdo_err = &stmt->error_code;
 116         }
 117 
 118         /* hash sqlstate to error messages */
 119         msg = pdo_sqlstate_state_to_description(*pdo_err);
 120         if (!msg) {
 121                 msg = "<<Unknown error>>";
 122         }
 123 
 124         ZVAL_UNDEF(&info);
 125         if (dbh->methods->fetch_err) {
 126                 array_init(&info);
 127 
 128                 add_next_index_string(&info, *pdo_err);
 129 
 130                 if (dbh->methods->fetch_err(dbh, stmt, &info)) {
 131                         zval *item;
 132 
 133                         if ((item = zend_hash_index_find(Z_ARRVAL(info), 1)) != NULL) {
 134                                 native_code = Z_LVAL_P(item);
 135                         }
 136 
 137                         if ((item = zend_hash_index_find(Z_ARRVAL(info), 2)) != NULL) {
 138                                 supp = estrndup(Z_STRVAL_P(item), Z_STRLEN_P(item));
 139                         }
 140                 }
 141         }
 142 
 143         if (supp) {
 144                 message = strpprintf(0, "SQLSTATE[%s]: %s: %ld %s", *pdo_err, msg, native_code, supp);
 145         } else {
 146                 message = strpprintf(0, "SQLSTATE[%s]: %s", *pdo_err, msg);
 147         }
 148 
 149         if (dbh->error_mode == PDO_ERRMODE_WARNING) {
 150                 php_error_docref(NULL, E_WARNING, "%s", ZSTR_VAL(message));
 151         } else if (EG(exception) == NULL) {
 152                 zval ex;
 153                 zend_class_entry *def_ex = php_pdo_get_exception_base(1), *pdo_ex = php_pdo_get_exception();
 154 
 155                 object_init_ex(&ex, pdo_ex);
 156 
 157                 zend_update_property_str(def_ex, &ex, "message", sizeof("message") - 1, message);
 158                 zend_update_property_string(def_ex, &ex, "code", sizeof("code") - 1, *pdo_err);
 159 
 160                 if (!Z_ISUNDEF(info)) {
 161                         zend_update_property(pdo_ex, &ex, "errorInfo", sizeof("errorInfo") - 1, &info);
 162                 }
 163 
 164                 zend_throw_exception_object(&ex);
 165         }
 166 
 167         if (!Z_ISUNDEF(info)) {
 168                 zval_ptr_dtor(&info);
 169         }
 170 
 171         if (message) {
 172                 zend_string_release(message);
 173         }
 174 
 175         if (supp) {
 176                 efree(supp);
 177         }
 178 }
 179 /* }}} */
 180 
 181 static char *dsn_from_uri(char *uri, char *buf, size_t buflen) /* {{{ */
 182 {
 183         php_stream *stream;
 184         char *dsn = NULL;
 185 
 186         stream = php_stream_open_wrapper(uri, "rb", REPORT_ERRORS, NULL);
 187         if (stream) {
 188                 dsn = php_stream_get_line(stream, buf, buflen, NULL);
 189                 php_stream_close(stream);
 190         }
 191         return dsn;
 192 }
 193 /* }}} */
 194 
 195 /* {{{ proto void PDO::__construct(string dsn[, string username[, string passwd [, array options]]])
 196    */
 197 static PHP_METHOD(PDO, dbh_constructor)
 198 {
 199         zval *object = getThis();
 200         pdo_dbh_t *dbh = NULL;
 201         zend_bool is_persistent = 0;
 202         char *data_source;
 203         size_t data_source_len;
 204         char *colon;
 205         char *username=NULL, *password=NULL;
 206         size_t usernamelen, passwordlen;
 207         pdo_driver_t *driver = NULL;
 208         zval *options = NULL;
 209         char alt_dsn[512];
 210         int call_factory = 1;
 211         zend_error_handling zeh;
 212 
 213         if (FAILURE == zend_parse_parameters_throw(ZEND_NUM_ARGS(),
 214                                 "s|s!s!a!", &data_source, &data_source_len,
 215                                 &username, &usernamelen, &password, &passwordlen, &options)) {
 216                 return;
 217         }
 218 
 219         /* parse the data source name */
 220         colon = strchr(data_source, ':');
 221 
 222         if (!colon) {
 223                 /* let's see if this string has a matching dsn in the php.ini */
 224                 char *ini_dsn = NULL;
 225 
 226                 snprintf(alt_dsn, sizeof(alt_dsn), "pdo.dsn.%s", data_source);
 227                 if (FAILURE == cfg_get_string(alt_dsn, &ini_dsn)) {
 228                         zend_throw_exception_ex(php_pdo_get_exception(), 0, "invalid data source name");
 229                         return;
 230                 }
 231 
 232                 data_source = ini_dsn;
 233                 colon = strchr(data_source, ':');
 234 
 235                 if (!colon) {
 236                         zend_throw_exception_ex(php_pdo_get_exception(), 0, "invalid data source name (via INI: %s)", alt_dsn);
 237                         return;
 238                 }
 239         }
 240 
 241         if (!strncmp(data_source, "uri:", sizeof("uri:")-1)) {
 242                 /* the specified URI holds connection details */
 243                 data_source = dsn_from_uri(data_source + sizeof("uri:")-1, alt_dsn, sizeof(alt_dsn));
 244                 if (!data_source) {
 245                         zend_throw_exception_ex(php_pdo_get_exception(), 0, "invalid data source URI");
 246                         return;
 247                 }
 248                 colon = strchr(data_source, ':');
 249                 if (!colon) {
 250                         zend_throw_exception_ex(php_pdo_get_exception(), 0, "invalid data source name (via URI)");
 251                         return;
 252                 }
 253         }
 254 
 255         driver = pdo_find_driver(data_source, colon - data_source);
 256 
 257         if (!driver) {
 258                 /* NB: don't want to include the data_source in the error message as
 259                  * it might contain a password */
 260                 zend_throw_exception_ex(php_pdo_get_exception(), 0, "could not find driver");
 261                 return;
 262         }
 263 
 264         dbh = Z_PDO_DBH_P(object);
 265 
 266         /* is this supposed to be a persistent connection ? */
 267         if (options) {
 268                 int plen = 0;
 269                 char *hashkey = NULL;
 270                 zend_resource *le;
 271                 pdo_dbh_t *pdbh = NULL;
 272                 zval *v;
 273 
 274                 if ((v = zend_hash_index_find(Z_ARRVAL_P(options), PDO_ATTR_PERSISTENT)) != NULL) {
 275                         if (Z_TYPE_P(v) == IS_STRING &&
 276                                 !is_numeric_string(Z_STRVAL_P(v), Z_STRLEN_P(v), NULL, NULL, 0) && Z_STRLEN_P(v) > 0) {
 277                                 /* user specified key */
 278                                 plen = spprintf(&hashkey, 0, "PDO:DBH:DSN=%s:%s:%s:%s", data_source,
 279                                                 username ? username : "",
 280                                                 password ? password : "",
 281                                                 Z_STRVAL_P(v));
 282                                 is_persistent = 1;
 283                         } else {
 284                                 is_persistent = zval_get_long(v) ? 1 : 0;
 285                                 plen = spprintf(&hashkey, 0, "PDO:DBH:DSN=%s:%s:%s", data_source,
 286                                                 username ? username : "",
 287                                                 password ? password : "");
 288                         }
 289                 }
 290 
 291                 if (is_persistent) {
 292                         /* let's see if we have one cached.... */
 293                         if ((le = zend_hash_str_find_ptr(&EG(persistent_list), hashkey, plen)) != NULL) {
 294                                 if (le->type == php_pdo_list_entry()) {
 295                                         pdbh = (pdo_dbh_t*)le->ptr;
 296 
 297                                         /* is the connection still alive ? */
 298                                         if (pdbh->methods->check_liveness && FAILURE == (pdbh->methods->check_liveness)(pdbh)) {
 299                                                 /* nope... need to kill it */
 300                                                 /*??? memory leak */
 301                                                 zend_list_close(le);
 302                                                 pdbh = NULL;
 303                                         }
 304                                 }
 305                         }
 306 
 307                         if (pdbh) {
 308                                 call_factory = 0;
 309                         } else {
 310                                 /* need a brand new pdbh */
 311                                 pdbh = pecalloc(1, sizeof(*pdbh), 1);
 312 
 313                                 pdbh->is_persistent = 1;
 314                                 pdbh->persistent_id = pemalloc(plen + 1, 1);
 315                                 memcpy((char *)pdbh->persistent_id, hashkey, plen+1);
 316                                 pdbh->persistent_id_len = plen;
 317                                 pdbh->def_stmt_ce = dbh->def_stmt_ce;
 318                         }
 319                 }
 320 
 321                 if (pdbh) {
 322                         efree(dbh);
 323                         /* switch over to the persistent one */
 324                         Z_PDO_OBJECT_P(object)->inner = pdbh;
 325                         dbh = pdbh;
 326                 }
 327 
 328                 if (hashkey) {
 329                         efree(hashkey);
 330                 }
 331         }
 332 
 333         if (call_factory) {
 334                 dbh->data_source_len = strlen(colon + 1);
 335                 dbh->data_source = (const char*)pestrdup(colon + 1, is_persistent);
 336                 dbh->username = username ? pestrdup(username, is_persistent) : NULL;
 337                 dbh->password = password ? pestrdup(password, is_persistent) : NULL;
 338                 dbh->default_fetch_type = PDO_FETCH_BOTH;
 339         }
 340 
 341         dbh->auto_commit = pdo_attr_lval(options, PDO_ATTR_AUTOCOMMIT, 1);
 342 
 343         if (!dbh->data_source || (username && !dbh->username) || (password && !dbh->password)) {
 344                 php_error_docref(NULL, E_ERROR, "out of memory");
 345         }
 346 
 347         zend_replace_error_handling(EH_THROW, pdo_exception_ce, &zeh);
 348 
 349         if (!call_factory) {
 350                 /* we got a persistent guy from our cache */
 351                 goto options;
 352         }
 353 
 354         if (driver->db_handle_factory(dbh, options)) {
 355                 /* all set */
 356 
 357                 if (is_persistent) {
 358                         zend_resource le;
 359 
 360                         /* register in the persistent list etc. */
 361                         /* we should also need to replace the object store entry,
 362                            since it was created with emalloc */
 363 
 364                         le.type = php_pdo_list_entry();
 365                         le.ptr = dbh;
 366                         GC_REFCOUNT(&le) = 1;
 367 
 368                         if ((zend_hash_str_update_mem(&EG(persistent_list),
 369                                                 (char*)dbh->persistent_id, dbh->persistent_id_len, &le, sizeof(le))) == NULL) {
 370                                 php_error_docref(NULL, E_ERROR, "Failed to register persistent entry");
 371                         }
 372                 }
 373 
 374                 dbh->driver = driver;
 375 options:
 376                 if (options) {
 377                         zval *attr_value;
 378                         zend_ulong long_key;
 379                         zend_string *str_key = NULL;
 380 
 381                         ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(options), long_key, str_key, attr_value) {
 382                                 if (str_key) {
 383                                         continue;
 384                                 }
 385                                 pdo_dbh_attribute_set(dbh, long_key, attr_value);
 386                         } ZEND_HASH_FOREACH_END();
 387                 }
 388 
 389                 zend_restore_error_handling(&zeh);
 390                 return;
 391         }
 392 
 393         /* the connection failed; things will tidy up in free_storage */
 394         /* XXX raise exception */
 395         zend_restore_error_handling(&zeh);
 396         if (!EG(exception)) {
 397                 zend_throw_exception(pdo_exception_ce, "Constructor failed", 0);
 398         }
 399 }
 400 /* }}} */
 401 
 402 static zval *pdo_stmt_instantiate(pdo_dbh_t *dbh, zval *object, zend_class_entry *dbstmt_ce, zval *ctor_args) /* {{{ */
 403 {
 404         if (!Z_ISUNDEF_P(ctor_args)) {
 405                 if (Z_TYPE_P(ctor_args) != IS_ARRAY) {
 406                         pdo_raise_impl_error(dbh, NULL, "HY000", "constructor arguments must be passed as an array");
 407                         return NULL;
 408                 }
 409                 if (!dbstmt_ce->constructor) {
 410                         pdo_raise_impl_error(dbh, NULL, "HY000", "user-supplied statement does not accept constructor arguments");
 411                         return NULL;
 412                 }
 413         }
 414 
 415         if (UNEXPECTED(object_init_ex(object, dbstmt_ce) != SUCCESS)) {
 416                 return NULL;
 417         }
 418 
 419         return object;
 420 } /* }}} */
 421 
 422 static void pdo_stmt_construct(zend_execute_data *execute_data, pdo_stmt_t *stmt, zval *object, zend_class_entry *dbstmt_ce, zval *ctor_args) /* {{{ */
 423 {
 424         zval query_string;
 425         zval z_key;
 426 
 427         ZVAL_STRINGL(&query_string, stmt->query_string, stmt->query_stringlen);
 428         ZVAL_STRINGL(&z_key, "queryString", sizeof("queryString") - 1);
 429         std_object_handlers.write_property(object, &z_key, &query_string, NULL);
 430         zval_ptr_dtor(&query_string);
 431         zval_ptr_dtor(&z_key);
 432 
 433         if (dbstmt_ce->constructor) {
 434                 zend_fcall_info fci;
 435                 zend_fcall_info_cache fcc;
 436                 zval retval;
 437 
 438                 fci.size = sizeof(zend_fcall_info);
 439                 fci.function_table = &dbstmt_ce->function_table;
 440                 ZVAL_UNDEF(&fci.function_name);
 441                 fci.object = Z_OBJ_P(object);
 442                 fci.symbol_table = NULL;
 443                 fci.retval = &retval;
 444                 fci.param_count = 0;
 445                 fci.params = NULL;
 446                 fci.no_separation = 1;
 447 
 448                 zend_fcall_info_args(&fci, ctor_args);
 449 
 450                 fcc.initialized = 1;
 451                 fcc.function_handler = dbstmt_ce->constructor;
 452                 fcc.calling_scope = EG(scope);
 453                 fcc.called_scope = Z_OBJCE_P(object);
 454                 fcc.object = Z_OBJ_P(object);
 455 
 456                 if (zend_call_function(&fci, &fcc) != FAILURE) {
 457                         zval_ptr_dtor(&retval);
 458                 }
 459 
 460                 zend_fcall_info_args_clear(&fci, 1);
 461         }
 462 }
 463 /* }}} */
 464 
 465 /* {{{ proto object PDO::prepare(string statement [, array options])
 466    Prepares a statement for execution and returns a statement object */
 467 static PHP_METHOD(PDO, prepare)
 468 {
 469         pdo_stmt_t *stmt;
 470         char *statement;
 471         size_t statement_len;
 472         zval *options = NULL, *opt, *item, ctor_args;
 473         zend_class_entry *dbstmt_ce, *pce;
 474         pdo_dbh_object_t *dbh_obj = Z_PDO_OBJECT_P(getThis());
 475         pdo_dbh_t *dbh = dbh_obj->inner;
 476 
 477         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "s|a", &statement,
 478                         &statement_len, &options)) {
 479                 RETURN_FALSE;
 480         }
 481 
 482         PDO_DBH_CLEAR_ERR();
 483         PDO_CONSTRUCT_CHECK;
 484 
 485         if (ZEND_NUM_ARGS() > 1 && (opt = zend_hash_index_find(Z_ARRVAL_P(options), PDO_ATTR_STATEMENT_CLASS)) != NULL) {
 486                 if (Z_TYPE_P(opt) != IS_ARRAY || (item = zend_hash_index_find(Z_ARRVAL_P(opt), 0)) == NULL
 487                         || Z_TYPE_P(item) != IS_STRING
 488                         || (pce = zend_lookup_class(Z_STR_P(item))) == NULL
 489                 ) {
 490                         pdo_raise_impl_error(dbh, NULL, "HY000",
 491                                 "PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); "
 492                                 "the classname must be a string specifying an existing class"
 493                                 );
 494                         PDO_HANDLE_DBH_ERR();
 495                         RETURN_FALSE;
 496                 }
 497                 dbstmt_ce = pce;
 498                 if (!instanceof_function(dbstmt_ce, pdo_dbstmt_ce)) {
 499                         pdo_raise_impl_error(dbh, NULL, "HY000",
 500                                 "user-supplied statement class must be derived from PDOStatement");
 501                         PDO_HANDLE_DBH_ERR();
 502                         RETURN_FALSE;
 503                 }
 504                 if (dbstmt_ce->constructor && !(dbstmt_ce->constructor->common.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED))) {
 505                         pdo_raise_impl_error(dbh, NULL, "HY000",
 506                                 "user-supplied statement class cannot have a public constructor");
 507                         PDO_HANDLE_DBH_ERR();
 508                         RETURN_FALSE;
 509                 }
 510                 if ((item = zend_hash_index_find(Z_ARRVAL_P(opt), 1)) != NULL) {
 511                         if (Z_TYPE_P(item) != IS_ARRAY) {
 512                                 pdo_raise_impl_error(dbh, NULL, "HY000",
 513                                         "PDO::ATTR_STATEMENT_CLASS requires format array(classname, ctor_args); "
 514                                         "ctor_args must be an array"
 515                                 );
 516                                 PDO_HANDLE_DBH_ERR();
 517                                 RETURN_FALSE;
 518                         }
 519                         ZVAL_COPY_VALUE(&ctor_args, item);
 520                 } else {
 521                         ZVAL_UNDEF(&ctor_args);
 522                 }
 523         } else {
 524                 dbstmt_ce = dbh->def_stmt_ce;
 525                 ZVAL_COPY_VALUE(&ctor_args, &dbh->def_stmt_ctor_args);
 526         }
 527 
 528         if (!pdo_stmt_instantiate(dbh, return_value, dbstmt_ce, &ctor_args)) {
 529                 if (EXPECTED(!EG(exception))) {
 530                         pdo_raise_impl_error(dbh, NULL, "HY000",
 531                                 "failed to instantiate user-supplied statement class"
 532                                 );
 533                 }
 534                 PDO_HANDLE_DBH_ERR();
 535                 RETURN_FALSE;
 536         }
 537         stmt = Z_PDO_STMT_P(return_value);
 538 
 539         /* unconditionally keep this for later reference */
 540         stmt->query_string = estrndup(statement, statement_len);
 541         stmt->query_stringlen = statement_len;
 542         stmt->default_fetch_type = dbh->default_fetch_type;
 543         stmt->dbh = dbh;
 544         /* give it a reference to me */
 545         ZVAL_OBJ(&stmt->database_object_handle, &dbh_obj->std);
 546         Z_ADDREF(stmt->database_object_handle);
 547         /* we haven't created a lazy object yet */
 548         ZVAL_UNDEF(&stmt->lazy_object_ref);
 549 
 550         if (dbh->methods->preparer(dbh, statement, statement_len, stmt, options)) {
 551                 pdo_stmt_construct(execute_data, stmt, return_value, dbstmt_ce, &ctor_args);
 552                 return;
 553         }
 554 
 555         PDO_HANDLE_DBH_ERR();
 556 
 557         /* kill the object handle for the stmt here */
 558         zval_dtor(return_value);
 559 
 560         RETURN_FALSE;
 561 }
 562 /* }}} */
 563 
 564 /* {{{ proto bool PDO::beginTransaction()
 565    Initiates a transaction */
 566 static PHP_METHOD(PDO, beginTransaction)
 567 {
 568         pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
 569 
 570         if (zend_parse_parameters_none() == FAILURE) {
 571                 return;
 572         }
 573         PDO_CONSTRUCT_CHECK;
 574 
 575         if (dbh->in_txn) {
 576                 zend_throw_exception_ex(php_pdo_get_exception(), 0, "There is already an active transaction");
 577                 RETURN_FALSE;
 578         }
 579 
 580         if (!dbh->methods->begin) {
 581                 /* TODO: this should be an exception; see the auto-commit mode
 582                  * comments below */
 583                 zend_throw_exception_ex(php_pdo_get_exception(), 0, "This driver doesn't support transactions");
 584                 RETURN_FALSE;
 585         }
 586 
 587         if (dbh->methods->begin(dbh)) {
 588                 dbh->in_txn = 1;
 589                 RETURN_TRUE;
 590         }
 591 
 592         PDO_HANDLE_DBH_ERR();
 593         RETURN_FALSE;
 594 }
 595 /* }}} */
 596 
 597 /* {{{ proto bool PDO::commit()
 598    Commit a transaction */
 599 static PHP_METHOD(PDO, commit)
 600 {
 601         pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
 602 
 603         if (zend_parse_parameters_none() == FAILURE) {
 604                 return;
 605         }
 606         PDO_CONSTRUCT_CHECK;
 607 
 608         if (!dbh->in_txn) {
 609                 zend_throw_exception_ex(php_pdo_get_exception(), 0, "There is no active transaction");
 610                 RETURN_FALSE;
 611         }
 612 
 613         if (dbh->methods->commit(dbh)) {
 614                 dbh->in_txn = 0;
 615                 RETURN_TRUE;
 616         }
 617 
 618         PDO_HANDLE_DBH_ERR();
 619         RETURN_FALSE;
 620 }
 621 /* }}} */
 622 
 623 /* {{{ proto bool PDO::rollBack()
 624    roll back a transaction */
 625 static PHP_METHOD(PDO, rollBack)
 626 {
 627         pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
 628 
 629         if (zend_parse_parameters_none() == FAILURE) {
 630                 return;
 631         }
 632         PDO_CONSTRUCT_CHECK;
 633 
 634         if (!dbh->in_txn) {
 635                 zend_throw_exception_ex(php_pdo_get_exception(), 0, "There is no active transaction");
 636                 RETURN_FALSE;
 637         }
 638 
 639         if (dbh->methods->rollback(dbh)) {
 640                 dbh->in_txn = 0;
 641                 RETURN_TRUE;
 642         }
 643 
 644         PDO_HANDLE_DBH_ERR();
 645         RETURN_FALSE;
 646 }
 647 /* }}} */
 648 
 649 /* {{{ proto bool PDO::inTransaction()
 650    determine if inside a transaction */
 651 static PHP_METHOD(PDO, inTransaction)
 652 {
 653         pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
 654 
 655         if (zend_parse_parameters_none() == FAILURE) {
 656                 return;
 657         }
 658         PDO_CONSTRUCT_CHECK;
 659 
 660         if (!dbh->methods->in_transaction) {
 661                 RETURN_BOOL(dbh->in_txn);
 662         }
 663 
 664         RETURN_BOOL(dbh->methods->in_transaction(dbh));
 665 }
 666 /* }}} */
 667 
 668 static int pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) /* {{{ */
 669 {
 670         zend_long lval;
 671 
 672 #define PDO_LONG_PARAM_CHECK \
 673         if (Z_TYPE_P(value) != IS_LONG && Z_TYPE_P(value) != IS_STRING && Z_TYPE_P(value) != IS_FALSE && Z_TYPE_P(value) != IS_TRUE) { \
 674                 pdo_raise_impl_error(dbh, NULL, "HY000", "attribute value must be an integer"); \
 675                 PDO_HANDLE_DBH_ERR(); \
 676                 return FAILURE; \
 677         } \
 678 
 679         switch (attr) {
 680                 case PDO_ATTR_ERRMODE:
 681                         PDO_LONG_PARAM_CHECK;
 682                         lval = zval_get_long(value);
 683                         switch (lval) {
 684                                 case PDO_ERRMODE_SILENT:
 685                                 case PDO_ERRMODE_WARNING:
 686                                 case PDO_ERRMODE_EXCEPTION:
 687                                         dbh->error_mode = lval;
 688                                         return SUCCESS;
 689                                 default:
 690                                         pdo_raise_impl_error(dbh, NULL, "HY000", "invalid error mode");
 691                                         PDO_HANDLE_DBH_ERR();
 692                                         return FAILURE;
 693                         }
 694                         return FAILURE;
 695 
 696                 case PDO_ATTR_CASE:
 697                         PDO_LONG_PARAM_CHECK;
 698                         lval = zval_get_long(value);
 699                         switch (lval) {
 700                                 case PDO_CASE_NATURAL:
 701                                 case PDO_CASE_UPPER:
 702                                 case PDO_CASE_LOWER:
 703                                         dbh->desired_case = lval;
 704                                         return SUCCESS;
 705                                 default:
 706                                         pdo_raise_impl_error(dbh, NULL, "HY000", "invalid case folding mode");
 707                                         PDO_HANDLE_DBH_ERR();
 708                                         return FAILURE;
 709                         }
 710                         return FAILURE;
 711 
 712                 case PDO_ATTR_ORACLE_NULLS:
 713                         PDO_LONG_PARAM_CHECK;
 714                         dbh->oracle_nulls = zval_get_long(value);
 715                         return SUCCESS;
 716 
 717                 case PDO_ATTR_DEFAULT_FETCH_MODE:
 718                         if (Z_TYPE_P(value) == IS_ARRAY) {
 719                                 zval *tmp;
 720                                 if ((tmp = zend_hash_index_find(Z_ARRVAL_P(value), 0)) != NULL && Z_TYPE_P(tmp) == IS_LONG) {
 721                                         if (Z_LVAL_P(tmp) == PDO_FETCH_INTO || Z_LVAL_P(tmp) == PDO_FETCH_CLASS) {
 722                                                 pdo_raise_impl_error(dbh, NULL, "HY000", "FETCH_INTO and FETCH_CLASS are not yet supported as default fetch modes");
 723                                                 return FAILURE;
 724                                         }
 725                                 }
 726                         } else {
 727                                 PDO_LONG_PARAM_CHECK;
 728                         }
 729                         lval = zval_get_long(value);
 730                         if (lval == PDO_FETCH_USE_DEFAULT) {
 731                                 pdo_raise_impl_error(dbh, NULL, "HY000", "invalid fetch mode type");
 732                                 return FAILURE;
 733                         }
 734                         dbh->default_fetch_type = lval;
 735                         return SUCCESS;
 736 
 737                 case PDO_ATTR_STRINGIFY_FETCHES:
 738                         PDO_LONG_PARAM_CHECK;
 739                         dbh->stringify = zval_get_long(value) ? 1 : 0;
 740                         return SUCCESS;
 741 
 742                 case PDO_ATTR_STATEMENT_CLASS: {
 743                         /* array(string classname, array(mixed ctor_args)) */
 744                         zend_class_entry *pce;
 745                         zval *item;
 746 
 747                         if (dbh->is_persistent) {
 748                                 pdo_raise_impl_error(dbh, NULL, "HY000",
 749                                         "PDO::ATTR_STATEMENT_CLASS cannot be used with persistent PDO instances"
 750                                         );
 751                                 PDO_HANDLE_DBH_ERR();
 752                                 return FAILURE;
 753                         }
 754                         if (Z_TYPE_P(value) != IS_ARRAY
 755                                 || (item = zend_hash_index_find(Z_ARRVAL_P(value), 0)) == NULL
 756                                 || Z_TYPE_P(item) != IS_STRING
 757                                 || (pce = zend_lookup_class(Z_STR_P(item))) == NULL
 758                         ) {
 759                                 pdo_raise_impl_error(dbh, NULL, "HY000",
 760                                         "PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); "
 761                                         "the classname must be a string specifying an existing class"
 762                                         );
 763                                 PDO_HANDLE_DBH_ERR();
 764                                 return FAILURE;
 765                         }
 766                         if (!instanceof_function(pce, pdo_dbstmt_ce)) {
 767                                 pdo_raise_impl_error(dbh, NULL, "HY000",
 768                                         "user-supplied statement class must be derived from PDOStatement");
 769                                 PDO_HANDLE_DBH_ERR();
 770                                 return FAILURE;
 771                         }
 772                         if (pce->constructor && !(pce->constructor->common.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED))) {
 773                                 pdo_raise_impl_error(dbh, NULL, "HY000",
 774                                         "user-supplied statement class cannot have a public constructor");
 775                                 PDO_HANDLE_DBH_ERR();
 776                                 return FAILURE;
 777                         }
 778                         dbh->def_stmt_ce = pce;
 779                         if (!Z_ISUNDEF(dbh->def_stmt_ctor_args)) {
 780                                 zval_ptr_dtor(&dbh->def_stmt_ctor_args);
 781                                 ZVAL_UNDEF(&dbh->def_stmt_ctor_args);
 782                         }
 783                         if ((item = zend_hash_index_find(Z_ARRVAL_P(value), 1)) != NULL) {
 784                                 if (Z_TYPE_P(item) != IS_ARRAY) {
 785                                         pdo_raise_impl_error(dbh, NULL, "HY000",
 786                                                 "PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); "
 787                                                 "ctor_args must be an array"
 788                                         );
 789                                         PDO_HANDLE_DBH_ERR();
 790                                         return FAILURE;
 791                                 }
 792                                 ZVAL_COPY(&dbh->def_stmt_ctor_args, item);
 793                         }
 794                         return SUCCESS;
 795                 }
 796 
 797                 default:
 798                         ;
 799         }
 800 
 801         if (!dbh->methods->set_attribute) {
 802                 goto fail;
 803         }
 804 
 805         PDO_DBH_CLEAR_ERR();
 806         if (dbh->methods->set_attribute(dbh, attr, value)) {
 807                 return SUCCESS;
 808         }
 809 
 810 fail:
 811         if (attr == PDO_ATTR_AUTOCOMMIT) {
 812                 zend_throw_exception_ex(php_pdo_get_exception(), 0, "The auto-commit mode cannot be changed for this driver");
 813         } else if (!dbh->methods->set_attribute) {
 814                 pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support setting attributes");
 815         } else {
 816                 PDO_HANDLE_DBH_ERR();
 817         }
 818         return FAILURE;
 819 }
 820 /* }}} */
 821 
 822 /* {{{ proto bool PDO::setAttribute(long attribute, mixed value)
 823    Set an attribute */
 824 static PHP_METHOD(PDO, setAttribute)
 825 {
 826         pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
 827         zend_long attr;
 828         zval *value;
 829 
 830         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "lz", &attr, &value)) {
 831                 RETURN_FALSE;
 832         }
 833 
 834         PDO_DBH_CLEAR_ERR();
 835         PDO_CONSTRUCT_CHECK;
 836 
 837         if (pdo_dbh_attribute_set(dbh, attr, value) != FAILURE) {
 838                 RETURN_TRUE;
 839         }
 840         RETURN_FALSE;
 841 }
 842 /* }}} */
 843 
 844 /* {{{ proto mixed PDO::getAttribute(long attribute)
 845    Get an attribute */
 846 static PHP_METHOD(PDO, getAttribute)
 847 {
 848         pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
 849         zend_long attr;
 850 
 851         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "l", &attr)) {
 852                 RETURN_FALSE;
 853         }
 854 
 855         PDO_DBH_CLEAR_ERR();
 856         PDO_CONSTRUCT_CHECK;
 857 
 858         /* handle generic PDO-level attributes */
 859         switch (attr) {
 860                 case PDO_ATTR_PERSISTENT:
 861                         RETURN_BOOL(dbh->is_persistent);
 862 
 863                 case PDO_ATTR_CASE:
 864                         RETURN_LONG(dbh->desired_case);
 865 
 866                 case PDO_ATTR_ORACLE_NULLS:
 867                         RETURN_LONG(dbh->oracle_nulls);
 868 
 869                 case PDO_ATTR_ERRMODE:
 870                         RETURN_LONG(dbh->error_mode);
 871 
 872                 case PDO_ATTR_DRIVER_NAME:
 873                         RETURN_STRINGL((char*)dbh->driver->driver_name, dbh->driver->driver_name_len);
 874 
 875                 case PDO_ATTR_STATEMENT_CLASS:
 876                         array_init(return_value);
 877                         add_next_index_str(return_value, zend_string_copy(dbh->def_stmt_ce->name));
 878                         if (!Z_ISUNDEF(dbh->def_stmt_ctor_args)) {
 879                                 if (Z_REFCOUNTED(dbh->def_stmt_ctor_args)) Z_ADDREF(dbh->def_stmt_ctor_args);
 880                                 add_next_index_zval(return_value, &dbh->def_stmt_ctor_args);
 881                         }
 882                         return;
 883                 case PDO_ATTR_DEFAULT_FETCH_MODE:
 884                         RETURN_LONG(dbh->default_fetch_type);
 885                 default:
 886                         break;
 887         }
 888 
 889         if (!dbh->methods->get_attribute) {
 890                 pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support getting attributes");
 891                 RETURN_FALSE;
 892         }
 893 
 894         switch (dbh->methods->get_attribute(dbh, attr, return_value)) {
 895                 case -1:
 896                         PDO_HANDLE_DBH_ERR();
 897                         RETURN_FALSE;
 898 
 899                 case 0:
 900                         pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support that attribute");
 901                         RETURN_FALSE;
 902 
 903                 default:
 904                         return;
 905         }
 906 }
 907 /* }}} */
 908 
 909 /* {{{ proto long PDO::exec(string query)
 910    Execute a query that does not return a row set, returning the number of affected rows */
 911 static PHP_METHOD(PDO, exec)
 912 {
 913         pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
 914         char *statement;
 915         size_t statement_len;
 916         zend_long ret;
 917 
 918         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &statement, &statement_len)) {
 919                 RETURN_FALSE;
 920         }
 921 
 922         if (!statement_len) {
 923                 pdo_raise_impl_error(dbh, NULL, "HY000",  "trying to execute an empty query");
 924                 RETURN_FALSE;
 925         }
 926         PDO_DBH_CLEAR_ERR();
 927         PDO_CONSTRUCT_CHECK;
 928         ret = dbh->methods->doer(dbh, statement, statement_len);
 929         if(ret == -1) {
 930                 PDO_HANDLE_DBH_ERR();
 931                 RETURN_FALSE;
 932         } else {
 933                 RETURN_LONG(ret);
 934         }
 935 }
 936 /* }}} */
 937 
 938 /* {{{ proto string PDO::lastInsertId([string seqname])
 939    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. */
 940 static PHP_METHOD(PDO, lastInsertId)
 941 {
 942         pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
 943         char *name = NULL;
 944         size_t namelen;
 945 
 946         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|s!", &name, &namelen)) {
 947                 RETURN_FALSE;
 948         }
 949 
 950         PDO_DBH_CLEAR_ERR();
 951         PDO_CONSTRUCT_CHECK;
 952         if (!dbh->methods->last_id) {
 953                 pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support lastInsertId()");
 954                 RETURN_FALSE;
 955         } else {
 956                 size_t id_len;
 957                 char *id;
 958                 id = dbh->methods->last_id(dbh, name, &id_len);
 959                 if (!id) {
 960                         PDO_HANDLE_DBH_ERR();
 961                         RETURN_FALSE;
 962                 } else {
 963                         //??? use zend_string ?
 964                         RETVAL_STRINGL(id, id_len);
 965                         efree(id);
 966                 }
 967         }
 968 }
 969 /* }}} */
 970 
 971 /* {{{ proto string PDO::errorCode()
 972    Fetch the error code associated with the last operation on the database handle */
 973 static PHP_METHOD(PDO, errorCode)
 974 {
 975         pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
 976 
 977         if (zend_parse_parameters_none() == FAILURE) {
 978                 return;
 979         }
 980         PDO_CONSTRUCT_CHECK;
 981 
 982         if (dbh->query_stmt) {
 983                 RETURN_STRING(dbh->query_stmt->error_code);
 984         }
 985 
 986         if (dbh->error_code[0] == '\0') {
 987                 RETURN_NULL();
 988         }
 989 
 990         /**
 991          * Making sure that we fallback to the default implementation
 992          * if the dbh->error_code is not null.
 993          */
 994         RETURN_STRING(dbh->error_code);
 995 }
 996 /* }}} */
 997 
 998 /* {{{ proto int PDO::errorInfo()
 999    Fetch extended error information associated with the last operation on the database handle */
1000 static PHP_METHOD(PDO, errorInfo)
1001 {
1002         int error_count;
1003         int error_count_diff     = 0;
1004         int error_expected_count = 3;
1005 
1006         pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
1007 
1008         if (zend_parse_parameters_none() == FAILURE) {
1009                 return;
1010         }
1011 
1012         PDO_CONSTRUCT_CHECK;
1013 
1014         array_init(return_value);
1015 
1016         if (dbh->query_stmt) {
1017                 add_next_index_string(return_value, dbh->query_stmt->error_code);
1018                 if(!strncmp(dbh->query_stmt->error_code, PDO_ERR_NONE, sizeof(PDO_ERR_NONE))) goto fill_array;
1019         } else {
1020                 add_next_index_string(return_value, dbh->error_code);
1021                 if(!strncmp(dbh->error_code, PDO_ERR_NONE, sizeof(PDO_ERR_NONE))) goto fill_array;
1022         }
1023 
1024         if (dbh->methods->fetch_err) {
1025                 dbh->methods->fetch_err(dbh, dbh->query_stmt, return_value);
1026         }
1027 
1028 fill_array:
1029         /**
1030          * In order to be consistent, we have to make sure we add the good amount
1031          * of nulls depending on the current number of elements. We make a simple
1032          * difference and add the needed elements
1033          */
1034         error_count = zend_hash_num_elements(Z_ARRVAL_P(return_value));
1035 
1036         if (error_expected_count > error_count) {
1037                 int current_index;
1038 
1039                 error_count_diff = error_expected_count - error_count;
1040                 for (current_index = 0; current_index < error_count_diff; current_index++) {
1041                         add_next_index_null(return_value);
1042                 }
1043         }
1044 }
1045 /* }}} */
1046 
1047 /* {{{ proto object PDO::query(string sql [, PDOStatement::setFetchMode() args])
1048    Prepare and execute $sql; returns the statement object for iteration */
1049 static PHP_METHOD(PDO, query)
1050 {
1051         pdo_stmt_t *stmt;
1052         char *statement;
1053         size_t statement_len;
1054         pdo_dbh_object_t *dbh_obj = Z_PDO_OBJECT_P(getThis());
1055         pdo_dbh_t *dbh = dbh_obj->inner;
1056 
1057         /* Return a meaningful error when no parameters were passed */
1058         if (!ZEND_NUM_ARGS()) {
1059                 zend_parse_parameters(0, "z|z", NULL, NULL);
1060                 RETURN_FALSE;
1061         }
1062 
1063         if (FAILURE == zend_parse_parameters(1, "s", &statement,
1064                         &statement_len)) {
1065                 RETURN_FALSE;
1066         }
1067 
1068         PDO_DBH_CLEAR_ERR();
1069         PDO_CONSTRUCT_CHECK;
1070 
1071         if (!pdo_stmt_instantiate(dbh, return_value, dbh->def_stmt_ce, &dbh->def_stmt_ctor_args)) {
1072                 if (EXPECTED(!EG(exception))) {
1073                         pdo_raise_impl_error(dbh, NULL, "HY000", "failed to instantiate user supplied statement class");
1074                 }
1075                 return;
1076         }
1077         stmt = Z_PDO_STMT_P(return_value);
1078 
1079         /* unconditionally keep this for later reference */
1080         stmt->query_string = estrndup(statement, statement_len);
1081         stmt->query_stringlen = statement_len;
1082 
1083         stmt->default_fetch_type = dbh->default_fetch_type;
1084         stmt->active_query_string = stmt->query_string;
1085         stmt->active_query_stringlen = statement_len;
1086         stmt->dbh = dbh;
1087         /* give it a reference to me */
1088         ZVAL_OBJ(&stmt->database_object_handle, &dbh_obj->std);
1089         Z_ADDREF(stmt->database_object_handle);
1090         /* we haven't created a lazy object yet */
1091         ZVAL_UNDEF(&stmt->lazy_object_ref);
1092 
1093         if (dbh->methods->preparer(dbh, statement, statement_len, stmt, NULL)) {
1094                 PDO_STMT_CLEAR_ERR();
1095                 if (ZEND_NUM_ARGS() == 1 || SUCCESS == pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, 1)) {
1096 
1097                         /* now execute the statement */
1098                         PDO_STMT_CLEAR_ERR();
1099                         if (stmt->methods->executer(stmt)) {
1100                                 int ret = 1;
1101                                 if (!stmt->executed) {
1102                                         if (stmt->dbh->alloc_own_columns) {
1103                                                 ret = pdo_stmt_describe_columns(stmt);
1104                                         }
1105                                         stmt->executed = 1;
1106                                 }
1107                                 if (ret) {
1108                                         pdo_stmt_construct(execute_data, stmt, return_value, dbh->def_stmt_ce, &dbh->def_stmt_ctor_args);
1109                                         return;
1110                                 }
1111                         }
1112                 }
1113                 /* something broke */
1114                 dbh->query_stmt = stmt;
1115                 ZVAL_COPY_VALUE(&dbh->query_stmt_zval, return_value);
1116                 Z_DELREF(stmt->database_object_handle);
1117                 ZVAL_UNDEF(&stmt->database_object_handle);
1118                 PDO_HANDLE_STMT_ERR();
1119         } else {
1120                 PDO_HANDLE_DBH_ERR();
1121                 zval_ptr_dtor(return_value);
1122         }
1123 
1124         RETURN_FALSE;
1125 }
1126 /* }}} */
1127 
1128 /* {{{ proto string PDO::quote(string string [, int paramtype])
1129    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 */
1130 static PHP_METHOD(PDO, quote)
1131 {
1132         pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
1133         char *str;
1134         size_t str_len;
1135         zend_long paramtype = PDO_PARAM_STR;
1136         char *qstr;
1137         size_t qlen;
1138 
1139         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &str, &str_len, &paramtype)) {
1140                 RETURN_FALSE;
1141         }
1142 
1143         PDO_DBH_CLEAR_ERR();
1144         PDO_CONSTRUCT_CHECK;
1145         if (!dbh->methods->quoter) {
1146                 pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support quoting");
1147                 RETURN_FALSE;
1148         }
1149 
1150         if (dbh->methods->quoter(dbh, str, str_len, &qstr, &qlen, paramtype)) {
1151                 RETVAL_STRINGL(qstr, qlen);
1152                 efree(qstr);
1153                 return;
1154         }
1155         PDO_HANDLE_DBH_ERR();
1156         RETURN_FALSE;
1157 }
1158 /* }}} */
1159 
1160 /* {{{ proto int PDO::__wakeup()
1161    Prevents use of a PDO instance that has been unserialized */
1162 static PHP_METHOD(PDO, __wakeup)
1163 {
1164         zend_throw_exception_ex(php_pdo_get_exception(), 0, "You cannot serialize or unserialize PDO instances");
1165 }
1166 /* }}} */
1167 
1168 /* {{{ proto int PDO::__sleep()
1169    Prevents serialization of a PDO instance */
1170 static PHP_METHOD(PDO, __sleep)
1171 {
1172         zend_throw_exception_ex(php_pdo_get_exception(), 0, "You cannot serialize or unserialize PDO instances");
1173 }
1174 /* }}} */
1175 
1176 /* {{{ proto array PDO::getAvailableDrivers()
1177    Return array of available PDO drivers */
1178 static PHP_METHOD(PDO, getAvailableDrivers)
1179 {
1180         pdo_driver_t *pdriver;
1181 
1182         if (zend_parse_parameters_none() == FAILURE) {
1183                 return;
1184         }
1185 
1186         array_init(return_value);
1187 
1188         ZEND_HASH_FOREACH_PTR(&pdo_driver_hash, pdriver) {
1189                 add_next_index_stringl(return_value, (char*)pdriver->driver_name, pdriver->driver_name_len);
1190         } ZEND_HASH_FOREACH_END();
1191 }
1192 /* }}} */
1193 
1194 /* {{{ arginfo */
1195 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdo___construct, 0, 0, 1)
1196         ZEND_ARG_INFO(0, dsn)
1197         ZEND_ARG_INFO(0, username)
1198         ZEND_ARG_INFO(0, passwd)
1199         ZEND_ARG_INFO(0, options) /* array */
1200 ZEND_END_ARG_INFO()
1201 
1202 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdo_prepare, 0, 0, 1)
1203         ZEND_ARG_INFO(0, statement)
1204         ZEND_ARG_INFO(0, options) /* array */
1205 ZEND_END_ARG_INFO()
1206 
1207 ZEND_BEGIN_ARG_INFO(arginfo_pdo_setattribute, 0)
1208         ZEND_ARG_INFO(0, attribute)
1209         ZEND_ARG_INFO(0, value)
1210 ZEND_END_ARG_INFO()
1211 
1212 ZEND_BEGIN_ARG_INFO(arginfo_pdo_getattribute, 0)
1213         ZEND_ARG_INFO(0, attribute)
1214 ZEND_END_ARG_INFO()
1215 
1216 ZEND_BEGIN_ARG_INFO(arginfo_pdo_exec, 0)
1217         ZEND_ARG_INFO(0, query)
1218 ZEND_END_ARG_INFO()
1219 
1220 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdo_lastinsertid, 0, 0, 0)
1221         ZEND_ARG_INFO(0, seqname)
1222 ZEND_END_ARG_INFO()
1223 
1224 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdo_quote, 0, 0, 1)
1225         ZEND_ARG_INFO(0, string)
1226         ZEND_ARG_INFO(0, paramtype)
1227 ZEND_END_ARG_INFO()
1228 
1229 ZEND_BEGIN_ARG_INFO(arginfo_pdo__void, 0)
1230 ZEND_END_ARG_INFO()
1231 /* }}} */
1232 
1233 const zend_function_entry pdo_dbh_functions[] = /* {{{ */ {
1234         ZEND_MALIAS(PDO, __construct, dbh_constructor,  arginfo_pdo___construct,        ZEND_ACC_PUBLIC)
1235         PHP_ME(PDO, prepare,                            arginfo_pdo_prepare,            ZEND_ACC_PUBLIC)
1236         PHP_ME(PDO, beginTransaction,       arginfo_pdo__void,         ZEND_ACC_PUBLIC)
1237         PHP_ME(PDO, commit,                 arginfo_pdo__void,         ZEND_ACC_PUBLIC)
1238         PHP_ME(PDO, rollBack,               arginfo_pdo__void,         ZEND_ACC_PUBLIC)
1239         PHP_ME(PDO, inTransaction,          arginfo_pdo__void,         ZEND_ACC_PUBLIC)
1240         PHP_ME(PDO, setAttribute,       arginfo_pdo_setattribute,       ZEND_ACC_PUBLIC)
1241         PHP_ME(PDO, exec,                       arginfo_pdo_exec,               ZEND_ACC_PUBLIC)
1242         PHP_ME(PDO, query,                      NULL,                                   ZEND_ACC_PUBLIC)
1243         PHP_ME(PDO, lastInsertId,       arginfo_pdo_lastinsertid,       ZEND_ACC_PUBLIC)
1244         PHP_ME(PDO, errorCode,              arginfo_pdo__void,         ZEND_ACC_PUBLIC)
1245         PHP_ME(PDO, errorInfo,              arginfo_pdo__void,         ZEND_ACC_PUBLIC)
1246         PHP_ME(PDO, getAttribute,       arginfo_pdo_getattribute,       ZEND_ACC_PUBLIC)
1247         PHP_ME(PDO, quote,                      arginfo_pdo_quote,              ZEND_ACC_PUBLIC)
1248         PHP_ME(PDO, __wakeup,               arginfo_pdo__void,         ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
1249         PHP_ME(PDO, __sleep,                arginfo_pdo__void,         ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
1250         PHP_ME(PDO, getAvailableDrivers,    arginfo_pdo__void,         ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
1251         {NULL, NULL, NULL}
1252 };
1253 /* }}} */
1254 
1255 static void cls_method_dtor(zval *el) /* {{{ */ {
1256         zend_function *func = (zend_function*)Z_PTR_P(el);
1257         if (func->common.function_name) {
1258                 zend_string_release(func->common.function_name);
1259         }
1260         efree(func);
1261 }
1262 /* }}} */
1263 
1264 static void cls_method_pdtor(zval *el) /* {{{ */ {
1265         zend_function *func = (zend_function*)Z_PTR_P(el);
1266         if (func->common.function_name) {
1267                 zend_string_release(func->common.function_name);
1268         }
1269         pefree(func, 1);
1270 }
1271 /* }}} */
1272 
1273 /* {{{ overloaded object handlers for PDO class */
1274 int pdo_hash_methods(pdo_dbh_object_t *dbh_obj, int kind)
1275 {
1276         const zend_function_entry *funcs;
1277         zend_internal_function func;
1278         size_t namelen;
1279         char *lc_name;
1280         pdo_dbh_t *dbh = dbh_obj->inner;
1281 
1282         if (!dbh || !dbh->methods || !dbh->methods->get_driver_methods) {
1283                 return 0;
1284         }
1285         funcs = dbh->methods->get_driver_methods(dbh, kind);
1286         if (!funcs) {
1287                 return 0;
1288         }
1289 
1290         if (!(dbh->cls_methods[kind] = pemalloc(sizeof(HashTable), dbh->is_persistent))) {
1291                 php_error_docref(NULL, E_ERROR, "out of memory while allocating PDO methods.");
1292         }
1293         zend_hash_init_ex(dbh->cls_methods[kind], 8, NULL,
1294                         dbh->is_persistent? cls_method_pdtor : cls_method_dtor, dbh->is_persistent, 0);
1295 
1296         memset(&func, 0, sizeof(func));
1297 
1298         while (funcs->fname) {
1299                 func.type = ZEND_INTERNAL_FUNCTION;
1300                 func.handler = funcs->handler;
1301                 func.function_name = zend_string_init(funcs->fname, strlen(funcs->fname), dbh->is_persistent);
1302                 func.scope = dbh_obj->std.ce;
1303                 func.prototype = NULL;
1304                 if (funcs->flags) {
1305                         func.fn_flags = funcs->flags | ZEND_ACC_NEVER_CACHE;
1306                 } else {
1307                         func.fn_flags = ZEND_ACC_PUBLIC | ZEND_ACC_NEVER_CACHE;
1308                 }
1309                 if (funcs->arg_info) {
1310                         zend_internal_function_info *info = (zend_internal_function_info*)funcs->arg_info;
1311 
1312                         func.arg_info = (zend_internal_arg_info*)funcs->arg_info + 1;
1313                         func.num_args = funcs->num_args;
1314                         if (info->required_num_args == -1) {
1315                                 func.required_num_args = funcs->num_args;
1316                         } else {
1317                                 func.required_num_args = info->required_num_args;
1318                         }
1319                         if (info->return_reference) {
1320                                 func.fn_flags |= ZEND_ACC_RETURN_REFERENCE;
1321                         }
1322                         if (funcs->arg_info[funcs->num_args].is_variadic) {
1323                                 func.fn_flags |= ZEND_ACC_VARIADIC;
1324                                 /* Don't count the variadic argument */
1325                                 func.num_args--;
1326                         }
1327                 } else {
1328                         func.arg_info = NULL;
1329                         func.num_args = 0;
1330                         func.required_num_args = 0;
1331                 }
1332                 zend_set_function_arg_flags((zend_function*)&func);
1333                 namelen = strlen(funcs->fname);
1334                 lc_name = emalloc(namelen+1);
1335                 zend_str_tolower_copy(lc_name, funcs->fname, namelen);
1336                 zend_hash_str_add_mem(dbh->cls_methods[kind], lc_name, namelen, &func, sizeof(func));
1337                 efree(lc_name);
1338                 funcs++;
1339         }
1340 
1341         return 1;
1342 }
1343 
1344 static union _zend_function *dbh_method_get(zend_object **object, zend_string *method_name, const zval *key)
1345 {
1346         zend_function *fbc = NULL;
1347         pdo_dbh_object_t *dbh_obj = php_pdo_dbh_fetch_object(*object);
1348         zend_string *lc_method_name;
1349 
1350         lc_method_name = zend_string_init(ZSTR_VAL(method_name), ZSTR_LEN(method_name), 0);
1351         zend_str_tolower_copy(ZSTR_VAL(lc_method_name), ZSTR_VAL(method_name), ZSTR_LEN(method_name));
1352 
1353         if ((fbc = std_object_handlers.get_method(object, method_name, key)) == NULL) {
1354                 /* not a pre-defined method, nor a user-defined method; check
1355                  * the driver specific methods */
1356                 if (!dbh_obj->inner->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH]) {
1357                         if (!pdo_hash_methods(dbh_obj,
1358                                 PDO_DBH_DRIVER_METHOD_KIND_DBH)
1359                                 || !dbh_obj->inner->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH]) {
1360                                 goto out;
1361                         }
1362                 }
1363 
1364                 fbc = zend_hash_find_ptr(dbh_obj->inner->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH], lc_method_name);
1365         }
1366 
1367 out:
1368         zend_string_release(lc_method_name);
1369         return fbc;
1370 }
1371 
1372 static int dbh_compare(zval *object1, zval *object2)
1373 {
1374         return -1;
1375 }
1376 
1377 static HashTable *dbh_get_gc(zval *object, zval **gc_data, int *gc_count)
1378 {
1379         pdo_dbh_t *dbh = Z_PDO_DBH_P(object);
1380         *gc_data = &dbh->def_stmt_ctor_args;
1381         *gc_count = 1;
1382         return zend_std_get_properties(object);
1383 }
1384 
1385 static zend_object_handlers pdo_dbh_object_handlers;
1386 static void pdo_dbh_free_storage(zend_object *std);
1387 
1388 void pdo_dbh_init(void)
1389 {
1390         zend_class_entry ce;
1391 
1392         INIT_CLASS_ENTRY(ce, "PDO", pdo_dbh_functions);
1393         pdo_dbh_ce = zend_register_internal_class(&ce);
1394         pdo_dbh_ce->create_object = pdo_dbh_new;
1395 
1396         memcpy(&pdo_dbh_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
1397         pdo_dbh_object_handlers.offset = XtOffsetOf(pdo_dbh_object_t, std);
1398         pdo_dbh_object_handlers.dtor_obj = zend_objects_destroy_object;
1399         pdo_dbh_object_handlers.free_obj = pdo_dbh_free_storage;
1400         pdo_dbh_object_handlers.get_method = dbh_method_get;
1401         pdo_dbh_object_handlers.compare_objects = dbh_compare;
1402         pdo_dbh_object_handlers.get_gc = dbh_get_gc;
1403 
1404         REGISTER_PDO_CLASS_CONST_LONG("PARAM_BOOL", (zend_long)PDO_PARAM_BOOL);
1405         REGISTER_PDO_CLASS_CONST_LONG("PARAM_NULL", (zend_long)PDO_PARAM_NULL);
1406         REGISTER_PDO_CLASS_CONST_LONG("PARAM_INT",  (zend_long)PDO_PARAM_INT);
1407         REGISTER_PDO_CLASS_CONST_LONG("PARAM_STR",  (zend_long)PDO_PARAM_STR);
1408         REGISTER_PDO_CLASS_CONST_LONG("PARAM_LOB",  (zend_long)PDO_PARAM_LOB);
1409         REGISTER_PDO_CLASS_CONST_LONG("PARAM_STMT", (zend_long)PDO_PARAM_STMT);
1410         REGISTER_PDO_CLASS_CONST_LONG("PARAM_INPUT_OUTPUT", (zend_long)PDO_PARAM_INPUT_OUTPUT);
1411 
1412         REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_ALLOC",                (zend_long)PDO_PARAM_EVT_ALLOC);
1413         REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_FREE",                 (zend_long)PDO_PARAM_EVT_FREE);
1414         REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_EXEC_PRE",             (zend_long)PDO_PARAM_EVT_EXEC_PRE);
1415         REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_EXEC_POST",    (zend_long)PDO_PARAM_EVT_EXEC_POST);
1416         REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_FETCH_PRE",    (zend_long)PDO_PARAM_EVT_FETCH_PRE);
1417         REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_FETCH_POST",   (zend_long)PDO_PARAM_EVT_FETCH_POST);
1418         REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_NORMALIZE",    (zend_long)PDO_PARAM_EVT_NORMALIZE);
1419 
1420         REGISTER_PDO_CLASS_CONST_LONG("FETCH_LAZY", (zend_long)PDO_FETCH_LAZY);
1421         REGISTER_PDO_CLASS_CONST_LONG("FETCH_ASSOC", (zend_long)PDO_FETCH_ASSOC);
1422         REGISTER_PDO_CLASS_CONST_LONG("FETCH_NUM",  (zend_long)PDO_FETCH_NUM);
1423         REGISTER_PDO_CLASS_CONST_LONG("FETCH_BOTH", (zend_long)PDO_FETCH_BOTH);
1424         REGISTER_PDO_CLASS_CONST_LONG("FETCH_OBJ",  (zend_long)PDO_FETCH_OBJ);
1425         REGISTER_PDO_CLASS_CONST_LONG("FETCH_BOUND", (zend_long)PDO_FETCH_BOUND);
1426         REGISTER_PDO_CLASS_CONST_LONG("FETCH_COLUMN", (zend_long)PDO_FETCH_COLUMN);
1427         REGISTER_PDO_CLASS_CONST_LONG("FETCH_CLASS", (zend_long)PDO_FETCH_CLASS);
1428         REGISTER_PDO_CLASS_CONST_LONG("FETCH_INTO", (zend_long)PDO_FETCH_INTO);
1429         REGISTER_PDO_CLASS_CONST_LONG("FETCH_FUNC", (zend_long)PDO_FETCH_FUNC);
1430         REGISTER_PDO_CLASS_CONST_LONG("FETCH_GROUP", (zend_long)PDO_FETCH_GROUP);
1431         REGISTER_PDO_CLASS_CONST_LONG("FETCH_UNIQUE", (zend_long)PDO_FETCH_UNIQUE);
1432         REGISTER_PDO_CLASS_CONST_LONG("FETCH_KEY_PAIR", (zend_long)PDO_FETCH_KEY_PAIR);
1433         REGISTER_PDO_CLASS_CONST_LONG("FETCH_CLASSTYPE", (zend_long)PDO_FETCH_CLASSTYPE);
1434 
1435 #if PHP_VERSION_ID >= 50100
1436         REGISTER_PDO_CLASS_CONST_LONG("FETCH_SERIALIZE",(zend_long)PDO_FETCH_SERIALIZE);
1437 #endif
1438         REGISTER_PDO_CLASS_CONST_LONG("FETCH_PROPS_LATE", (zend_long)PDO_FETCH_PROPS_LATE);
1439         REGISTER_PDO_CLASS_CONST_LONG("FETCH_NAMED", (zend_long)PDO_FETCH_NAMED);
1440 
1441         REGISTER_PDO_CLASS_CONST_LONG("ATTR_AUTOCOMMIT",        (zend_long)PDO_ATTR_AUTOCOMMIT);
1442         REGISTER_PDO_CLASS_CONST_LONG("ATTR_PREFETCH",          (zend_long)PDO_ATTR_PREFETCH);
1443         REGISTER_PDO_CLASS_CONST_LONG("ATTR_TIMEOUT",           (zend_long)PDO_ATTR_TIMEOUT);
1444         REGISTER_PDO_CLASS_CONST_LONG("ATTR_ERRMODE",           (zend_long)PDO_ATTR_ERRMODE);
1445         REGISTER_PDO_CLASS_CONST_LONG("ATTR_SERVER_VERSION",    (zend_long)PDO_ATTR_SERVER_VERSION);
1446         REGISTER_PDO_CLASS_CONST_LONG("ATTR_CLIENT_VERSION",    (zend_long)PDO_ATTR_CLIENT_VERSION);
1447         REGISTER_PDO_CLASS_CONST_LONG("ATTR_SERVER_INFO",               (zend_long)PDO_ATTR_SERVER_INFO);
1448         REGISTER_PDO_CLASS_CONST_LONG("ATTR_CONNECTION_STATUS",         (zend_long)PDO_ATTR_CONNECTION_STATUS);
1449         REGISTER_PDO_CLASS_CONST_LONG("ATTR_CASE",                      (zend_long)PDO_ATTR_CASE);
1450         REGISTER_PDO_CLASS_CONST_LONG("ATTR_CURSOR_NAME",       (zend_long)PDO_ATTR_CURSOR_NAME);
1451         REGISTER_PDO_CLASS_CONST_LONG("ATTR_CURSOR",            (zend_long)PDO_ATTR_CURSOR);
1452         REGISTER_PDO_CLASS_CONST_LONG("ATTR_ORACLE_NULLS",      (zend_long)PDO_ATTR_ORACLE_NULLS);
1453         REGISTER_PDO_CLASS_CONST_LONG("ATTR_PERSISTENT",        (zend_long)PDO_ATTR_PERSISTENT);
1454         REGISTER_PDO_CLASS_CONST_LONG("ATTR_STATEMENT_CLASS",           (zend_long)PDO_ATTR_STATEMENT_CLASS);
1455         REGISTER_PDO_CLASS_CONST_LONG("ATTR_FETCH_TABLE_NAMES",         (zend_long)PDO_ATTR_FETCH_TABLE_NAMES);
1456         REGISTER_PDO_CLASS_CONST_LONG("ATTR_FETCH_CATALOG_NAMES",               (zend_long)PDO_ATTR_FETCH_CATALOG_NAMES);
1457         REGISTER_PDO_CLASS_CONST_LONG("ATTR_DRIVER_NAME",               (zend_long)PDO_ATTR_DRIVER_NAME);
1458         REGISTER_PDO_CLASS_CONST_LONG("ATTR_STRINGIFY_FETCHES", (zend_long)PDO_ATTR_STRINGIFY_FETCHES);
1459         REGISTER_PDO_CLASS_CONST_LONG("ATTR_MAX_COLUMN_LEN", (zend_long)PDO_ATTR_MAX_COLUMN_LEN);
1460         REGISTER_PDO_CLASS_CONST_LONG("ATTR_EMULATE_PREPARES", (zend_long)PDO_ATTR_EMULATE_PREPARES);
1461         REGISTER_PDO_CLASS_CONST_LONG("ATTR_DEFAULT_FETCH_MODE", (zend_long)PDO_ATTR_DEFAULT_FETCH_MODE);
1462 
1463         REGISTER_PDO_CLASS_CONST_LONG("ERRMODE_SILENT", (zend_long)PDO_ERRMODE_SILENT);
1464         REGISTER_PDO_CLASS_CONST_LONG("ERRMODE_WARNING",        (zend_long)PDO_ERRMODE_WARNING);
1465         REGISTER_PDO_CLASS_CONST_LONG("ERRMODE_EXCEPTION",      (zend_long)PDO_ERRMODE_EXCEPTION);
1466 
1467         REGISTER_PDO_CLASS_CONST_LONG("CASE_NATURAL",   (zend_long)PDO_CASE_NATURAL);
1468         REGISTER_PDO_CLASS_CONST_LONG("CASE_LOWER",     (zend_long)PDO_CASE_LOWER);
1469         REGISTER_PDO_CLASS_CONST_LONG("CASE_UPPER",     (zend_long)PDO_CASE_UPPER);
1470 
1471         REGISTER_PDO_CLASS_CONST_LONG("NULL_NATURAL",   (zend_long)PDO_NULL_NATURAL);
1472         REGISTER_PDO_CLASS_CONST_LONG("NULL_EMPTY_STRING",      (zend_long)PDO_NULL_EMPTY_STRING);
1473         REGISTER_PDO_CLASS_CONST_LONG("NULL_TO_STRING", (zend_long)PDO_NULL_TO_STRING);
1474 
1475         REGISTER_PDO_CLASS_CONST_STRING("ERR_NONE",     PDO_ERR_NONE);
1476 
1477         REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_NEXT", (zend_long)PDO_FETCH_ORI_NEXT);
1478         REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_PRIOR", (zend_long)PDO_FETCH_ORI_PRIOR);
1479         REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_FIRST", (zend_long)PDO_FETCH_ORI_FIRST);
1480         REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_LAST", (zend_long)PDO_FETCH_ORI_LAST);
1481         REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_ABS", (zend_long)PDO_FETCH_ORI_ABS);
1482         REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_REL", (zend_long)PDO_FETCH_ORI_REL);
1483 
1484         REGISTER_PDO_CLASS_CONST_LONG("CURSOR_FWDONLY", (zend_long)PDO_CURSOR_FWDONLY);
1485         REGISTER_PDO_CLASS_CONST_LONG("CURSOR_SCROLL", (zend_long)PDO_CURSOR_SCROLL);
1486 
1487 #if 0
1488         REGISTER_PDO_CLASS_CONST_LONG("ERR_CANT_MAP",           (zend_long)PDO_ERR_CANT_MAP);
1489         REGISTER_PDO_CLASS_CONST_LONG("ERR_SYNTAX",             (zend_long)PDO_ERR_SYNTAX);
1490         REGISTER_PDO_CLASS_CONST_LONG("ERR_CONSTRAINT",         (zend_long)PDO_ERR_CONSTRAINT);
1491         REGISTER_PDO_CLASS_CONST_LONG("ERR_NOT_FOUND",          (zend_long)PDO_ERR_NOT_FOUND);
1492         REGISTER_PDO_CLASS_CONST_LONG("ERR_ALREADY_EXISTS",     (zend_long)PDO_ERR_ALREADY_EXISTS);
1493         REGISTER_PDO_CLASS_CONST_LONG("ERR_NOT_IMPLEMENTED",    (zend_long)PDO_ERR_NOT_IMPLEMENTED);
1494         REGISTER_PDO_CLASS_CONST_LONG("ERR_MISMATCH",           (zend_long)PDO_ERR_MISMATCH);
1495         REGISTER_PDO_CLASS_CONST_LONG("ERR_TRUNCATED",          (zend_long)PDO_ERR_TRUNCATED);
1496         REGISTER_PDO_CLASS_CONST_LONG("ERR_DISCONNECTED",       (zend_long)PDO_ERR_DISCONNECTED);
1497         REGISTER_PDO_CLASS_CONST_LONG("ERR_NO_PERM",            (zend_long)PDO_ERR_NO_PERM);
1498 #endif
1499 
1500 }
1501 
1502 static void dbh_free(pdo_dbh_t *dbh, zend_bool free_persistent)
1503 {
1504         int i;
1505 
1506         if (dbh->is_persistent && !free_persistent) {
1507                 return;
1508         }
1509 
1510         if (dbh->query_stmt) {
1511                 zval_ptr_dtor(&dbh->query_stmt_zval);
1512                 dbh->query_stmt = NULL;
1513         }
1514 
1515         if (dbh->methods) {
1516                 dbh->methods->closer(dbh);
1517         }
1518 
1519         if (dbh->data_source) {
1520                 pefree((char *)dbh->data_source, dbh->is_persistent);
1521         }
1522         if (dbh->username) {
1523                 pefree(dbh->username, dbh->is_persistent);
1524         }
1525         if (dbh->password) {
1526                 pefree(dbh->password, dbh->is_persistent);
1527         }
1528 
1529         if (dbh->persistent_id) {
1530                 pefree((char *)dbh->persistent_id, dbh->is_persistent);
1531         }
1532 
1533         if (!Z_ISUNDEF(dbh->def_stmt_ctor_args)) {
1534                 zval_ptr_dtor(&dbh->def_stmt_ctor_args);
1535         }
1536 
1537         for (i = 0; i < PDO_DBH_DRIVER_METHOD_KIND__MAX; i++) {
1538                 if (dbh->cls_methods[i]) {
1539                         zend_hash_destroy(dbh->cls_methods[i]);
1540                         pefree(dbh->cls_methods[i], dbh->is_persistent);
1541                 }
1542         }
1543 
1544         pefree(dbh, dbh->is_persistent);
1545 }
1546 
1547 static void pdo_dbh_free_storage(zend_object *std)
1548 {
1549         pdo_dbh_t *dbh = php_pdo_dbh_fetch_inner(std);
1550         if (dbh->in_txn && dbh->methods && dbh->methods->rollback) {
1551                 dbh->methods->rollback(dbh);
1552                 dbh->in_txn = 0;
1553         }
1554 
1555         if (dbh->is_persistent && dbh->methods && dbh->methods->persistent_shutdown) {
1556                 dbh->methods->persistent_shutdown(dbh);
1557         }
1558         zend_object_std_dtor(std);
1559         dbh_free(dbh, 0);
1560 }
1561 
1562 zend_object *pdo_dbh_new(zend_class_entry *ce)
1563 {
1564         pdo_dbh_object_t *dbh;
1565 
1566         dbh = ecalloc(1, sizeof(pdo_dbh_object_t) + zend_object_properties_size(ce));
1567         zend_object_std_init(&dbh->std, ce);
1568         object_properties_init(&dbh->std, ce);
1569         rebuild_object_properties(&dbh->std);
1570         dbh->inner = ecalloc(1, sizeof(pdo_dbh_t));
1571         dbh->inner->def_stmt_ce = pdo_dbstmt_ce;
1572 
1573         dbh->std.handlers = &pdo_dbh_object_handlers;
1574 
1575         return &dbh->std;
1576 }
1577 
1578 /* }}} */
1579 
1580 ZEND_RSRC_DTOR_FUNC(php_pdo_pdbh_dtor) /* {{{ */
1581 {
1582         if (res->ptr) {
1583                 pdo_dbh_t *dbh = (pdo_dbh_t*)res->ptr;
1584                 dbh_free(dbh, 1);
1585                 res->ptr = NULL;
1586         }
1587 }
1588 /* }}} */
1589 
1590 /*
1591  * Local variables:
1592  * tab-width: 4
1593  * c-basic-offset: 4
1594  * End:
1595  * vim600: noet sw=4 ts=4 fdm=marker
1596  * vim<600: noet sw=4 ts=4
1597  */

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