File: rpl_gtid_empty_transaction.test

package info (click to toggle)
mysql-8.0 8.0.43-3
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,273,924 kB
  • sloc: cpp: 4,684,605; ansic: 412,450; pascal: 108,398; java: 83,641; perl: 30,221; cs: 27,067; sql: 26,594; sh: 24,181; python: 21,816; yacc: 17,169; php: 11,522; xml: 7,388; javascript: 7,076; makefile: 2,194; lex: 1,075; awk: 670; asm: 520; objc: 183; ruby: 97; lisp: 86
file content (354 lines) | stat: -rw-r--r-- 10,886 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
# ==== Purpose ====
#
# Verifies that empty transactions are generated when they are
# supposed to. There are three cases:
#
#  1. Transaction is filtered out on slave
#
#  2. Transaction does not have any effect, gets logged and assigned a
#     GTID on master because master uses binlog_format=statement, but
#     does not get logged on slave because slave uses binlog_format='row'.
#
#  3. Transaction is explicitly made empty on master by setting
#     gtid_next and executing a COMMIT.
#
# Moreover, verify that no empty transaction is generated for rolled
# back transactions.
#
# ==== Implementation ====
#
# For case 1, we use a filter (specified in the .cnf file) to filter
# out table t_ignore, and verify that empty transaction is generated
# on slave.  Do this both for (1A) base tables and for (1B) temporary
# tables.
#
# For case 2, we use binlog_format=statement on master and
# binlog_format='row' on the first slave.  We test two cases of
# transactions that are not logged in row format: (2A) temporary table
# DDL and DML and (2B) an UPDATE statement that matches no row.  We
# use a second slave where the effect of the statement would be seen,
# if it was not logged as an empty statement.  In case (2A) we check
# that replica_open_temp_tables is still 0 on the second slave. In case
# (2B) we do an UPDATE on master that matches no rows on master, but
# that would match a row on the second slave.
#
# For case 3, we just execute an explicit empty transaction
# inside/outside stored procedure on master and verify that it gets
# assigned a GTID and gets replicated to the slaves.
#
# To verify nothing is logged for rollback transactions, we execute a
# DDL statement that generates an error, a DML statement that
# generates an error, and an explicit ROLLBACK transaction, and verify
# that nothing got logged for the three statements.
#
# ==== References ====
#
# WL#3584 - Global Transaction Identifiers (GTIDs)
# - The base worklog implementing empty transactions.
# BUG#18145032 - NO EMPTY TRANSACTION IS CREATED FOR A FILTERED CREATE TEMPORARY TABLE WITH GTIDS
# - Addressing the special cases for CREATE/ALTER/DROP TEMPORARY.
# BUG#18095502 - RESTART OF SLAVE INSTANCE FAIL IN GTID REPLICATION IF WE USE REPLICATE-IGNORE-DB
# - Addressing database filters in the applier thread.
# BUG#19774317 GTID_NEXT WITH EMPTY TRANSACTIONS DOES NOT WORK INSIDE STORED PROCEDURES
# - Addressing gtid_next with empty transaction inside stored procedure.

--let $rpl_topology= 1->2->3
--let $rpl_gtid_utils= 1
--source include/rpl_init.inc
--source include/rpl_default_connections.inc
--source include/have_binlog_format_mixed.inc

--source include/rpl_reset.inc

--echo ==== Case 1A: Transaction filtered out ====

--source include/gtid_step_reset.inc

CREATE TABLE t_ignore(id INT);
INSERT INTO t_ignore VALUES (1);
DROP TABLE t_ignore;

CREATE TABLE t_ignore_wild(id INT);
INSERT INTO t_ignore_wild VALUES (1);
DROP TABLE t_ignore_wild;

# Verify that 6 GTIDs were generated.
--let $gtid_step_count= 6
--source include/gtid_step_assert.inc

# Verify that the GTIDs make it to every slave
--source include/rpl_sync.inc

--echo ==== Case 1B: CREATE/ALTER/DROP TEMPORARY filtered out ====

CREATE TEMPORARY TABLE t_ignore(a INT);
ALTER TABLE t_ignore ADD COLUMN b INT;
INSERT INTO t_ignore VALUES (1, 2);
DROP TEMPORARY TABLE t_ignore;

