Skip to content

Commit 8459eb2

Browse files
MDEV-40388: sequence.simple fails on replay
When recording is enabled for the query such as, explain select * from seq_1_to_10; it recorded the table context having a DDL definition as: - CREATE TABLE `seq_1_to_10` ( -> `seq` bigint(20) unsigned NOT NULL, -> PRIMARY KEY (`seq`) -> ) ENGINE=SEQUENCE DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci; Now, when that context is replayed, the DDL statement is executed. But, we cannot create such a table, and instead it errors out saying ERROR 1050 (42S01): Table 'seq_1_to_10' already exists. Solution is to not record a DDL statement or any stats for sequence tables such as seq_1_to_10. Also, there is a different way to use sequences as: - Create sequence s1; Explain select * from s1; Here, we should be recording the DDL statement, but no need to store the stats for it. However, we didn't record the DDL statement earlier. Moreover, sequence's next value should be the same in the replay environment. Solution here is to record the DDL for such a sequence, and set its start value as the recorded environment's previous value.
1 parent 97e8c62 commit 8459eb2

7 files changed

Lines changed: 178 additions & 4 deletions

mysql-test/main/opt_context_replay_basic.result

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,4 +549,28 @@ select context like '%bar%' from information_schema.optimizer_context;
549549
context like '%bar%'
550550
1
551551
drop table t1;
552+
#
553+
# MDEV-40388: sequence.simple fails on replay
554+
#
555+
set optimizer_record_context=0;
556+
create sequence s1;
557+
select setval(s1, 10);
558+
setval(s1, 10)
559+
10
560+
set optimizer_record_context=1;
561+
select nextval(s1) as nv;
562+
nv
563+
11
564+
select context into dumpfile "../../tmp/dump1.sql"
565+
from information_schema.optimizer_context;
566+
set optimizer_record_context=0;
567+
drop table s1;
568+
set optimizer_replay_context='opt_context';
569+
# Get the last recorded value from the sequence; must have same output as above
570+
select lastval(s1) as nv;
571+
nv
572+
11
573+
set optimizer_replay_context='';
574+
drop table s1;
575+
# End of 13.1 tests
552576
drop database db1;

mysql-test/main/opt_context_replay_basic.test

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
--source include/not_embedded.inc
22
--source include/have_sequence.inc
3-
--source include/no_view_protocol.inc
3+
--source include/no_protocol.inc
44
--echo #enable optimizer_record_context
55
set optimizer_trace=0;
66
set optimizer_record_context=ON;
@@ -351,4 +351,31 @@ explain select * from t1 where a >'foo' or a < 'bar';
351351
select context like '%bar%' from information_schema.optimizer_context;
352352

353353
drop table t1;
354+
355+
--echo #
356+
--echo # MDEV-40388: sequence.simple fails on replay
357+
--echo #
358+
set optimizer_record_context=0;
359+
create sequence s1;
360+
select setval(s1, 10);
361+
set optimizer_record_context=1;
362+
select nextval(s1) as nv;
363+
select context into dumpfile "../../tmp/dump1.sql"
364+
from information_schema.optimizer_context;
365+
set optimizer_record_context=0;
366+
drop table s1;
367+
--disable_query_log
368+
--disable_result_log
369+
--source "$MYSQLTEST_VARDIR/tmp/dump1.sql"
370+
--enable_query_log
371+
--enable_result_log
372+
set optimizer_replay_context='opt_context';
373+
--echo # Get the last recorded value from the sequence; must have same output as above
374+
select lastval(s1) as nv;
375+
376+
set optimizer_replay_context='';
377+
--remove_file "$MYSQLTEST_VARDIR/tmp/dump1.sql"
378+
drop table s1;
379+
--echo # End of 13.1 tests
380+
354381
drop database db1;

