Skip to content

Commit 1754f4c

Browse files
pdo_pgsql: Reset persistent session state on disconnect-equivalent processing
1 parent ca914ee commit 1754f4c

File tree

4 files changed

+173
-1
lines changed

4 files changed

+173
-1
lines changed

ext/pdo_pgsql/pgsql_driver.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1340,6 +1340,20 @@ static const zend_function_entry *pdo_pgsql_get_driver_methods(pdo_dbh_t *dbh, i
13401340
}
13411341
}
13421342

1343+
static void pdo_pgsql_request_shutdown(pdo_dbh_t *dbh)
1344+
{
1345+
PGresult *res;
1346+
pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
1347+
1348+
if(H->server) {
1349+
res = PQexec(H->server, "DISCARD ALL");
1350+
1351+
if(res) {
1352+
PQclear(res);
1353+
}
1354+
}
1355+
}
1356+
13431357
static bool pdo_pgsql_set_attr(pdo_dbh_t *dbh, zend_long attr, zval *val)
13441358
{
13451359
bool bval;
@@ -1383,7 +1397,7 @@ static const struct pdo_dbh_methods pgsql_methods = {
13831397
pdo_pgsql_get_attribute,
13841398
pdo_pgsql_check_liveness, /* check_liveness */
13851399
pdo_pgsql_get_driver_methods, /* get_driver_methods */
1386-
NULL,
1400+
pdo_pgsql_request_shutdown,
13871401
pgsql_handle_in_transaction,
13881402
NULL, /* get_gc */
13891403
pdo_pgsql_scanner
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
--TEST--
2+
Persistent connections: session state reset when performing disconnect-equivalent processing (general case)
3+
--EXTENSIONS--
4+
pdo_pgsql
5+
--SKIPIF--
6+
<?php
7+
require __DIR__ . '/config.inc';
8+
require __DIR__ . '/../../../ext/pdo/tests/pdo_test.inc';
9+
PDOTest::skip();
10+
?>
11+
--FILE--
12+
<?php
13+
putenv('PDOTEST_ATTR='.serialize([PDO::ATTR_PERSISTENT => true]));
14+
15+
require __DIR__ . '/../../../ext/pdo/tests/pdo_test.inc';
16+
17+
$pdo1 = PDOTest::test_factory(__DIR__ . '/common.phpt');
18+
19+
$pid1 = (int)$pdo1
20+
->query('select pg_backend_pid()::int;')
21+
->fetchColumn(0);
22+
23+
$defaultValue = (int)$pdo1
24+
->query('show log_min_duration_statement;')
25+
->fetchColumn(0);
26+
27+
$setValue = $defaultValue + 1;
28+
29+
$pdo1->exec("set log_min_duration_statement = {$setValue};");
30+
31+
$pdo1 = null;
32+
33+
$pdo2 = PDOTest::test_factory(__DIR__ . '/common.phpt');
34+
35+
$pid2 = (int)$pdo2
36+
->query('select pg_backend_pid()::int;')
37+
->fetchColumn(0);
38+
39+
$expectedValue = (int)$pdo2
40+
->query('show log_min_duration_statement;')
41+
->fetchColumn(0);
42+
43+
echo "pid1 is equals to pid2: " . (($pid1 === $pid2) ? 'yes' : 'no') . "\n";
44+
echo "defaultValue: {$defaultValue}\n";
45+
echo "setValue: {$setValue}\n";
46+
echo "expectedValue: {$expectedValue}\n";
47+
echo "expected value should be reset to default: " . (($expectedValue === $defaultValue) ? 'success' : 'failure') . "\n";
48+
49+
?>
50+
--EXPECTF--
51+
pid1 is equals to pid2: yes
52+
defaultValue: %i
53+
setValue: %d
54+
expectedValue: %i
55+
expected value should be reset to default: success
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
--TEST--
2+
Persistent connections: session state reset when performing disconnect-equivalent processing (advisory lock case)
3+
--EXTENSIONS--
4+
pdo_pgsql
5+
--SKIPIF--
6+
<?php
7+
require __DIR__ . '/config.inc';
8+
require __DIR__ . '/../../../ext/pdo/tests/pdo_test.inc';
9+
PDOTest::skip();
10+
?>
11+
--FILE--
12+
<?php
13+
putenv('PDOTEST_ATTR='.serialize([PDO::ATTR_PERSISTENT => true]));
14+
15+
require __DIR__ . '/../../../ext/pdo/tests/pdo_test.inc';
16+
17+
$pdo1 = PDOTest::test_factory(__DIR__ . '/common.phpt');
18+
19+
$pid1 = (int)$pdo1
20+
->query('select pg_backend_pid()::int;')
21+
->fetchColumn(0);
22+
23+
$lockResult1 = (bool)$pdo1
24+
->query('select pg_try_advisory_lock(42)::int;')
25+
->fetchColumn(0);
26+
27+
$pdo1 = null;
28+
29+
$dsn = getenv('PDO_PGSQL_TEST_DSN');
30+
$dsn .= ';';
31+
putenv('PDO_PGSQL_TEST_DSN='.$dsn);
32+
33+
$pdo2 = PDOTest::test_factory(__DIR__ . '/common.phpt');
34+
35+
$pid2 = (int)$pdo2
36+
->query('select pg_backend_pid()::int;')
37+
->fetchColumn(0);
38+
39+
$lockResult2 = (bool)$pdo2
40+
->query('select pg_try_advisory_lock(42)::int;')
41+
->fetchColumn(0);
42+
43+
echo "pid1 is NOT equals to pid2: " . (($pid1 !== $pid2) ? 'yes' : 'no') . "\n";
44+
echo "lock1: " . ($lockResult1 ? 'success' : 'failure') . "\n";
45+
echo "lock2: " . ($lockResult2 ? 'success' : 'failure') . "\n";
46+
47+
?>
48+
--EXPECT--
49+
pid1 is NOT equals to pid2: yes
50+
lock1: success
51+
lock2: success
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
--TEST--
2+
Persistent connections: session state reset after backend termination (interrupted case)
3+
--EXTENSIONS--
4+
pdo_pgsql
5+
--SKIPIF--
6+
<?php
7+
require __DIR__ . '/config.inc';
8+
require __DIR__ . '/../../../ext/pdo/tests/pdo_test.inc';
9+
PDOTest::skip();
10+
?>
11+
--FILE--
12+
<?php
13+
putenv('PDOTEST_ATTR='.serialize([PDO::ATTR_PERSISTENT => true]));
14+
15+
require __DIR__ . '/../../../ext/pdo/tests/pdo_test.inc';
16+
17+
$pdo1 = PDOTest::test_factory(__DIR__ . '/common.phpt');
18+
19+
$pid1 = (int)$pdo1
20+
->query('select pg_backend_pid()::int;')
21+
->fetchColumn(0);
22+
23+
$pid1 = (int)$pdo1
24+
->query('select pg_backend_pid()::int;')
25+
->fetchColumn(0);
26+
27+
$dsn = getenv('PDO_PGSQL_TEST_DSN');
28+
$dsn .= ';';
29+
putenv('PDO_PGSQL_TEST_DSN='.$dsn);
30+
31+
$pdo2 = PDOTest::test_factory(__DIR__ . '/common.phpt');
32+
33+
$pid2 = (int)$pdo2
34+
->query('select pg_backend_pid()::int;')
35+
->fetchColumn(0);
36+
37+
$terminateResult = (bool)$pdo2
38+
->query("select pg_terminate_backend({$pid1})::int")
39+
->fetchColumn(0);
40+
41+
// Disconnect after being terminated by another connection
42+
$pdo1 = null;
43+
44+
echo "pid1 is NOT equals to pid2: " . (($pid1 !== $pid2) ? 'yes' : 'no') . "\n";
45+
echo 'pid of pdo1: ' . $pid1 . "\n";
46+
echo 'terminate result of pdo1 by pdo2: ' . ($terminateResult ? 'success' : 'failure') . "\n";
47+
48+
?>
49+
--EXPECTF--
50+
pid1 is NOT equals to pid2: yes
51+
pid of pdo1: %d
52+
terminate result of pdo1 by pdo2: success

0 commit comments

Comments
 (0)