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. pdo_hash_methods
  25. dbh_method_get
  26. dbh_compare
  27. pdo_dbh_init
  28. dbh_free
  29. php_pdo_dbh_addref
  30. php_pdo_dbh_delref
  31. pdo_dbh_free_storage
  32. pdo_dbh_new
  33. ZEND_RSRC_DTOR_FUNC

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

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