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