For no obvious reason, isolationtester has always insisted that
session and step names be written with double quotes. This is
fairly tedious and does little for test readability, especially
since the names that people actually choose almost always look
like normal identifiers. Hence, let's tweak the lexer to allow
SQL-like identifiers not only double-quoted strings.
(They're SQL-like, not exactly SQL, because I didn't add any
case-folding logic. Also there's no provision for U&"..." names,
not that anyone's likely to care.)
There is one incompatibility introduced by this change: if you write
"foo""bar" with no space, that used to be taken as two identifiers,
but now it's just one identifier with an embedded quote mark.
I converted all the src/test/isolation/ specfiles to remove
unnecessary double quotes, but stopped there because my
eyes were glazing over already.
Like 741d7f104, back-patch to all supported branches, so that this
isn't a stumbling block for back-patching isolation test changes.
Discussion: https://postgr.es/m/759113.1623861959@sss.pgh.pa.us
step "rx1" { SELECT count(*) FROM room_reservation WHERE room_id = '101' AND start_time < TIMESTAMP WITH TIME ZONE '2010-04-01 14:00' AND end_time > TIMESTAMP WITH TIME ZONE '2010-04-01 13:00'; }
step "wy1" { INSERT INTO room_reservation VALUES ('101', TIMESTAMP WITH TIME ZONE '2010-04-01 13:00', TIMESTAMP WITH TIME ZONE '2010-04-01 14:00', 'Carol'); }
step "c1" { COMMIT; }
step rx1 { SELECT count(*) FROM room_reservation WHERE room_id = '101' AND start_time < TIMESTAMP WITH TIME ZONE '2010-04-01 14:00' AND end_time > TIMESTAMP WITH TIME ZONE '2010-04-01 13:00'; }
step wy1 { INSERT INTO room_reservation VALUES ('101', TIMESTAMP WITH TIME ZONE '2010-04-01 13:00', TIMESTAMP WITH TIME ZONE '2010-04-01 14:00', 'Carol'); }
step c1 { COMMIT; }
session "s2"
session s2
setup { BEGIN ISOLATION LEVEL SERIALIZABLE; }
step "ry2" { SELECT count(*) FROM room_reservation WHERE room_id = '101' AND start_time < TIMESTAMP WITH TIME ZONE '2010-04-01 14:30' AND end_time > TIMESTAMP WITH TIME ZONE '2010-04-01 13:30'; }
step "wx2" { UPDATE room_reservation SET start_time = TIMESTAMP WITH TIME ZONE '2010-04-01 13:30', end_time = TIMESTAMP WITH TIME ZONE '2010-04-01 14:30' WHERE room_id = '101' AND start_time = TIMESTAMP WITH TIME ZONE '2010-04-01 10:00'; }
step "c2" { COMMIT; }
step ry2 { SELECT count(*) FROM room_reservation WHERE room_id = '101' AND start_time < TIMESTAMP WITH TIME ZONE '2010-04-01 14:30' AND end_time > TIMESTAMP WITH TIME ZONE '2010-04-01 13:30'; }
step wx2 { UPDATE room_reservation SET start_time = TIMESTAMP WITH TIME ZONE '2010-04-01 13:30', end_time = TIMESTAMP WITH TIME ZONE '2010-04-01 14:30' WHERE room_id = '101' AND start_time = TIMESTAMP WITH TIME ZONE '2010-04-01 10:00'; }
step "chkiso" { SELECT (setting in ('read committed','read uncommitted')) AS is_read_committed FROM pg_settings WHERE name = 'default_transaction_isolation'; }
step "prepi" { PREPARE getrow_idx AS SELECT * FROM test_dc WHERE data=34 ORDER BY id,data; }
step "preps" { PREPARE getrow_seq AS SELECT * FROM test_dc WHERE data::text=34::text ORDER BY id,data; }
step chkiso { SELECT (setting in ('read committed','read uncommitted')) AS is_read_committed FROM pg_settings WHERE name = 'default_transaction_isolation'; }
step prepi { PREPARE getrow_idx AS SELECT * FROM test_dc WHERE data=34 ORDER BY id,data; }
step preps { PREPARE getrow_seq AS SELECT * FROM test_dc WHERE data::text=34::text ORDER BY id,data; }
# (updated|deleted). The *fail versions of the tests additionally
# perform an update, via a function, in a different command, to test
# behaviour relating to that.
step "updwcte" { WITH doup AS (UPDATE accounts SET balance = balance + 1100 WHERE accountid = 'checking' RETURNING *) UPDATE accounts a SET balance = doup.balance + 100 FROM doup RETURNING *; }
step "updwctefail" { WITH doup AS (UPDATE accounts SET balance = balance + 1100 WHERE accountid = 'checking' RETURNING *, update_checking(999)) UPDATE accounts a SET balance = doup.balance + 100 FROM doup RETURNING *; }
step "delwcte" { WITH doup AS (UPDATE accounts SET balance = balance + 1100 WHERE accountid = 'checking' RETURNING *) DELETE FROM accounts a USING doup RETURNING *; }
step "delwctefail" { WITH doup AS (UPDATE accounts SET balance = balance + 1100 WHERE accountid = 'checking' RETURNING *, update_checking(999)) DELETE FROM accounts a USING doup RETURNING *; }
step updwcte { WITH doup AS (UPDATE accounts SET balance = balance + 1100 WHERE accountid = 'checking' RETURNING *) UPDATE accounts a SET balance = doup.balance + 100 FROM doup RETURNING *; }
step updwctefail { WITH doup AS (UPDATE accounts SET balance = balance + 1100 WHERE accountid = 'checking' RETURNING *, update_checking(999)) UPDATE accounts a SET balance = doup.balance + 100 FROM doup RETURNING *; }
step delwcte { WITH doup AS (UPDATE accounts SET balance = balance + 1100 WHERE accountid = 'checking' RETURNING *) DELETE FROM accounts a USING doup RETURNING *; }
step delwctefail { WITH doup AS (UPDATE accounts SET balance = balance + 1100 WHERE accountid = 'checking' RETURNING *, update_checking(999)) DELETE FROM accounts a USING doup RETURNING *; }
# Check that nested EPQ works correctly
step "wnested2" {
step wnested2 {
UPDATE accounts SET balance = balance - 1200
WHERE noisy_oper('upid', accountid, '=', 'checking')
AND noisy_oper('up', balance, '>', 200.0)
@ -265,17 +265,17 @@ step "wnested2" {
);
}
step "c2" { COMMIT; }
step "r2" { ROLLBACK; }
step c2 { COMMIT; }
step r2 { ROLLBACK; }
session "s3"
session s3
setup { BEGIN ISOLATION LEVEL READ COMMITTED; }
step "read" { SELECT * FROM accounts ORDER BY accountid; }
step "read_ext" { SELECT * FROM accounts_ext ORDER BY accountid; }
step "read_a" { SELECT * FROM table_a ORDER BY id; }
step read { SELECT * FROM accounts ORDER BY accountid; }
step read_ext { SELECT * FROM accounts_ext ORDER BY accountid; }
step read_a { SELECT * FROM table_a ORDER BY id; }
# this test exercises EvalPlanQual with a CTE, cf bug #14328
step "readwcte" {
step readwcte {
WITH
cte1 AS (
SELECT id FROM table_b WHERE value = 'tableBValue'
@ -289,7 +289,7 @@ step "readwcte" {
}
# this test exercises a different CTE misbehavior, cf bug #14870
step "multireadwcte" {
step multireadwcte {
WITH updated AS (
UPDATE table_a SET value = 'tableAValue3' WHERE id = 1 RETURNING id
)
@ -299,61 +299,61 @@ step "multireadwcte" {
teardown { COMMIT; }
# test that normal update follows update chains, and reverifies quals
permutation "wx1""wx2""c1""c2""read"
permutation "wy1""wy2""c1""c2""read"
permutation "wx1""wx2""r1""c2""read"
permutation "wy1""wy2""r1""c2""read"
permutation wx1 wx2 c1 c2 read
permutation wy1 wy2 c1 c2 read
permutation wx1 wx2 r1 c2 read
permutation wy1 wy2 r1 c2 read
# test that deletes follow chains, and if necessary reverifies quals
step "s1_upsert" { INSERT INTO upserttest(key, data) VALUES('k1', 'inserted s1') ON CONFLICT (blurt_and_lock_123(key)) DO UPDATE SET data = upserttest.data || ' with conflict update s1'; }
step "s1_insert_toast" { INSERT INTO upserttest VALUES('k2', ctoast_large_val()) ON CONFLICT DO NOTHING; }
step "s1_commit" { COMMIT; }
step "s1_noop" { }
step s1_begin { BEGIN; }
step s1_create_non_unique_index { CREATE INDEX upserttest_key_idx ON upserttest((blurt_and_lock_4(key))); }
step s1_upsert { INSERT INTO upserttest(key, data) VALUES('k1', 'inserted s1') ON CONFLICT (blurt_and_lock_123(key)) DO UPDATE SET data = upserttest.data || ' with conflict update s1'; }
step s1_insert_toast { INSERT INTO upserttest VALUES('k2', ctoast_large_val()) ON CONFLICT DO NOTHING; }
step s1_commit { COMMIT; }
step s1_noop { }
session "s2"
session s2
setup
{
SET default_transaction_isolation = 'read committed';
SET spec.session = 2;
SET application_name = 'isolation/insert-conflict-specconflict-s2';
}
step "s2_begin" { BEGIN; }
step "s2_upsert" { INSERT INTO upserttest(key, data) VALUES('k1', 'inserted s2') ON CONFLICT (blurt_and_lock_123(key)) DO UPDATE SET data = upserttest.data || ' with conflict update s2'; }
step "s2_insert_toast" { INSERT INTO upserttest VALUES('k2', ctoast_large_val()) ON CONFLICT DO NOTHING; }
step "s2_commit" { COMMIT; }
step "s2_noop" { }
step s2_begin { BEGIN; }
step s2_upsert { INSERT INTO upserttest(key, data) VALUES('k1', 'inserted s2') ON CONFLICT (blurt_and_lock_123(key)) DO UPDATE SET data = upserttest.data || ' with conflict update s2'; }
step s2_insert_toast { INSERT INTO upserttest VALUES('k2', ctoast_large_val()) ON CONFLICT DO NOTHING; }
step s2_commit { COMMIT; }
step s2_noop { }
# Test that speculative locks are correctly acquired and released, s2
# inserts, s1 updates.
@ -105,23 +105,23 @@ permutation
# blurt_and_lock_123 function acquires advisory locks that allow us to
# continue after a) the optimistic conflict probe b) after the
# insertion of the speculative tuple.
"controller_locks"
"controller_show"
"s1_upsert""s2_upsert"
"controller_show"
controller_locks
controller_show
s1_upsert s2_upsert
controller_show
# Switch both sessions to wait on the other lock next time (the speculative insertion)
"controller_unlock_1_1""controller_unlock_2_1"
controller_unlock_1_1 controller_unlock_2_1
# Allow both sessions to continue
"controller_unlock_1_3""controller_unlock_2_3"
"controller_show"
controller_unlock_1_3 controller_unlock_2_3
controller_show
# Allow the second session to finish insertion
"controller_unlock_2_2"
controller_unlock_2_2
# This should now show a successful insertion
"controller_show"
controller_show
# Allow the first session to finish insertion
"controller_unlock_1_2"
controller_unlock_1_2
# This should now show a successful UPSERT
"controller_show"
controller_show
# Test that speculative locks are correctly acquired and released, s1
# inserts, s2 updates.
@ -130,23 +130,23 @@ permutation
# blurt_and_lock_123 function acquires advisory locks that allow us to
# continue after a) the optimistic conflict probe b) after the
# insertion of the speculative tuple.
"controller_locks"
"controller_show"
"s1_upsert""s2_upsert"
"controller_show"
controller_locks
controller_show
s1_upsert s2_upsert
controller_show
# Switch both sessions to wait on the other lock next time (the speculative insertion)
"controller_unlock_1_1""controller_unlock_2_1"
controller_unlock_1_1 controller_unlock_2_1
# Allow both sessions to continue
"controller_unlock_1_3""controller_unlock_2_3"
"controller_show"
controller_unlock_1_3 controller_unlock_2_3
controller_show
# Allow the first session to finish insertion
"controller_unlock_1_2"
controller_unlock_1_2
# This should now show a successful insertion
"controller_show"
controller_show
# Allow the second session to finish insertion
"controller_unlock_2_2"
controller_unlock_2_2
# This should now show a successful UPSERT
"controller_show"
controller_show
# Test that speculatively inserted toast rows do not cause conflicts.
# s1 inserts successfully, s2 does not.
@ -155,23 +155,23 @@ permutation
# blurt_and_lock_123 function acquires advisory locks that allow us to
# continue after a) the optimistic conflict probe b) after the
# insertion of the speculative tuple.
"controller_locks"
"controller_show"
"s1_insert_toast""s2_insert_toast"
"controller_show"
controller_locks
controller_show
s1_insert_toast s2_insert_toast
controller_show
# Switch both sessions to wait on the other lock next time (the speculative insertion)
"controller_unlock_1_1""controller_unlock_2_1"
controller_unlock_1_1 controller_unlock_2_1
# Allow both sessions to continue
"controller_unlock_1_3""controller_unlock_2_3"
"controller_show"
controller_unlock_1_3 controller_unlock_2_3
controller_show
# Allow the first session to finish insertion
"controller_unlock_1_2"
controller_unlock_1_2
# This should now show that 1 additional tuple was inserted successfully
"controller_show_count"
controller_show_count
# Allow the second session to finish insertion and kill the speculatively inserted tuple
"controller_unlock_2_2"
controller_unlock_2_2
# This should show the same number of tuples as before s2 inserted
"controller_show_count"
controller_show_count
# Test that speculative locks are correctly acquired and released, s2
# inserts, s1 updates. With the added complication that transactions
@ -181,28 +181,28 @@ permutation
# blurt_and_lock_123 function acquires advisory locks that allow us to
# continue after a) the optimistic conflict probe b) after the
# insertion of the speculative tuple.
"controller_locks"
"controller_show"
"s1_begin""s2_begin"
"s1_upsert""s2_upsert"
"controller_show"
controller_locks
controller_show
s1_begin s2_begin
s1_upsert s2_upsert
controller_show
# Switch both sessions to wait on the other lock next time (the speculative insertion)
"controller_unlock_1_1""controller_unlock_2_1"
controller_unlock_1_1 controller_unlock_2_1
# Allow both sessions to continue
"controller_unlock_1_3""controller_unlock_2_3"
"controller_show"
controller_unlock_1_3 controller_unlock_2_3
controller_show
# Allow the first session to finish insertion
"controller_unlock_1_2"
controller_unlock_1_2
# But the change isn't visible yet, nor should the second session continue
"controller_show"
controller_show
# Allow the second session to finish insertion, but it's blocked
"controller_unlock_2_2"
"controller_show"
controller_unlock_2_2
controller_show
# But committing should unblock
"s1_commit"
"controller_show"
"s2_commit"
"controller_show"
s1_commit
controller_show
s2_commit
controller_show
# Test that speculative wait is performed if a session sees a speculatively
# inserted tuple. A speculatively inserted tuple is one which has been inserted
@ -218,45 +218,45 @@ permutation
# create the second index here to avoid affecting the other
# permutations.
"s1_create_non_unique_index"
s1_create_non_unique_index
# confirm that the insertion into the unique index will happen first
"s1_confirm_index_order"
"controller_locks"
"controller_show"
"s2_begin"
s1_confirm_index_order
controller_locks
controller_show
s2_begin
# Both sessions wait on advisory locks
# (but don't show s2_upsert as complete till we've seen all of s1's notices)
"s1_upsert""s2_upsert" ("s1_upsert" notices 10)
"controller_show"
s1_upsert s2_upsert (s1_upsert notices 10)
controller_show
# Switch both sessions to wait on the other lock next time (the speculative insertion)
"controller_unlock_1_1""controller_unlock_2_1"
controller_unlock_1_1 controller_unlock_2_1
# Allow both sessions to do the optimistic conflict probe and do the
# speculative insertion into the table
# They will then be waiting on another advisory lock when they attempt to
# update the index
"controller_unlock_1_3""controller_unlock_2_3"
"controller_show"
controller_unlock_1_3 controller_unlock_2_3
controller_show
# take lock to block second session after inserting in unique index but
# before completing the speculative insert
"controller_lock_2_4"
controller_lock_2_4
# Allow the second session to move forward
"controller_unlock_2_2"
controller_unlock_2_2
# This should still not show a successful insertion
"controller_show"
controller_show
# Allow the first session to continue, it should perform speculative wait
"controller_unlock_1_2"
controller_unlock_1_2
# Should report s1 is waiting on speculative lock
"controller_print_speculative_locks"
controller_print_speculative_locks
# Allow s2 to insert into the non-unique index and complete. s1 will
# no longer wait on speculative lock, but proceed to wait on the
# transaction to finish. The no-op step is needed to ensure that
# we don't advance to the reporting step until s2_upsert has completed.
"controller_unlock_2_4""s2_noop"
controller_unlock_2_4 s2_noop
# Should report that s1 is now waiting for s2 to commit
"controller_print_speculative_locks"
controller_print_speculative_locks
# Once s2 commits, s1 is finally free to continue to update
step "rx1" { SELECT count(*) FROM statute WHERE statute_cite = '123.45(1)a' AND eff_date <= DATE '2009-05-15' AND (exp_date IS NULL OR exp_date > DATE '2009-05-15'); }
step "wy1" { INSERT INTO offense VALUES (1, '123.45(1)a', DATE '2009-05-15'); }
step "c1" { COMMIT; }
step rx1 { SELECT count(*) FROM statute WHERE statute_cite = '123.45(1)a' AND eff_date <= DATE '2009-05-15' AND (exp_date IS NULL OR exp_date > DATE '2009-05-15'); }
step wy1 { INSERT INTO offense VALUES (1, '123.45(1)a', DATE '2009-05-15'); }
step c1 { COMMIT; }
session "s2"
session s2
setup { BEGIN ISOLATION LEVEL SERIALIZABLE; }
step "ry2" { SELECT count(*) FROM offense WHERE statute_cite = '123.45(1)a' AND offense_date >= DATE '2008-01-01'; }
step "wx2" { DELETE FROM statute WHERE statute_cite = '123.45(1)a' AND eff_date = DATE '2008-01-01'; }
step "c2" { COMMIT; }
step ry2 { SELECT count(*) FROM offense WHERE statute_cite = '123.45(1)a' AND offense_date >= DATE '2008-01-01'; }
step wx2 { DELETE FROM statute WHERE statute_cite = '123.45(1)a' AND eff_date = DATE '2008-01-01'; }