@@ -313,6 +313,7 @@ PHP_METHOD(PDO, __construct)
313
313
int plen = 0 ;
314
314
char * hashkey = NULL ;
315
315
pdo_dbh_t * pdbh = NULL ;
316
+ pdo_dbh_t * * pdbh_ref = NULL ;
316
317
zval * v ;
317
318
318
319
if ((v = zend_hash_index_find_deref (Z_ARRVAL_P (options ), PDO_ATTR_PERSISTENT )) != NULL ) {
@@ -338,9 +339,22 @@ PHP_METHOD(PDO, __construct)
338
339
/* is the connection still alive ? */
339
340
if (!pdbh || pdbh -> is_closed ||
340
341
(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
+ }
341
350
/* need a brand new pdbh */
342
351
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
+ }
344
358
pdbh -> is_persistent = 1 ;
345
359
pdbh -> persistent_id = pemalloc (plen + 1 , 1 );
346
360
memcpy ((char * )pdbh -> persistent_id , hashkey , plen + 1 );
@@ -394,7 +408,7 @@ PHP_METHOD(PDO, __construct)
394
408
/* we should also need to replace the object store entry,
395
409
since it was created with emalloc */
396
410
/* 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. */
398
412
if ((zend_register_persistent_resource (
399
413
(char * )dbh -> persistent_id , dbh -> persistent_id_len , dbh , php_pdo_list_entry ())) == NULL ) {
400
414
php_error_docref (NULL , E_ERROR , "Failed to register persistent entry" );
@@ -517,6 +531,8 @@ PHP_METHOD(PDO, prepare)
517
531
518
532
PDO_DBH_CLEAR_ERR ();
519
533
534
+ PDO_CLOSE_CHECK ;
535
+
520
536
if (options && (value = zend_hash_index_find (Z_ARRVAL_P (options ), PDO_ATTR_STATEMENT_CLASS )) != NULL ) {
521
537
if (Z_TYPE_P (value ) != IS_ARRAY ) {
522
538
zend_type_error ("PDO::ATTR_STATEMENT_CLASS value must be of type array, %s given" ,
@@ -604,6 +620,8 @@ PHP_METHOD(PDO, beginTransaction)
604
620
605
621
PDO_CONSTRUCT_CHECK ;
606
622
623
+ PDO_CLOSE_CHECK ;
624
+
607
625
if (pdo_is_in_transaction (dbh )) {
608
626
zend_throw_exception_ex (php_pdo_get_exception (), 0 , "There is already an active transaction" );
609
627
RETURN_THROWS ();
@@ -634,6 +652,8 @@ PHP_METHOD(PDO, commit)
634
652
635
653
PDO_CONSTRUCT_CHECK ;
636
654
655
+ PDO_CLOSE_CHECK ;
656
+
637
657
if (!pdo_is_in_transaction (dbh )) {
638
658
zend_throw_exception_ex (php_pdo_get_exception (), 0 , "There is no active transaction" );
639
659
RETURN_THROWS ();
@@ -658,6 +678,8 @@ PHP_METHOD(PDO, rollBack)
658
678
659
679
PDO_CONSTRUCT_CHECK ;
660
680
681
+ PDO_CLOSE_CHECK ;
682
+
661
683
if (!pdo_is_in_transaction (dbh )) {
662
684
zend_throw_exception_ex (php_pdo_get_exception (), 0 , "There is no active transaction" );
663
685
RETURN_THROWS ();
@@ -682,6 +704,8 @@ PHP_METHOD(PDO, inTransaction)
682
704
683
705
PDO_CONSTRUCT_CHECK ;
684
706
707
+ PDO_CLOSE_CHECK ;
708
+
685
709
RETURN_BOOL (pdo_is_in_transaction (dbh ));
686
710
}
687
711
/* }}} */
@@ -693,6 +717,8 @@ PHP_METHOD(PDO, isConnected)
693
717
694
718
ZEND_PARSE_PARAMETERS_NONE ();
695
719
720
+ PDO_CONSTRUCT_CHECK ;
721
+
696
722
RETURN_BOOL (!dbh -> is_closed );
697
723
}
698
724
/* }}} */
@@ -900,6 +926,7 @@ PHP_METHOD(PDO, setAttribute)
900
926
901
927
PDO_DBH_CLEAR_ERR ();
902
928
PDO_CONSTRUCT_CHECK ;
929
+ PDO_CLOSE_CHECK ;
903
930
904
931
RETURN_BOOL (pdo_dbh_attribute_set (dbh , attr , value ));
905
932
}
@@ -954,6 +981,12 @@ PHP_METHOD(PDO, getAttribute)
954
981
break ;
955
982
}
956
983
984
+ if (!dbh -> methods ) {
985
+ pdo_raise_impl_error (dbh , NULL , "IM001" ,
986
+ "driver attributes not initialized, possibly due to disconnect" );
987
+ RETURN_FALSE ;
988
+ }
989
+
957
990
if (!dbh -> methods -> get_attribute ) {
958
991
pdo_raise_impl_error (dbh , NULL , "IM001" , "driver does not support getting attributes" );
959
992
RETURN_FALSE ;
@@ -994,6 +1027,8 @@ PHP_METHOD(PDO, exec)
994
1027
995
1028
PDO_DBH_CLEAR_ERR ();
996
1029
PDO_CONSTRUCT_CHECK ;
1030
+ PDO_CLOSE_CHECK ;
1031
+
997
1032
ret = dbh -> methods -> doer (dbh , statement );
998
1033
if (ret == -1 ) {
999
1034
PDO_HANDLE_DBH_ERR ();
@@ -1020,6 +1055,8 @@ PHP_METHOD(PDO, lastInsertId)
1020
1055
1021
1056
PDO_DBH_CLEAR_ERR ();
1022
1057
1058
+ PDO_CLOSE_CHECK ;
1059
+
1023
1060
if (!dbh -> methods -> last_id ) {
1024
1061
pdo_raise_impl_error (dbh , NULL , "IM001" , "driver does not support lastInsertId()" );
1025
1062
RETURN_FALSE ;
@@ -1040,6 +1077,8 @@ PHP_METHOD(PDO, errorCode)
1040
1077
1041
1078
ZEND_PARSE_PARAMETERS_NONE ();
1042
1079
1080
+ PDO_CONSTRUCT_CHECK ;
1081
+
1043
1082
if (dbh -> query_stmt ) {
1044
1083
RETURN_STRING (dbh -> query_stmt -> error_code );
1045
1084
}
@@ -1067,6 +1106,8 @@ PHP_METHOD(PDO, errorInfo)
1067
1106
1068
1107
ZEND_PARSE_PARAMETERS_NONE ();
1069
1108
1109
+ PDO_CONSTRUCT_CHECK ;
1110
+
1070
1111
array_init (return_value );
1071
1112
1072
1113
if (dbh -> query_stmt ) {
@@ -1127,6 +1168,8 @@ PHP_METHOD(PDO, query)
1127
1168
1128
1169
PDO_DBH_CLEAR_ERR ();
1129
1170
1171
+ PDO_CLOSE_CHECK ;
1172
+
1130
1173
if (!pdo_stmt_instantiate (dbh , return_value , dbh -> def_stmt_ce , & dbh -> def_stmt_ctor_args )) {
1131
1174
RETURN_THROWS ();
1132
1175
}
@@ -1194,6 +1237,9 @@ PHP_METHOD(PDO, quote)
1194
1237
PDO_CONSTRUCT_CHECK ;
1195
1238
1196
1239
PDO_DBH_CLEAR_ERR ();
1240
+
1241
+ PDO_CLOSE_CHECK ;
1242
+
1197
1243
if (!dbh -> methods -> quoter ) {
1198
1244
pdo_raise_impl_error (dbh , NULL , "IM001" , "driver does not support quoting" );
1199
1245
RETURN_FALSE ;
@@ -1379,11 +1425,6 @@ void pdo_dbh_init(int module_number)
1379
1425
/* Disconnect from the database and free associated driver. */
1380
1426
static void dbh_shutdown (pdo_dbh_t * dbh )
1381
1427
{
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
-
1387
1428
if (dbh -> methods ) {
1388
1429
dbh -> methods -> closer (dbh );
1389
1430
}
@@ -1442,6 +1483,11 @@ static void dbh_free(pdo_dbh_t *dbh)
1442
1483
pefree ((char * )dbh -> persistent_id , dbh -> is_persistent );
1443
1484
}
1444
1485
1486
+ if (dbh -> persistent_resource ) {
1487
+ dbh -> persistent_resource -> ptr = NULL ;
1488
+ dbh -> persistent_resource = NULL ;
1489
+ }
1490
+
1445
1491
if (!Z_ISUNDEF (dbh -> def_stmt_ctor_args )) {
1446
1492
zval_ptr_dtor (& dbh -> def_stmt_ctor_args );
1447
1493
}
@@ -1475,10 +1521,6 @@ static void pdo_dbh_free_storage(zend_object *std)
1475
1521
1476
1522
/* dbh might be null if we OOMed during object initialization. */
1477
1523
if (dbh ) {
1478
- if (dbh -> is_persistent && dbh -> methods && dbh -> methods -> persistent_shutdown ) {
1479
- dbh -> methods -> persistent_shutdown (dbh );
1480
- }
1481
-
1482
1524
/* stmt is not persistent, even if dbh is, so it must be freed with pdo.
1483
1525
* Consider copying stmt error code to dbh at this point, seemingly the reason
1484
1526
* that the stmt is even being held, or even better, to do that at the time of
@@ -1488,12 +1530,14 @@ static void pdo_dbh_free_storage(zend_object *std)
1488
1530
dbh -> query_stmt = NULL ;
1489
1531
}
1490
1532
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 );
1533
+ if (!(-- dbh -> refcount )) {
1534
+ /* a persisted dbh will be freed when the resource is destructed. */
1535
+ if (!pdo_is_persisted (dbh )) {
1536
+ if (!dbh -> is_closed ) {
1537
+ dbh_shutdown (dbh );
1538
+ }
1539
+ dbh_free (dbh );
1495
1540
}
1496
- dbh_free (dbh );
1497
1541
}
1498
1542
}
1499
1543
@@ -1517,6 +1561,27 @@ zend_object *pdo_dbh_new(zend_class_entry *ce)
1517
1561
1518
1562
/* }}} */
1519
1563
1564
+ ZEND_RSRC_DTOR_FUNC (php_pdo_pdbh_request_dtor ) /* {{{ */
1565
+ {
1566
+ if (res -> ptr ) {
1567
+ pdo_dbh_t * * dbh_ref = (pdo_dbh_t * * )res -> ptr ;
1568
+ if (* dbh_ref ) {
1569
+ pdo_dbh_t * dbh = (pdo_dbh_t * )* dbh_ref ;
1570
+ if (dbh -> methods && dbh -> methods -> persistent_shutdown ) {
1571
+ dbh -> methods -> persistent_shutdown (dbh );
1572
+ }
1573
+ if (dbh -> methods && dbh -> methods -> rollback && pdo_is_in_transaction (dbh )) {
1574
+ dbh -> methods -> rollback (dbh );
1575
+ dbh -> in_txn = false;
1576
+ }
1577
+ dbh -> persistent_resource = NULL ;
1578
+ }
1579
+ efree (dbh_ref );
1580
+ res -> ptr = NULL ;
1581
+ }
1582
+ }
1583
+ /* }}} */
1584
+
1520
1585
ZEND_RSRC_DTOR_FUNC (php_pdo_pdbh_dtor ) /* {{{ */
1521
1586
{
1522
1587
if (res -> ptr ) {
0 commit comments