mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-08-27 18:37:19 +02:00
Manifested as ERROR: subtransaction logged without previous top-level txn record this check forbids legit behaviours like - First xl_xact_assignment record is beyond reading, i.e. earlier restart_lsn. - After restart_lsn there is some change of a subxact. - After that, there is second xl_xact_assignment (for another subxact) revealing the relationship between top and first subxact. Such a transaction won't be streamed anyway because we hadn't seen it in full. Saying for sure whether xact of some record encountered after the snapshot was deserialized can be streamed or not requires to know whether it wrote something before deserialization point --if yes, it hasn't been seen in full and can't be decoded. Snapshot doesn't have such info, so there is no easy way to relax the check. Reported-by: Hsu, John Diagnosed-by: Arseny Sher Author: Arseny Sher, Amit Kapila Reviewed-by: Amit Kapila, Dilip Kumar Backpatch-through: 9.5 Discussion: https://postgr.es/m/AB5978B2-1772-4FEE-A245-74C91704ECB0@amazon.com
64 lines
2.4 KiB
Ruby
64 lines
2.4 KiB
Ruby
# Test decoding of subtransactions whose top-transaction is before restart
|
|
# point. Such transactions won't be streamed as we stream only complete
|
|
# transactions, but it is good to test that they don't cause any problem.
|
|
|
|
setup
|
|
{
|
|
SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding'); -- must be first write in xact
|
|
CREATE TABLE harvest(apples integer);
|
|
CREATE OR REPLACE FUNCTION subxacts() returns void as $$
|
|
BEGIN
|
|
FOR i in 1 .. 128 LOOP
|
|
BEGIN
|
|
INSERT INTO harvest VALUES (42);
|
|
EXCEPTION
|
|
WHEN OTHERS THEN
|
|
RAISE;
|
|
END;
|
|
END LOOP;
|
|
END; $$LANGUAGE 'plpgsql';
|
|
}
|
|
|
|
teardown
|
|
{
|
|
DROP TABLE IF EXISTS harvest;
|
|
SELECT 'stop' FROM pg_drop_replication_slot('isolation_slot');
|
|
}
|
|
|
|
session "s0"
|
|
setup { SET synchronous_commit=on; }
|
|
step "s0_begin" { BEGIN; }
|
|
step "s0_first_subxact" {
|
|
DO LANGUAGE plpgsql $$
|
|
BEGIN
|
|
BEGIN
|
|
INSERT INTO harvest VALUES (41);
|
|
EXCEPTION WHEN OTHERS THEN RAISE;
|
|
END;
|
|
END $$;
|
|
}
|
|
step "s0_many_subxacts" { select subxacts(); }
|
|
step "s0_commit" { COMMIT; }
|
|
|
|
session "s1"
|
|
setup { SET synchronous_commit=on; }
|
|
step "s1_begin" { BEGIN; }
|
|
step "s1_dml" { INSERT INTO harvest VALUES (43); }
|
|
step "s1_commit" { COMMIT; }
|
|
|
|
session "s2"
|
|
setup { SET synchronous_commit=on; }
|
|
step "s2_checkpoint" { CHECKPOINT; }
|
|
step "s2_get_changes" { SELECT data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); }
|
|
step "s2_get_changes_suppress_output" { SELECT null n FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1') GROUP BY n; }
|
|
|
|
# The first checkpoint establishes the potential restart point (aka
|
|
# restart_lsn) for the slot after the initial subxact. The second checkpoint
|
|
# followed by get_changes will ensure that the potential restart point will
|
|
# become the actual restart point. We do get_changes twice because if one
|
|
# more xl_running_xacts record had slipped before our s0_commit, then the
|
|
# potential restart point won't become actual restart point. The s1's open
|
|
# transaction till get_changes holds the potential restart point to our first
|
|
# checkpoint location.
|
|
permutation "s0_begin" "s0_first_subxact" "s2_checkpoint" "s1_begin" "s1_dml" "s0_many_subxacts" "s0_commit" "s2_checkpoint" "s2_get_changes_suppress_output" "s2_get_changes_suppress_output" "s1_commit" "s2_get_changes"
|