@@ -313,6 +313,7 @@ PHP_METHOD(PDO, __construct)
313313 int plen = 0 ;
314314 char * hashkey = NULL ;
315315 pdo_dbh_t * pdbh = NULL ;
316+ pdo_dbh_t * * pdbh_ref = NULL ;
316317 zval * v ;
317318
318319 if ((v = zend_hash_index_find_deref (Z_ARRVAL_P (options ), PDO_ATTR_PERSISTENT )) != NULL ) {
@@ -338,9 +339,22 @@ PHP_METHOD(PDO, __construct)
338339 /* is the connection still alive ? */
339340 if (!pdbh || pdbh -> is_closed ||
340341 (pdbh -> methods -> check_liveness && FAILURE == (pdbh -> methods -> check_liveness )(pdbh ))) {
342+ /* clean up prior dbh reference */
343+ if (pdbh && pdbh -> persistent_resource ) {
344+ pdbh_ref = (pdo_dbh_t * * )pdbh -> persistent_resource -> ptr ;
345+ /* clear dbh reference to forestall end-of-request actions in destructor */
346+ * pdbh_ref = NULL ;
347+ zend_list_delete (pdbh -> persistent_resource );
348+ pdbh -> persistent_resource = NULL ;
349+ }
341350 /* need a brand new pdbh */
342351 pdbh = pecalloc (1 , sizeof (* pdbh ), 1 );
343-
352+ pdbh_ref = emalloc (sizeof (* pdbh_ref ));
353+ * pdbh_ref = pdbh ;
354+ pdbh -> persistent_resource = zend_register_resource (pdbh_ref , php_pdo_list_entry ());
355+ if (!pdbh -> persistent_resource ) {
356+ php_error_docref (NULL , E_ERROR , "Failed to register resource entry" );
357+ }
344358 pdbh -> is_persistent = 1 ;
345359 pdbh -> persistent_id = pemalloc (plen + 1 , 1 );
346360 memcpy ((char * )pdbh -> persistent_id , hashkey , plen + 1 );
@@ -394,7 +408,7 @@ PHP_METHOD(PDO, __construct)
394408 /* we should also need to replace the object store entry,
395409 since it was created with emalloc */
396410 /* if a resource is already registered, then it failed a liveness check
397- * and will be replaced, prompting destruct. */
411+ and will be replaced, prompting destruct. */
398412 if ((zend_register_persistent_resource (
399413 (char * )dbh -> persistent_id , dbh -> persistent_id_len , dbh , php_pdo_list_entry ())) == NULL ) {
400414 php_error_docref (NULL , E_ERROR , "Failed to register persistent entry" );
@@ -517,6 +531,8 @@ PHP_METHOD(PDO, prepare)
517531
518532 PDO_DBH_CLEAR_ERR ();
519533
534+ PDO_CLOSE_CHECK ;
535+
520536 if (options && (value = zend_hash_index_find (Z_ARRVAL_P (options ), PDO_ATTR_STATEMENT_CLASS )) != NULL ) {
521537 if (Z_TYPE_P (value ) != IS_ARRAY ) {
522538 zend_type_error ("PDO::ATTR_STATEMENT_CLASS value must be of type array, %s given" ,
@@ -604,6 +620,8 @@ PHP_METHOD(PDO, beginTransaction)
604620
605621 PDO_CONSTRUCT_CHECK ;
606622
623+ PDO_CLOSE_CHECK ;
624+
607625 if (pdo_is_in_transaction (dbh )) {
608626 zend_throw_exception_ex (php_pdo_get_exception (), 0 , "There is already an active transaction" );
609627 RETURN_THROWS ();
@@ -634,6 +652,8 @@ PHP_METHOD(PDO, commit)
634652
635653 PDO_CONSTRUCT_CHECK ;
636654
655+ PDO_CLOSE_CHECK ;
656+
637657 if (!pdo_is_in_transaction (dbh )) {
638658 zend_throw_exception_ex (php_pdo_get_exception (), 0 , "There is no active transaction" );
639659 RETURN_THROWS ();
@@ -658,6 +678,8 @@ PHP_METHOD(PDO, rollBack)
658678
659679 PDO_CONSTRUCT_CHECK ;
660680
681+ PDO_CLOSE_CHECK ;
682+
661683 if (!pdo_is_in_transaction (dbh )) {
662684 zend_throw_exception_ex (php_pdo_get_exception (), 0 , "There is no active transaction" );
663685 RETURN_THROWS ();
@@ -682,6 +704,8 @@ PHP_METHOD(PDO, inTransaction)
682704
683705 PDO_CONSTRUCT_CHECK ;
684706
707+ PDO_CLOSE_CHECK ;
708+
685709 RETURN_BOOL (pdo_is_in_transaction (dbh ));
686710}
687711/* }}} */
@@ -693,6 +717,8 @@ PHP_METHOD(PDO, isConnected)
693717
694718 ZEND_PARSE_PARAMETERS_NONE ();
695719
720+ PDO_CONSTRUCT_CHECK ;
721+
696722 RETURN_BOOL (!dbh -> is_closed );
697723}
698724/* }}} */
@@ -867,6 +893,12 @@ static bool pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) /
867893 default :;
868894 }
869895
896+ if (!dbh -> methods ) {
897+ pdo_raise_impl_error (dbh , NULL , "IM001" ,
898+ "driver attributes not initialized, possibly due to disconnect" );
899+ return false;
900+ }
901+
870902 if (!dbh -> methods -> set_attribute ) {
871903 goto fail ;
872904 }
@@ -954,6 +986,12 @@ PHP_METHOD(PDO, getAttribute)
954986 break ;
955987 }
956988
989+ if (!dbh -> methods ) {
990+ pdo_raise_impl_error (dbh , NULL , "IM001" ,
991+ "driver attributes not initialized, possibly due to disconnect" );
992+ RETURN_FALSE ;
993+ }
994+
957995 if (!dbh -> methods -> get_attribute ) {
958996 pdo_raise_impl_error (dbh , NULL , "IM001" , "driver does not support getting attributes" );
959997 RETURN_FALSE ;
@@ -994,6 +1032,8 @@ PHP_METHOD(PDO, exec)
9941032
9951033 PDO_DBH_CLEAR_ERR ();
9961034 PDO_CONSTRUCT_CHECK ;
1035+ PDO_CLOSE_CHECK ;
1036+
9971037 ret = dbh -> methods -> doer (dbh , statement );
9981038 if (ret == -1 ) {
9991039 PDO_HANDLE_DBH_ERR ();
@@ -1020,6 +1060,8 @@ PHP_METHOD(PDO, lastInsertId)
10201060
10211061 PDO_DBH_CLEAR_ERR ();
10221062
1063+ PDO_CLOSE_CHECK ;
1064+
10231065 if (!dbh -> methods -> last_id ) {
10241066 pdo_raise_impl_error (dbh , NULL , "IM001" , "driver does not support lastInsertId()" );
10251067 RETURN_FALSE ;
@@ -1040,6 +1082,8 @@ PHP_METHOD(PDO, errorCode)
10401082
10411083 ZEND_PARSE_PARAMETERS_NONE ();
10421084
1085+ PDO_CONSTRUCT_CHECK ;
1086+
10431087 if (dbh -> query_stmt ) {
10441088 RETURN_STRING (dbh -> query_stmt -> error_code );
10451089 }
@@ -1067,6 +1111,8 @@ PHP_METHOD(PDO, errorInfo)
10671111
10681112 ZEND_PARSE_PARAMETERS_NONE ();
10691113
1114+ PDO_CONSTRUCT_CHECK ;
1115+
10701116 array_init (return_value );
10711117
10721118 if (dbh -> query_stmt ) {
@@ -1127,6 +1173,8 @@ PHP_METHOD(PDO, query)
11271173
11281174 PDO_DBH_CLEAR_ERR ();
11291175
1176+ PDO_CLOSE_CHECK ;
1177+
11301178 if (!pdo_stmt_instantiate (dbh , return_value , dbh -> def_stmt_ce , & dbh -> def_stmt_ctor_args )) {
11311179 RETURN_THROWS ();
11321180 }
@@ -1194,6 +1242,9 @@ PHP_METHOD(PDO, quote)
11941242 PDO_CONSTRUCT_CHECK ;
11951243
11961244 PDO_DBH_CLEAR_ERR ();
1245+
1246+ PDO_CLOSE_CHECK ;
1247+
11971248 if (!dbh -> methods -> quoter ) {
11981249 pdo_raise_impl_error (dbh , NULL , "IM001" , "driver does not support quoting" );
11991250 RETURN_FALSE ;
@@ -1379,11 +1430,6 @@ void pdo_dbh_init(int module_number)
13791430/* Disconnect from the database and free associated driver. */
13801431static void dbh_shutdown (pdo_dbh_t * dbh )
13811432{
1382- if (dbh -> driver_data && dbh -> methods && dbh -> methods -> rollback && pdo_is_in_transaction (dbh )) {
1383- dbh -> methods -> rollback (dbh );
1384- dbh -> in_txn = false;
1385- }
1386-
13871433 if (dbh -> methods ) {
13881434 dbh -> methods -> closer (dbh );
13891435 }
@@ -1442,6 +1488,12 @@ static void dbh_free(pdo_dbh_t *dbh)
14421488 pefree ((char * )dbh -> persistent_id , dbh -> is_persistent );
14431489 }
14441490
1491+ if (dbh -> persistent_resource ) {
1492+ pdo_dbh_t * * dbh_ref = (pdo_dbh_t * * )dbh -> persistent_resource -> ptr ;
1493+ dbh -> persistent_resource = NULL ;
1494+ * dbh_ref = NULL ;
1495+ }
1496+
14451497 if (!Z_ISUNDEF (dbh -> def_stmt_ctor_args )) {
14461498 zval_ptr_dtor (& dbh -> def_stmt_ctor_args );
14471499 }
@@ -1475,10 +1527,6 @@ static void pdo_dbh_free_storage(zend_object *std)
14751527
14761528 /* dbh might be null if we OOMed during object initialization. */
14771529 if (dbh ) {
1478- if (dbh -> is_persistent && dbh -> methods && dbh -> methods -> persistent_shutdown ) {
1479- dbh -> methods -> persistent_shutdown (dbh );
1480- }
1481-
14821530 /* stmt is not persistent, even if dbh is, so it must be freed with pdo.
14831531 * Consider copying stmt error code to dbh at this point, seemingly the reason
14841532 * that the stmt is even being held, or even better, to do that at the time of
@@ -1488,12 +1536,14 @@ static void pdo_dbh_free_storage(zend_object *std)
14881536 dbh -> query_stmt = NULL ;
14891537 }
14901538
1491- /* a persisted dbh will be freed when the resource is destructed. */
1492- if (!(-- dbh -> refcount ) && !pdo_is_persisted (dbh )) {
1493- if (!dbh -> is_closed ) {
1494- dbh_shutdown (dbh );
1539+ if (!(-- dbh -> refcount )) {
1540+ /* a persisted dbh will be freed when the resource is destructed. */
1541+ if (!pdo_is_persisted (dbh )) {
1542+ if (!dbh -> is_closed ) {
1543+ dbh_shutdown (dbh );
1544+ }
1545+ dbh_free (dbh );
14951546 }
1496- dbh_free (dbh );
14971547 }
14981548 }
14991549
@@ -1517,6 +1567,27 @@ zend_object *pdo_dbh_new(zend_class_entry *ce)
15171567
15181568/* }}} */
15191569
1570+ ZEND_RSRC_DTOR_FUNC (php_pdo_pdbh_request_dtor ) /* {{{ */
1571+ {
1572+ if (res -> ptr ) {
1573+ pdo_dbh_t * * dbh_ref = (pdo_dbh_t * * )res -> ptr ;
1574+ if (* dbh_ref ) {
1575+ pdo_dbh_t * dbh = (pdo_dbh_t * )* dbh_ref ;
1576+ if (dbh -> methods && dbh -> methods -> persistent_shutdown ) {
1577+ dbh -> methods -> persistent_shutdown (dbh );
1578+ }
1579+ if (dbh -> methods && dbh -> methods -> rollback && pdo_is_in_transaction (dbh )) {
1580+ dbh -> methods -> rollback (dbh );
1581+ dbh -> in_txn = false;
1582+ }
1583+ dbh -> persistent_resource = NULL ;
1584+ }
1585+ efree (dbh_ref );
1586+ res -> ptr = NULL ;
1587+ }
1588+ }
1589+ /* }}} */
1590+
15201591ZEND_RSRC_DTOR_FUNC (php_pdo_pdbh_dtor ) /* {{{ */
15211592{
15221593 if (res -> ptr ) {
0 commit comments