-
Notifications
You must be signed in to change notification settings - Fork 8k
pdo_pgsql: Reset persistent session state on disconnect-equivalent processing #20572
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| --TEST-- | ||
| Persistent connections: session state reset when performing disconnect-equivalent processing (general case) | ||
| --EXTENSIONS-- | ||
| pdo_pgsql | ||
| --SKIPIF-- | ||
| <?php | ||
| require __DIR__ . '/config.inc'; | ||
| require __DIR__ . '/../../../ext/pdo/tests/pdo_test.inc'; | ||
| PDOTest::skip(); | ||
| ?> | ||
| --FILE-- | ||
| <?php | ||
| putenv('PDOTEST_ATTR='.serialize([PDO::ATTR_PERSISTENT => true])); | ||
|
|
||
| require __DIR__ . '/../../../ext/pdo/tests/pdo_test.inc'; | ||
|
|
||
| $pdo1 = PDOTest::test_factory(__DIR__ . '/common.phpt'); | ||
|
|
||
| $pid1 = (int)$pdo1 | ||
| ->query('select pg_backend_pid()::int;') | ||
| ->fetchColumn(0); | ||
|
|
||
| $defaultValue = (int)$pdo1 | ||
| ->query('show log_min_duration_statement;') | ||
| ->fetchColumn(0); | ||
|
|
||
| $setValue = $defaultValue + 1; | ||
|
|
||
| $pdo1->exec("set log_min_duration_statement = {$setValue};"); | ||
|
|
||
| $pdo1 = null; | ||
|
|
||
| $pdo2 = PDOTest::test_factory(__DIR__ . '/common.phpt'); | ||
|
|
||
| $pid2 = (int)$pdo2 | ||
| ->query('select pg_backend_pid()::int;') | ||
| ->fetchColumn(0); | ||
|
|
||
| assert($pid1 === $pid2); | ||
|
|
||
| $expectedValue = (int)$pdo2 | ||
| ->query('show log_min_duration_statement;') | ||
| ->fetchColumn(0); | ||
|
|
||
| echo "defaultValue: {$defaultValue}\n"; | ||
| echo "setValue: {$setValue}\n"; | ||
| echo "expectedValue: {$expectedValue}\n"; | ||
| echo "expected value should be reset to default: " . (($expectedValue === $defaultValue) ? 'success' : 'failure') . "\n"; | ||
|
|
||
| ?> | ||
| --EXPECTF-- | ||
| defaultValue: %i | ||
| setValue: %d | ||
| expectedValue: %i | ||
| expected value should be reset to default: success |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| --TEST-- | ||
| Persistent connections: session state reset when performing disconnect-equivalent processing (advisory lock case) | ||
| --EXTENSIONS-- | ||
| pdo_pgsql | ||
| --SKIPIF-- | ||
| <?php | ||
| require __DIR__ . '/config.inc'; | ||
| require __DIR__ . '/../../../ext/pdo/tests/pdo_test.inc'; | ||
| PDOTest::skip(); | ||
| ?> | ||
| --FILE-- | ||
| <?php | ||
| putenv('PDOTEST_ATTR='.serialize([PDO::ATTR_PERSISTENT => true])); | ||
|
|
||
| require __DIR__ . '/../../../ext/pdo/tests/pdo_test.inc'; | ||
|
|
||
| $pdo1 = PDOTest::test_factory(__DIR__ . '/common.phpt'); | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: would it be possible to store
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've added it to all the tests (now 3) related to this issue. You were right. I was confused myself by the 3 tests, some of which keep the pid the same and some of which intentionally change it :'D |
||
| $pid1 = (int)$pdo1 | ||
| ->query('select pg_backend_pid()::int;') | ||
| ->fetchColumn(0); | ||
|
|
||
| $lockResult1 = (bool)$pdo1 | ||
| ->query('select pg_try_advisory_lock(42)::int;') | ||
| ->fetchColumn(0); | ||
|
|
||
| $pdo1 = null; | ||
|
|
||
| $dsn = getenv('PDO_PGSQL_TEST_DSN'); | ||
| $dsn .= ';'; | ||
| putenv('PDO_PGSQL_TEST_DSN='.$dsn); | ||
|
|
||
| $pdo2 = PDOTest::test_factory(__DIR__ . '/common.phpt'); | ||
|
|
||
| $pid2 = (int)$pdo2 | ||
| ->query('select pg_backend_pid()::int;') | ||
| ->fetchColumn(0); | ||
|
|
||
| assert($pid1 !== $pid2); | ||
|
|
||
| $lockResult2 = (bool)$pdo2 | ||
| ->query('select pg_try_advisory_lock(42)::int;') | ||
| ->fetchColumn(0); | ||
|
|
||
| echo "lock1: " . ($lockResult1 ? 'success' : 'failure') . "\n"; | ||
| echo "lock2: " . ($lockResult2 ? 'success' : 'failure') . "\n"; | ||
|
|
||
| ?> | ||
| --EXPECT-- | ||
| lock1: success | ||
| lock2: success | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| --TEST-- | ||
| Persistent connections: session state reset after backend termination (interrupted case) | ||
| --EXTENSIONS-- | ||
| pdo_pgsql | ||
| --SKIPIF-- | ||
| <?php | ||
| require __DIR__ . '/config.inc'; | ||
| require __DIR__ . '/../../../ext/pdo/tests/pdo_test.inc'; | ||
| PDOTest::skip(); | ||
| ?> | ||
| --FILE-- | ||
| <?php | ||
| putenv('PDOTEST_ATTR='.serialize([PDO::ATTR_PERSISTENT => true])); | ||
|
|
||
| require __DIR__ . '/../../../ext/pdo/tests/pdo_test.inc'; | ||
|
|
||
| $pdo1 = PDOTest::test_factory(__DIR__ . '/common.phpt'); | ||
|
|
||
| $pid1 = (int)$pdo1 | ||
| ->query('select pg_backend_pid()::int;') | ||
| ->fetchColumn(0); | ||
|
|
||
| $pid1 = (int)$pdo1 | ||
| ->query('select pg_backend_pid()::int;') | ||
| ->fetchColumn(0); | ||
|
|
||
| $dsn = getenv('PDO_PGSQL_TEST_DSN'); | ||
| $dsn .= ';'; | ||
| putenv('PDO_PGSQL_TEST_DSN='.$dsn); | ||
|
|
||
| $pdo2 = PDOTest::test_factory(__DIR__ . '/common.phpt'); | ||
|
|
||
| $pid2 = (int)$pdo2 | ||
| ->query('select pg_backend_pid()::int;') | ||
| ->fetchColumn(0); | ||
|
|
||
| assert($pid1 !== $pid2); | ||
|
|
||
| $terminateResult = (bool)$pdo2 | ||
| ->query("select pg_terminate_backend({$pid1})::int") | ||
| ->fetchColumn(0); | ||
|
|
||
| // Disconnect after being terminated by another connection | ||
| $pdo1 = null; | ||
|
|
||
| echo 'pid of pdo1: ' . $pid1 . "\n"; | ||
| echo 'terminate result of pdo1 by pdo2: ' . ($terminateResult ? 'success' : 'failure') . "\n"; | ||
|
|
||
| ?> | ||
| --EXPECTF-- | ||
| pid of pdo1: %d | ||
| terminate result of pdo1 by pdo2: success |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might be nice to have a test with a transaction being interrupted, then forcing the shutdown wdyt ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a test case that "attempts to perform disconnection-equivalent processing after being disconnected from the outside." This is because session-level parameters and advisory locks have no concept of transactions.
For normal transactions, the previous implementation appears to correctly detect and initialize transactions, even if the BEGIN statement is issued independently with
exec()without using beginTransaction():php-src/ext/pdo_pgsql/pgsql_driver.c
Line 583 in 1ee8dfd
php-src/ext/pdo/pdo_dbh.c
Lines 1588 to 1591 in 1ee8dfd