CREATE TEMPORARY TABLE t_ignore_wild(a INT);
ALTER TABLE t_ignore_wild ADD COLUMN b INT;
INSERT INTO t_ignore_wild VALUES (1, 2);
DROP TEMPORARY TABLE t_ignore_wild;

# Verify that 0 GTIDs were generated.
--let $gtid_step_count= 0
--source include/gtid_step_assert.inc

# Verify that the GTIDs make it to every slave.
--source include/rpl_sync.inc

--echo ==== Case 1C: database filters on slave applier ====

--source include/gtid_step_reset.inc

# These two will be ignored on first slave.
CREATE DATABASE db_ignore;
USE db_ignore;
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1);
USE test;

# Verify 2 GTIDs were generated
--let $gtid_step_count= 3
--source include/gtid_step_assert.inc

--source include/rpl_sync.inc

--let $assert_text= db_ignore should not be created on slave
--let $assert_cond= "[slave:SHOW DATABASES LIKE "db_ignore"]" = ""
--source include/assert.inc

--let $assert_text= db_ignore should not be created on second slave
--let $assert_cond= "[server_3:SHOW DATABASES LIKE "db_ignore"]" = ""
--source include/assert.inc

DROP DATABASE db_ignore;
--source include/rpl_sync.inc

--echo ==== Case 1D: database filters on slave binary log ====

--source include/gtid_step_reset.inc

# These two will be ignored on first slave.
CREATE DATABASE db_binlog_ignore;
USE db_binlog_ignore;
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1);
USE test;

# Verify 2 GTIDs were generated
--let $gtid_step_count= 3
--source include/gtid_step_assert.inc

--source include/rpl_sync.inc

--let $assert_text= db_binlog_ignore should not be created on slave
--let $assert_cond= "[slave:SHOW DATABASES LIKE "db_binlog_ignore"]" = "db_binlog_ignore"
--source include/assert.inc

--let $assert_text= db_binlog_ignore should not be created on second slave
--let $assert_cond= "[server_3:SHOW DATABASES LIKE "db_binlog_ignore"]" = ""
--source include/assert.inc

DROP DATABASE db_binlog_ignore;
--source include/rpl_sync.inc

--echo ==== Case 2A: temp table transaction not logged in row format ====

--echo ---- Initialize ----

--connection slave
SET @save.binlog_format= @@global.binlog_format;
# To avoid an error 'ER_RUNNING_APPLIER_PREVENTS_SWITCH_GLOBAL_BINLOG_FORMAT',
# which will be caused by the following include/end_replace_combination.inc
--source include/stop_slave_sql.inc
SET @@global.binlog_format= 'row';
source include/start_slave_sql.inc;

--echo ---- Test ----

--source include/gtid_step_reset.inc


# - Master will log these statements and assign them GTIDs, since
#   master uses binlog_format=statement.
#
# - First slave will not log any change since it uses row format, but
#   it should log empty transactions with GTIDs.
#
# - Second slave should also not log any change, since it receives an
#   empty transaction from the first slave.  Thus
#   Replica_open_temp_tables should remain 0 on the second slave.
CREATE TEMPORARY TABLE t2 (a INT);
ALTER TABLE t2 ADD COLUMN b INT;
INSERT INTO t2 VALUES (1, 2);

# assert exactly 0 GTIDs were generated
--let $gtid_step_count= 0
--source include/gtid_step_assert.inc

# Verify that the GTID gets replicated everywhere.
--let $use_gtids= 1
--source include/rpl_sync.inc

# Verify temp tables on first slave but not on second slave
--let $assert_text= First slave should not have created any temp table
--let $assert_cond= [slave:SHOW GLOBAL STATUS LIKE 'Replica_open_temp_tables'] = 1

--let $assert_text= Second slave should not have created any temp table
--let $assert_cond= [server_3:SHOW GLOBAL STATUS LIKE 'Replica_open_temp_tables'] = 0

--echo ---- Clean up ----

DROP TEMPORARY TABLE t2;
--source include/rpl_sync.inc

--connection slave
# To avoid an error 'ER_RUNNING_APPLIER_PREVENTS_SWITCH_GLOBAL_BINLOG_FORMAT',
# which will be caused by the following include/end_replace_combination.inc
--source include/stop_slave_sql.inc
SET @@global.binlog_format= @save.binlog_format;
--connection master

