step "s1_init" { SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding'); }
step "s1_begin" { BEGIN; }
step "s1_insert_tbl1" { INSERT INTO tbl1 (val1, val2) VALUES (1, 1); }
-step "s1_insert_tbl1_3col" { INSERT INTO tbl1 (val1, val2, val3) VALUES (1, 1, 1); }
step "s1_insert_tbl2" { INSERT INTO tbl2 (val1, val2) VALUES (1, 1); }
step "s1_insert_tbl2_3col" { INSERT INTO tbl2 (val1, val2, val3) VALUES (1, 1, 1); }
step "s1_commit" { COMMIT; }
step "s2_alter_tbl1_float" { ALTER TABLE tbl1 ALTER COLUMN val2 TYPE float; }
step "s2_alter_tbl1_char" { ALTER TABLE tbl1 ALTER COLUMN val2 TYPE character varying; }
-step "s2_alter_tbl1_text" { ALTER TABLE tbl1 ALTER COLUMN val2 TYPE text; }
step "s2_alter_tbl1_boolean" { ALTER TABLE tbl1 ALTER COLUMN val2 TYPE boolean; }
-step "s2_alter_tbl1_add_int" { ALTER TABLE tbl1 ADD COLUMN val3 INTEGER; }
-step "s2_alter_tbl1_add_float" { ALTER TABLE tbl1 ADD COLUMN val3 FLOAT; }
-step "s2_alter_tbl1_add_char" { ALTER TABLE tbl1 ADD COLUMN val3 character varying; }
-step "s2_alter_tbl1_add_boolean" { ALTER TABLE tbl1 ADD COLUMN val3 BOOLEAN; }
-step "s2_alter_tbl1_add_text" { ALTER TABLE tbl1 ADD COLUMN val3 TEXT; }
-
step "s2_alter_tbl2_float" { ALTER TABLE tbl2 ALTER COLUMN val2 TYPE float; }
step "s2_alter_tbl2_char" { ALTER TABLE tbl2 ALTER COLUMN val2 TYPE character varying; }
step "s2_alter_tbl2_text" { ALTER TABLE tbl2 ALTER COLUMN val2 TYPE text; }
step "s2_alter_tbl2_add_int" { ALTER TABLE tbl2 ADD COLUMN val3 INTEGER; }
step "s2_alter_tbl2_add_float" { ALTER TABLE tbl2 ADD COLUMN val3 FLOAT; }
step "s2_alter_tbl2_add_char" { ALTER TABLE tbl2 ADD COLUMN val3 character varying; }
-step "s2_alter_tbl2_add_boolean" { ALTER TABLE tbl2 ADD COLUMN val3 BOOLEAN; }
step "s2_alter_tbl2_add_text" { ALTER TABLE tbl2 ADD COLUMN val3 TEXT; }
step "s2_alter_tbl2_drop_3rd_col" { ALTER TABLE tbl2 DROP COLUMN val3; }
step "s2_alter_tbl2_3rd_char" { ALTER TABLE tbl2 ALTER COLUMN val3 TYPE character varying; }
step "s0_insert" { INSERT INTO harvest VALUES (1, 2, 3); }
step "s0_end_sub0" { RELEASE SAVEPOINT s0; }
step "s0_end_sub1" { RELEASE SAVEPOINT s1; }
-step "s0_insert2" { INSERT INTO harvest VALUES (1, 2, 3, 4); }
step "s0_commit" { COMMIT; }
step "s0_get_changes" { SELECT data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); }
-Parsed test spec with 4 sessions
+Parsed test spec with 3 sessions
starting permutation: s1_trig_rep_b_u s1_trig_rep_a_u s1_ins_a s1_ins_b s1_b_rc s2_b_rc s1_upd_a_data s1_c s2_upd_a_data s2_c s0_rep
step s1_trig_rep_b_u: CREATE TRIGGER rep_b_u BEFORE UPDATE ON trigtest FOR EACH ROW EXECUTE PROCEDURE trig_report();
puts("isolationtester (PostgreSQL) " PG_VERSION);
exit(0);
default:
- fprintf(stderr, "Usage: isolationtester [-n] [CONNINFO]\n");
+ fprintf(stderr, "Usage: isolationtester [CONNINFO]\n");
return EXIT_FAILURE;
}
}
static void
run_testspec(TestSpec *testspec)
{
+ int i;
+
if (testspec->permutations)
run_named_permutations(testspec);
else
run_all_permutations(testspec);
+
+ /*
+ * Verify that all steps have been used, complaining about anything
+ * defined but not used.
+ */
+ for (i = 0; i < testspec->nallsteps; i++)
+ {
+ if (!testspec->allsteps[i]->used)
+ fprintf(stderr, "unused step name: %s\n",
+ testspec->allsteps[i]->name);
+ }
}
/*
printf("\nstarting permutation:");
for (i = 0; i < nsteps; i++)
+ {
+ /* Track the permutation as in-use */
+ steps[i]->used = true;
printf(" %s", steps[i]->name);
+ }
printf("\n");
/* Perform setup */
struct Step
{
int session;
+ bool used;
char *name;
char *sql;
char *errormsg;
$$ = malloc(sizeof(Step));
$$->name = $2;
$$->sql = $3;
+ $$->used = false;
$$->errormsg = NULL;
}
;
step "s2_b_rc" { BEGIN ISOLATION LEVEL READ COMMITTED; SELECT 1; }
step "s2_b_rr" { BEGIN ISOLATION LEVEL REPEATABLE READ; SELECT 1; }
step "s2_c" { COMMIT; }
-step "s2_r" { ROLLBACK; }
+#step "s2_r" { ROLLBACK; }
step "s2_ins_a" { INSERT INTO trigtest VALUES ('key-a', 'val-a-s2') RETURNING *; }
step "s2_del_a" {
DELETE FROM trigtest
RETURNING *;
}
-session "s3"
+#session "s3"
#setup { }
-step "s3_b_rc" { BEGIN ISOLATION LEVEL READ COMMITTED; SELECT 1; }
-step "s3_c" { COMMIT; }
-step "s3_r" { ROLLBACK; }
-step "s3_del_a" {
- DELETE FROM trigtest
- WHERE
- noisy_oper('upd', key, '=', 'key-a') AND
- noisy_oper('upk', data, '<>', 'mismatch')
- RETURNING *
-}
-step "s3_upd_a_data" {
- UPDATE trigtest SET data = data || '-ups3'
- WHERE
- noisy_oper('upd', key, '=', 'key-a') AND
- noisy_oper('upk', data, '<>', 'mismatch')
- RETURNING *;
-}
+#step "s3_b_rc" { BEGIN ISOLATION LEVEL READ COMMITTED; SELECT 1; }
+#step "s3_c" { COMMIT; }
+#step "s3_r" { ROLLBACK; }
+#step "s3_del_a" {
+# DELETE FROM trigtest
+# WHERE
+# noisy_oper('upd', key, '=', 'key-a') AND
+# noisy_oper('upk', data, '<>', 'mismatch')
+# RETURNING *
+#}
+#step "s3_upd_a_data" {
+# UPDATE trigtest SET data = data || '-ups3'
+# WHERE
+# noisy_oper('upd', key, '=', 'key-a') AND
+# noisy_oper('upk', data, '<>', 'mismatch')
+# RETURNING *;
+#}
### base case verifying that triggers see performed modifications
# s1 updates, s1 commits, s2 updates
step "s1_begin" { BEGIN; }
step "s1_update" { UPDATE tab_freeze SET x = x + 1 WHERE id = 3; }
step "s1_commit" { COMMIT; }
-step "s1_vacuum" { VACUUM FREEZE tab_freeze; }
step "s1_selectone" {
BEGIN;
SET LOCAL enable_seqscan = false;
COMMIT;
}
step "s1_selectall" { SELECT * FROM tab_freeze ORDER BY name, id; }
-step "s1_reindex" { REINDEX TABLE tab_freeze; }
session "s2"
step "s2_begin" { BEGIN; }
step "s3_begin" { BEGIN; }
step "s3_key_share" { SELECT id FROM tab_freeze WHERE id = 3 FOR KEY SHARE; }
step "s3_commit" { COMMIT; }
-step "s3_vacuum" { VACUUM FREEZE tab_freeze; }
# This permutation verfies that a previous bug
step "donothing2" { INSERT INTO ints(key, val) VALUES(1, 'donothing2') ON CONFLICT DO NOTHING; }
step "select2" { SELECT * FROM ints; }
step "c2" { COMMIT; }
-step "a2" { ABORT; }
# Regular case where one session block-waits on another to determine if it
# should proceed with an insert or do nothing.
step "insert2" { INSERT INTO upsert(key, payload) VALUES('FOOFOO', 'insert2') ON CONFLICT (lower(key)) DO UPDATE set key = EXCLUDED.key, payload = upsert.payload || ' updated by insert2'; }
step "select2" { SELECT * FROM upsert; }
step "c2" { COMMIT; }
-step "a2" { ABORT; }
# One session (session 2) block-waits on another (session 1) to determine if it
# should proceed with an insert or update. The user can still usefully UPDATE
step "insert2" { INSERT INTO upsert(key, val) VALUES(1, 'insert2') ON CONFLICT (key) DO UPDATE set val = upsert.val || ' updated by insert2'; }
step "select2" { SELECT * FROM upsert; }
step "c2" { COMMIT; }
-step "a2" { ABORT; }
# One session (session 2) block-waits on another (session 1) to determine if it
# should proceed with an insert or update. Notably, this entails updating a
session "s0"
step "s0_begin" { begin; }
step "s0_keyshare" { select id from tlu_job where id = 1 for key share;}
-step "s0_share" { select id from tlu_job where id = 1 for share;}
step "s0_rollback" { rollback; }
session "s1"
step "s1_share" { select id from tlu_job where id = 1 for share; }
step "s1_fornokeyupd" { select id from tlu_job where id = 1 for no key update; }
step "s1_update" { update tlu_job set name = 'b' where id = 1; }
-step "s1_delete" { delete from tlu_job where id = 1; }
step "s1_savept_e" { savepoint s1_e; }
step "s1_savept_f" { savepoint s1_f; }
step "s1_rollback_e" { rollback to s1_e; }
step "s2_update" { update tlu_job set name = 'b' where id = 1; }
step "s2_delete" { delete from tlu_job where id = 1; }
step "s2_rollback" { rollback; }
-step "s2_commit" { commit; }
session "s3"
setup { begin; }