@@ -6,65 +6,200 @@ SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_d
6
6
init
7
7
(1 row)
8
8
9
- CREATE TABLE test_prepared1(idint );
10
- CREATE TABLE test_prepared2(idint );
9
+ CREATE TABLE test_prepared1(idinteger primary key );
10
+ CREATE TABLE test_prepared2(idinteger primary key );
11
11
-- test simple successful use of a prepared xact
12
12
BEGIN;
13
13
INSERT INTO test_prepared1 VALUES (1);
14
14
PREPARE TRANSACTION 'test_prepared#1';
15
+ SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
16
+ data
17
+ ----------------------------------------------------
18
+ BEGIN
19
+ table public.test_prepared1: INSERT: id[integer]:1
20
+ PREPARE TRANSACTION 'test_prepared#1'
21
+ (3 rows)
22
+
15
23
COMMIT PREPARED 'test_prepared#1';
24
+ SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
25
+ data
26
+ -----------------------------------
27
+ COMMIT PREPARED 'test_prepared#1'
28
+ (1 row)
29
+
16
30
INSERT INTO test_prepared1 VALUES (2);
17
31
-- test abort of a prepared xact
18
32
BEGIN;
19
33
INSERT INTO test_prepared1 VALUES (3);
20
34
PREPARE TRANSACTION 'test_prepared#2';
35
+ SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
36
+ data
37
+ ----------------------------------------------------
38
+ BEGIN
39
+ table public.test_prepared1: INSERT: id[integer]:2
40
+ COMMIT
41
+ BEGIN
42
+ table public.test_prepared1: INSERT: id[integer]:3
43
+ PREPARE TRANSACTION 'test_prepared#2'
44
+ (6 rows)
45
+
21
46
ROLLBACK PREPARED 'test_prepared#2';
47
+ SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
48
+ data
49
+ -------------------------------------
50
+ ROLLBACK PREPARED 'test_prepared#2'
51
+ (1 row)
52
+
22
53
INSERT INTO test_prepared1 VALUES (4);
23
54
-- test prepared xact containing ddl
24
55
BEGIN;
25
56
INSERT INTO test_prepared1 VALUES (5);
26
57
ALTER TABLE test_prepared1 ADD COLUMN data text;
27
58
INSERT INTO test_prepared1 VALUES (6, 'frakbar');
28
59
PREPARE TRANSACTION 'test_prepared#3';
29
- -- test that we decode correctly while an uncommitted prepared xact
30
- -- with ddl exists.
31
- -- separate table because of the lock from the ALTER
32
- -- this will come before the '5' row above, as this commits before it.
33
- INSERT INTO test_prepared2 VALUES (7);
34
- COMMIT PREPARED 'test_prepared#3';
35
- -- make sure stuff still works
36
- INSERT INTO test_prepared1 VALUES (8);
37
- INSERT INTO test_prepared2 VALUES (9);
38
- -- cleanup
39
- DROP TABLE test_prepared1;
40
- DROP TABLE test_prepared2;
41
- -- show results
60
+ SELECT 'test_prepared_1' AS relation, locktype, mode
61
+ FROM pg_locks
62
+ WHERE locktype = 'relation'
63
+ AND relation = 'test_prepared1'::regclass;
64
+ relation | locktype | mode
65
+ -----------------+----------+---------------------
66
+ test_prepared_1 | relation | RowExclusiveLock
67
+ test_prepared_1 | relation | AccessExclusiveLock
68
+ (2 rows)
69
+
42
70
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
43
71
data
44
72
-------------------------------------------------------------------------
45
- BEGIN
46
- table public.test_prepared1: INSERT: id[integer]:1
47
- COMMIT
48
- BEGIN
49
- table public.test_prepared1: INSERT: id[integer]:2
50
- COMMIT
51
73
BEGIN
52
74
table public.test_prepared1: INSERT: id[integer]:4
53
75
COMMIT
54
76
BEGIN
55
- table public.test_prepared2: INSERT: id[integer]:7
56
- COMMIT
57
- BEGIN
58
77
table public.test_prepared1: INSERT: id[integer]:5
59
78
table public.test_prepared1: INSERT: id[integer]:6 data[text]:'frakbar'
79
+ PREPARE TRANSACTION 'test_prepared#3'
80
+ (7 rows)
81
+
82
+ -- Test that we decode correctly while an uncommitted prepared xact
83
+ -- with ddl exists.
84
+ --
85
+ -- Use a separate table for the concurrent transaction because the lock from
86
+ -- the ALTER will stop us inserting into the other one.
87
+ --
88
+ -- We should see '7' before '5' in our results since it commits first.
89
+ --
90
+ INSERT INTO test_prepared2 VALUES (7);
91
+ SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
92
+ data
93
+ ----------------------------------------------------
94
+ BEGIN
95
+ table public.test_prepared2: INSERT: id[integer]:7
60
96
COMMIT
97
+ (3 rows)
98
+
99
+ COMMIT PREPARED 'test_prepared#3';
100
+ SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
101
+ data
102
+ -----------------------------------
103
+ COMMIT PREPARED 'test_prepared#3'
104
+ (1 row)
105
+
106
+ -- make sure stuff still works
107
+ INSERT INTO test_prepared1 VALUES (8);
108
+ INSERT INTO test_prepared2 VALUES (9);
109
+ SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
110
+ data
111
+ --------------------------------------------------------------------
61
112
BEGIN
62
113
table public.test_prepared1: INSERT: id[integer]:8 data[text]:null
63
114
COMMIT
64
115
BEGIN
65
116
table public.test_prepared2: INSERT: id[integer]:9
66
117
COMMIT
67
- (22 rows)
118
+ (6 rows)
119
+
120
+ -- Check `CLUSTER` (as operation that hold exclusive lock) doesn't block
121
+ -- logical decoding.
122
+ BEGIN;
123
+ INSERT INTO test_prepared1 VALUES (10, 'othercol');
124
+ CLUSTER test_prepared1 USING test_prepared1_pkey;
125
+ INSERT INTO test_prepared1 VALUES (11, 'othercol2');
126
+ PREPARE TRANSACTION 'test_prepared_lock';
127
+ BEGIN;
128
+ insert into test_prepared2 values (12);
129
+ PREPARE TRANSACTION 'test_prepared_lock2';
130
+ COMMIT PREPARED 'test_prepared_lock2';
131
+ SELECT 'pg_class' AS relation, locktype, mode
132
+ FROM pg_locks
133
+ WHERE locktype = 'relation'
134
+ AND relation = 'pg_class'::regclass;
135
+ relation | locktype | mode
136
+ ----------+----------+------
137
+ (0 rows)
138
+
139
+ -- Shouldn't timeout on 2pc decoding.
140
+ SET statement_timeout = '1s';
141
+ SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
142
+ data
143
+ ----------------------------------------------------------------------------
144
+ BEGIN
145
+ table public.test_prepared1: INSERT: id[integer]:10 data[text]:'othercol'
146
+ table public.test_prepared1: INSERT: id[integer]:11 data[text]:'othercol2'
147
+ PREPARE TRANSACTION 'test_prepared_lock'
148
+ BEGIN
149
+ table public.test_prepared2: INSERT: id[integer]:12
150
+ PREPARE TRANSACTION 'test_prepared_lock2'
151
+ COMMIT PREPARED 'test_prepared_lock2'
152
+ (8 rows)
153
+
154
+ RESET statement_timeout;
155
+ COMMIT PREPARED 'test_prepared_lock';
156
+ -- will work normally after we commit
157
+ SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
158
+ data
159
+ --------------------------------------
160
+ COMMIT PREPARED 'test_prepared_lock'
161
+ (1 row)
162
+
163
+ -- test savepoints
164
+ BEGIN;
165
+ SAVEPOINT test_savepoint;
166
+ CREATE TABLE test_prepared_savepoint (a int);
167
+ PREPARE TRANSACTION 'test_prepared_savepoint';
168
+ COMMIT PREPARED 'test_prepared_savepoint';
169
+ SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
170
+ data
171
+ -------------------------------------------
172
+ COMMIT PREPARED 'test_prepared_savepoint'
173
+ (1 row)
174
+
175
+ -- test that a GID containing "nodecode" gets decoded at commit prepared time
176
+ BEGIN;
177
+ INSERT INTO test_prepared1 VALUES (20);
178
+ PREPARE TRANSACTION 'test_prepared_nodecode';
179
+ -- should show nothing
180
+ SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
181
+ data
182
+ ------
183
+ (0 rows)
184
+
185
+ COMMIT PREPARED 'test_prepared_nodecode';
186
+ -- should be decoded now
187
+ SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
188
+ data
189
+ ---------------------------------------------------------------------
190
+ BEGIN
191
+ table public.test_prepared1: INSERT: id[integer]:20 data[text]:null
192
+ COMMIT
193
+ (3 rows)
194
+
195
+ -- cleanup
196
+ DROP TABLE test_prepared1;
197
+ DROP TABLE test_prepared2;
198
+ -- show results. There should be nothing to show
199
+ SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
200
+ data
201
+ ------
202
+ (0 rows)
68
203
69
204
SELECT pg_drop_replication_slot('regression_slot');
70
205
pg_drop_replication_slot