--echo ==== Case 2B: transaction with no effect not logged in row format ====

--echo ---- Initialize ----

--connection slave
SET @save.binlog_format= @@global.binlog_format;
SET @@global.binlog_format= 'row';
source include/start_slave_sql.inc;

--connection master
SET @@session.binlog_format= statement;
CREATE TABLE t1(id INT) ENGINE = InnoDB;
--source include/rpl_sync.inc
--connection server_3
INSERT INTO t1 VALUES (0);
--connection master

--echo ---- Test ----

# - Master will log this and assign it a GTID despite it has no
#   effect, since master uses binlog_format=statement.
#
# - First slave will not log any change since it uses row format, but
#   it should log an empty transaction with a GTID.
#
# - Second slave should also not log any change, since it receives an
#   empty transaction from the first slave.  It should also not update
#   the table despite the original SQL statement would match a row on
#   the second slave, since it only receives the empty transaction
#   from the first slave.
UPDATE t1 SET id= 1 WHERE id = 0;

# Verify that the GTID gets replicated everywhere.
--let $use_gtids= 1
--source include/rpl_sync.inc

--let $assert_text= Second slave should not have done any update
--let $assert_cond= [server_3:SELECT * FROM t1] = 0

-- echo ---- Clean up ----

DROP TABLE t1;
--source include/rpl_sync.inc

--connection slave
# To avoid an error 'ER_RUNNING_APPLIER_PREVENTS_SWITCH_GLOBAL_BINLOG_FORMAT',
# which will be caused by the following include/end_replace_combination.inc
--source include/stop_slave_sql.inc
SET @@global.binlog_format= @save.binlog_format;
--source include/start_slave_sql.inc
--connection master

--echo ==== Case 3: explicit empty transaction on master ====

SET @@SESSION.binlog_format= 'row';
--source include/gtid_step_reset.inc
eval SET @@SESSION.GTID_NEXT = '$uuida:1';
COMMIT;
SET @@SESSION.GTID_NEXT = 'AUTOMATIC';

# Verify exactly one GTID was generated
--let $gtid_step_count= 1
--let $gtid_step_only_count= 1
--source include/gtid_step_assert.inc

# ==== Purpose ====
#
# Verify that committing an empty transaction with specified gtid works fine
# inside stored procedure when binlog is enabled.
#
# ==== References ====
#
# BUG#19774317 GTID_NEXT WITH EMPTY TRANSACTIONS DOES NOT WORK INSIDE STORED PROCEDURES
# mysql-test/t/no_binlog_gtid_empty_transaction.test

CREATE TABLE t1 (a INT);

delimiter |;

CREATE PROCEDURE p1()
BEGIN
  SET @@SESSION.GTID_NEXT = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:2';
  START TRANSACTION;
  COMMIT;
  SET @@SESSION.GTID_NEXT = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:3';
  START TRANSACTION;
  COMMIT;
END|

delimiter ;|

# Verify exactly two GTIDs were generated
--let $gtid_step_count= 2
--let $gtid_step_only_count= 1
--source include/gtid_step_assert.inc

CALL p1();

SET @@SESSION.GTID_NEXT = 'AUTOMATIC';
# Verify exactly four GTIDs were generated
--let $gtid_step_count= 2
--let $gtid_step_only_count= 1
--source include/gtid_step_assert.inc
--let $gtid_step_only_count= 0

DROP TABLE t1;

# Verify the GTID makes it to every slave.
--source include/rpl_sync.inc

--echo ==== Case 4: Nothing logged for ROLLBACK transactions ====

# Test that ROLLBACK does not generate any GTID

--echo ---- Initialize ----

CREATE TABLE t1 (a INT) ENGINE = InnoDB;

--echo ---- Test ----

--source include/gtid_step_reset.inc

--error ER_BAD_TABLE_ERROR
DROP TABLE t2;

--error ER_WRONG_VALUE_COUNT_ON_ROW
INSERT INTO t1 VALUES (1, 1);

BEGIN;
INSERT INTO t1 VALUES (2);
ROLLBACK;

--let $gtid_step_count= 0
--source include/gtid_step_assert.inc

--echo ---- Clean Up ----

DROP TABLE t1;
DROP PROCEDURE p1;

--source include/rpl_end.inc