mysql-test/main/opt_context_store_ddls.result

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,4 +542,41 @@ CREATE TABLE `t1` (
542542

543543

544544
drop table t1, t2;
545+
#
546+
# MDEV-40388: sequence.simple fails on replay
547+
#
548+
create sequence s1;
549+
# context result should have the ddl
550+
explain select * from s1;
551+
id select_type table type possible_keys key key_len ref rows Extra
552+
1 SIMPLE s1 system NULL NULL NULL NULL 1
553+
# == Optimizer Context Tables
554+
name
555+
# === Optimizer Context DDLs
556+
@ddls
557+
CREATE TABLE `s1` (
558+
`next_not_cached_value` bigint(21) NOT NULL,
559+
`minimum_value` bigint(21) NOT NULL,
560+
`maximum_value` bigint(21) NOT NULL,
561+
`start_value` bigint(21) NOT NULL COMMENT 'start value when sequences is created or value if RESTART is used',
562+
`increment` bigint(21) NOT NULL COMMENT 'increment value',
563+
`cache_size` bigint(21) unsigned NOT NULL,
564+
`cycle_option` tinyint(1) unsigned NOT NULL COMMENT '0 if no cycles are allowed, 1 if the sequence should begin a new cycle when maximum_value is passed',
565+
`cycle_count` bigint(21) NOT NULL COMMENT 'How many cycles have been done'
566+
) ENGINE=MyISAM SEQUENCE=1;
567+
568+
SELECT SETVAL(db1.s1, 1);
569+
570+
571+
drop table s1;
572+
# no ddl should be captured here
573+
explain select * from seq_1_to_10;
574+
id select_type table type possible_keys key key_len ref rows Extra
575+
1 SIMPLE seq_1_to_10 index NULL PRIMARY 8 NULL 10 Using index
576+
# == Optimizer Context Tables
577+
name
578+
# === Optimizer Context DDLs
579+
@ddls
580+
581+
# End of 13.1 tests
545582
drop database db1;

mysql-test/main/opt_context_store_ddls.test

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,4 +312,19 @@ delete t1.*, t2.* from t1, t2 where t1.id1 = t2.id2;
312312

313313
drop table t1, t2;
314314

315+
--echo #
316+
--echo # MDEV-40388: sequence.simple fails on replay
317+
--echo #
318+
create sequence s1;
319+
--echo # context result should have the ddl
320+
explain select * from s1;
321+
--source include/opt_context_list_tables_ddls.inc
322+
drop table s1;
323+
324+
--echo # no ddl should be captured here
325+
explain select * from seq_1_to_10;
326+
--source include/opt_context_list_tables_ddls.inc
327+
328+
--echo # End of 13.1 tests
329+
315330
drop database db1;

mysql-test/main/opt_context_store_stats.result

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,3 +591,19 @@ table_name file_stat_records index_name rec_per_key
591591
index_name ranges num_rows max_index_blocks max_row_blocks
592592
# == End of optimizer context
593593
drop table s1;
594+
#
595+
# MDEV-40388: sequence.simple fails on replay
596+
# Table context should *not* be recorded for seq
597+
#
598+
set optimizer_record_context=ON;
599+
explain select * from seq_1_to_10;
600+
id select_type table type possible_keys key key_len ref rows Extra
601+
1 SIMPLE seq_1_to_10 index NULL PRIMARY 8 NULL 10 Using index
602+
# == Optimizer Context
603+
# === Tables
604+
# Tables in the context
605+
table_name file_stat_records index_name rec_per_key
606+
# === Range accesses
607+
index_name ranges num_rows max_index_blocks max_row_blocks
608+
# == End of optimizer context
609+
# End of 13.1 tests

mysql-test/main/opt_context_store_stats.test

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,3 +432,14 @@ EXPLAIN select * from s1;
432432

433433
--source include/opt_context_list_tables_and_ranges.inc
434434
drop table s1;
435+
436+
--echo #
437+
--echo # MDEV-40388: sequence.simple fails on replay
438+
--echo # Table context should *not* be recorded for seq
439+
--echo #
440+
set optimizer_record_context=ON;
441+
explain select * from seq_1_to_10;
442+
443+
--source include/opt_context_list_tables_and_ranges.inc
444+
445+
--echo # End of 13.1 tests

sql/opt_context_store_replay.cc

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -756,10 +756,14 @@ bool Optimizer_context_recorder::dump_sql_script(THD* thd, String &sql_script)
756756
append_table_or_view_name(tbl, &full_tbl_name);
757757

758758
/*
759-
Sequence table doesn't need CREATE TABLE or contain any stats
759+
Sequence table such as seq_1_to_10 is a virtual table and so
760+
doesn't need CREATE TABLE STATEMENT, and stats.
760761
*/
761-
if (tbl->table && tbl->table->s && tbl->table->s->sequence)
762+
if (!tbl->is_view() && tbl->table && tbl->table->s->db_type() &&
763+
tbl->table->s->db_type()->discover_table)
764+
{
762765
continue;
766+
}
763767

764768
/*
765769
A query can use the same table multiple times. Do not dump the
@@ -809,10 +813,50 @@ bool Optimizer_context_recorder::dump_sql_script(THD* thd, String &sql_script)
809813
qry_ctx_script.append(ddl);
810814
qry_ctx_script.append(STRING_WITH_LEN(";\n\n"));
811815

812-
/* If this is a VIEW, we've stored its DDL and we're done. */
816+
/* If this is a VIEW we've stored its DDL and we're done. */
813817
if (tbl->is_view())
814818
continue;
815819

820+
/*
821+
if this is a SEQUENCE table defined as
822+
CREATE SEQUENCE s1;
823+
then, record the current value of s1 as well.
824+
DDL for it has already been recorded.
825+
No need to record stats.
826+
*/
827+
if (tbl->table && tbl->table->s->sequence)
828+
{
829+
const char *key;
830+
uint length= get_table_def_key(tbl, &key); // table def key = hash key
831+
SEQUENCE_LAST_VALUE *entry= (SEQUENCE_LAST_VALUE *) my_hash_search(
832+
&thd->sequences, (uchar *) key, length);
833+
SEQUENCE *seq= tbl->table->s->sequence;
834+
longlong value;
835+
if (entry && !entry->check_version(tbl->table))
836+
{
837+
/*
838+
Set the sequence so that the next NEXTVAL returns the value that
839+
was last handed out (entry->value): SETVAL(x) makes the next
840+
NEXTVAL return x + increment, so use entry->value - increment.
841+
Keep the argument within the sequence bounds - for an ascending
842+
sequence it may fall below min_value, for a descending one it may
843+
rise above max_value, and SETVAL rejects out-of-range values.
844+
*/
845+
longlong candidate= entry->value - seq->increment;
846+
value= seq->increment > 0 ? MY_MAX(candidate, seq->min_value)
847+
: MY_MIN(candidate, seq->max_value);
848+
}
849+
else
850+
value= seq->reserved_until;
851+
qry_ctx_script.append(STRING_WITH_LEN("SELECT SETVAL("));
852+
qry_ctx_script.append(full_tbl_name);
853+
qry_ctx_script.append(STRING_WITH_LEN(", "));
854+
qry_ctx_script.append_longlong(value);
855+
qry_ctx_script.append(STRING_WITH_LEN(");\n\n"));
856+
857+
continue;
858+
}
859+
816860
/* No, it's a base table */
817861
Json_writer_object ctx_wrapper(&ctx_writer);
818862

0 commit comments

Comments
 (0)