diff --git a/mysql-test/r/information_schema_keywords.result b/mysql-test/r/information_schema_keywords.result index 8b426703873b..1cb69df6237a 100644 --- a/mysql-test/r/information_schema_keywords.result +++ b/mysql-test/r/information_schema_keywords.result @@ -435,6 +435,7 @@ PASSWORD 0 PASSWORD_LOCK_TIME 0 PATH 0 PERCENT_RANK 1 +PERCONA_SEQUENCE_TABLE 1 PERSIST 0 PERSIST_ONLY 0 PHASE 0 @@ -554,6 +555,7 @@ SECURITY 0 SELECT 1 SENSITIVE 1 SEPARATOR 1 +SEQUENCE_TABLE 0 SERIAL 0 SERIALIZABLE 0 SERVER 0 diff --git a/mysql-test/r/mysqld--help-notwin.result b/mysql-test/r/mysqld--help-notwin.result index 04960ff00a02..494883a4c329 100644 --- a/mysql-test/r/mysqld--help-notwin.result +++ b/mysql-test/r/mysqld--help-notwin.result @@ -1612,6 +1612,9 @@ The following options may be given as the first argument: a version lower than 8.2.0. SHOW EVENTS and queries into information_schema.events will also output the old terminology for the event status field. + --tf-sequence-table-max-upper-bound=# + Maximum number of records PERCONA_SEQUENCE_TABLE() table + function is allowed to generate. --thread-cache-size=# How many threads we should keep in a cache for reuse --thread-handling=name @@ -2115,6 +2118,7 @@ tc-heuristic-recover OFF temptable-max-mmap 0 temptable-use-mmap FALSE terminology-use-previous NONE +tf-sequence-table-max-upper-bound 1048576 thread-cache-size 9 thread-handling one-thread-per-connection thread-stack 1048576 diff --git a/mysql-test/suite/federated/r/federated_debug.result b/mysql-test/suite/federated/r/federated_debug.result index b9556f98c097..742004a802bc 100644 --- a/mysql-test/suite/federated/r/federated_debug.result +++ b/mysql-test/suite/federated/r/federated_debug.result @@ -44,7 +44,7 @@ SELECT * FROM test.t1; id SET @debug_save= @@GLOBAL.DEBUG; SET @@GLOBAL.DEBUG='+d,PS-8747_wait_for_disconnect_after_check'; -INSERT INTO test.t1 SELECT tt.* FROM SEQUENCE_TABLE(20000) AS tt; +INSERT INTO test.t1 SELECT tt.* FROM PERCONA_SEQUENCE_TABLE(20000) AS tt; SET GLOBAL DEBUG= @debug_save; DROP TABLE test.t1; DROP SERVER test; diff --git a/mysql-test/suite/federated/t/federated_debug.test b/mysql-test/suite/federated/t/federated_debug.test index 5bde52fef793..581c4bbd94f0 100644 --- a/mysql-test/suite/federated/t/federated_debug.test +++ b/mysql-test/suite/federated/t/federated_debug.test @@ -60,7 +60,7 @@ SET @@GLOBAL.DEBUG='+d,PS-8747_wait_for_disconnect_after_check'; # Send data which will not fit into one communication packet, so client will try to send them # before flush and reconnection. -INSERT INTO test.t1 SELECT tt.* FROM SEQUENCE_TABLE(20000) AS tt; +INSERT INTO test.t1 SELECT tt.* FROM PERCONA_SEQUENCE_TABLE(20000) AS tt; SET GLOBAL DEBUG= @debug_save; DROP TABLE test.t1; diff --git a/mysql-test/suite/innodb_fts/include/percona_ft_special_chars.inc b/mysql-test/suite/innodb_fts/include/percona_ft_special_chars.inc index e6f4b99150fd..e25e045998ac 100644 --- a/mysql-test/suite/innodb_fts/include/percona_ft_special_chars.inc +++ b/mysql-test/suite/innodb_fts/include/percona_ft_special_chars.inc @@ -99,7 +99,7 @@ OPTIMIZE TABLE t1; --echo *** creating a list of all printable characters (ASCII 33..126) --echo *** (whitespace and control characters are excluded) -SELECT GROUP_CONCAT(CHAR(value + 33 USING utf8mb4) SEPARATOR '') INTO @special_characters FROM SEQUENCE_TABLE(127 - 33) AS tt; +SELECT GROUP_CONCAT(CHAR(value + 33 USING utf8mb4) SEPARATOR '') INTO @special_characters FROM PERCONA_SEQUENCE_TABLE(127 - 33) AS tt; SELECT @special_characters; --echo diff --git a/mysql-test/suite/innodb_fts/r/percona_ft_special_chars_default_ewc_off.result b/mysql-test/suite/innodb_fts/r/percona_ft_special_chars_default_ewc_off.result index 892c269a3a14..b999ad5e4801 100644 --- a/mysql-test/suite/innodb_fts/r/percona_ft_special_chars_default_ewc_off.result +++ b/mysql-test/suite/innodb_fts/r/percona_ft_special_chars_default_ewc_off.result @@ -67,7 +67,7 @@ test.t1 optimize status OK *** creating a list of all printable characters (ASCII 33..126) *** (whitespace and control characters are excluded) -SELECT GROUP_CONCAT(CHAR(value + 33 USING utf8mb4) SEPARATOR '') INTO @special_characters FROM SEQUENCE_TABLE(127 - 33) AS tt; +SELECT GROUP_CONCAT(CHAR(value + 33 USING utf8mb4) SEPARATOR '') INTO @special_characters FROM PERCONA_SEQUENCE_TABLE(127 - 33) AS tt; SELECT @special_characters; @special_characters !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ diff --git a/mysql-test/suite/innodb_fts/r/percona_ft_special_chars_default_ewc_on.result b/mysql-test/suite/innodb_fts/r/percona_ft_special_chars_default_ewc_on.result index 4276403ea6fe..fe2166939050 100644 --- a/mysql-test/suite/innodb_fts/r/percona_ft_special_chars_default_ewc_on.result +++ b/mysql-test/suite/innodb_fts/r/percona_ft_special_chars_default_ewc_on.result @@ -67,7 +67,7 @@ test.t1 optimize status OK *** creating a list of all printable characters (ASCII 33..126) *** (whitespace and control characters are excluded) -SELECT GROUP_CONCAT(CHAR(value + 33 USING utf8mb4) SEPARATOR '') INTO @special_characters FROM SEQUENCE_TABLE(127 - 33) AS tt; +SELECT GROUP_CONCAT(CHAR(value + 33 USING utf8mb4) SEPARATOR '') INTO @special_characters FROM PERCONA_SEQUENCE_TABLE(127 - 33) AS tt; SELECT @special_characters; @special_characters !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ diff --git a/mysql-test/suite/innodb_fts/r/percona_ft_special_chars_mecab_ewc_off.result b/mysql-test/suite/innodb_fts/r/percona_ft_special_chars_mecab_ewc_off.result index da877b95d924..9d33b0ff383e 100644 --- a/mysql-test/suite/innodb_fts/r/percona_ft_special_chars_mecab_ewc_off.result +++ b/mysql-test/suite/innodb_fts/r/percona_ft_special_chars_mecab_ewc_off.result @@ -71,7 +71,7 @@ test.t1 optimize status OK *** creating a list of all printable characters (ASCII 33..126) *** (whitespace and control characters are excluded) -SELECT GROUP_CONCAT(CHAR(value + 33 USING utf8mb4) SEPARATOR '') INTO @special_characters FROM SEQUENCE_TABLE(127 - 33) AS tt; +SELECT GROUP_CONCAT(CHAR(value + 33 USING utf8mb4) SEPARATOR '') INTO @special_characters FROM PERCONA_SEQUENCE_TABLE(127 - 33) AS tt; SELECT @special_characters; @special_characters !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ diff --git a/mysql-test/suite/innodb_fts/r/percona_ft_special_chars_mecab_ewc_on.result b/mysql-test/suite/innodb_fts/r/percona_ft_special_chars_mecab_ewc_on.result index 084935bfb2f4..f0580642b4ce 100644 --- a/mysql-test/suite/innodb_fts/r/percona_ft_special_chars_mecab_ewc_on.result +++ b/mysql-test/suite/innodb_fts/r/percona_ft_special_chars_mecab_ewc_on.result @@ -71,7 +71,7 @@ test.t1 optimize status OK *** creating a list of all printable characters (ASCII 33..126) *** (whitespace and control characters are excluded) -SELECT GROUP_CONCAT(CHAR(value + 33 USING utf8mb4) SEPARATOR '') INTO @special_characters FROM SEQUENCE_TABLE(127 - 33) AS tt; +SELECT GROUP_CONCAT(CHAR(value + 33 USING utf8mb4) SEPARATOR '') INTO @special_characters FROM PERCONA_SEQUENCE_TABLE(127 - 33) AS tt; SELECT @special_characters; @special_characters !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ diff --git a/mysql-test/suite/innodb_fts/r/percona_ft_special_chars_ngram_ewc_off.result b/mysql-test/suite/innodb_fts/r/percona_ft_special_chars_ngram_ewc_off.result index 394d6dde11fa..0937259298ea 100644 --- a/mysql-test/suite/innodb_fts/r/percona_ft_special_chars_ngram_ewc_off.result +++ b/mysql-test/suite/innodb_fts/r/percona_ft_special_chars_ngram_ewc_off.result @@ -99,7 +99,7 @@ test.t1 optimize status OK *** creating a list of all printable characters (ASCII 33..126) *** (whitespace and control characters are excluded) -SELECT GROUP_CONCAT(CHAR(value + 33 USING utf8mb4) SEPARATOR '') INTO @special_characters FROM SEQUENCE_TABLE(127 - 33) AS tt; +SELECT GROUP_CONCAT(CHAR(value + 33 USING utf8mb4) SEPARATOR '') INTO @special_characters FROM PERCONA_SEQUENCE_TABLE(127 - 33) AS tt; SELECT @special_characters; @special_characters !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ diff --git a/mysql-test/suite/innodb_fts/r/percona_ft_special_chars_ngram_ewc_on.result b/mysql-test/suite/innodb_fts/r/percona_ft_special_chars_ngram_ewc_on.result index 4b3b917a53ae..133225cd55c9 100644 --- a/mysql-test/suite/innodb_fts/r/percona_ft_special_chars_ngram_ewc_on.result +++ b/mysql-test/suite/innodb_fts/r/percona_ft_special_chars_ngram_ewc_on.result @@ -99,7 +99,7 @@ test.t1 optimize status OK *** creating a list of all printable characters (ASCII 33..126) *** (whitespace and control characters are excluded) -SELECT GROUP_CONCAT(CHAR(value + 33 USING utf8mb4) SEPARATOR '') INTO @special_characters FROM SEQUENCE_TABLE(127 - 33) AS tt; +SELECT GROUP_CONCAT(CHAR(value + 33 USING utf8mb4) SEPARATOR '') INTO @special_characters FROM PERCONA_SEQUENCE_TABLE(127 - 33) AS tt; SELECT @special_characters; @special_characters !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ diff --git a/mysql-test/suite/percona/include/percona_sequence_table.inc b/mysql-test/suite/percona/include/percona_sequence_table.inc new file mode 100644 index 000000000000..4fcd08180370 --- /dev/null +++ b/mysql-test/suite/percona/include/percona_sequence_table.inc @@ -0,0 +1,28 @@ +# $st_field_expression - the list of fileds which will be passed to a SELECT $st_field_expression FROM ... +# $st_table_expression - a table function expression which will be passed to a SELECT ... FROM $st_table_expression +# (do not use single quotes here as they will not be interpolated properly by assert.inc) +# $st_where - optional WHERE clause that will be added to SELECT $st_field_expression FROM $st_table_expression +# $st_expected_number_of_records - an expected number of records returned +# $st_expected_signature - a comma-separated list of expected returned values +# $st_sort_order - sort_order: , ASC or DESC (used in GROUP_CONCAT() ORDER BY clause) + +--let $st_query_suffix = FROM $st_table_expression +if ($st_where) +{ + --let $st_query_suffix = $st_query_suffix WHERE $st_where +} + +--echo ### SELECT $st_field_expression $st_query_suffix ### +--eval SELECT $st_field_expression $st_query_suffix +--let $assert_cond = "[SELECT COUNT(*) $st_query_suffix]" = $st_expected_number_of_records +--let $assert_text = [SELECT COUNT(*) $st_query_suffix] should return $st_expected_number_of_records records +--source include/assert.inc + +--let $assert_cond = "[SELECT IFNULL(GROUP_CONCAT($st_field_expression ORDER BY 1 $st_sort_order SEPARATOR ","), "") $st_query_suffix]" = "$st_expected_signature" +--let $assert_text = [SELECT $st_field_expression $st_query_suffix] should return "$st_expected_signature" +--source include/assert.inc + +--eval EXPLAIN SELECT $st_field_expression $st_query_suffix +--eval EXPLAIN FORMAT=TREE SELECT $st_field_expression $st_query_suffix + +--echo diff --git a/mysql-test/suite/percona/r/sequence_table.result b/mysql-test/suite/percona/r/sequence_table.result new file mode 100644 index 000000000000..347ce3fb9e02 --- /dev/null +++ b/mysql-test/suite/percona/r/sequence_table.result @@ -0,0 +1,711 @@ +### +### Checking invalid PERCONA_SEQUENCE_TABLE() arguments +### +# no arguments +SELECT * FROM PERCONA_SEQUENCE_TABLE() AS tt; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ') AS tt' at line 1 +# two arguments +SELECT * FROM PERCONA_SEQUENCE_TABLE(1, 2) AS tt; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ', 2) AS tt' at line 1 +### +### Checking PERCONA_SEQUENCE_TABLE() without table alias +### +SELECT * FROM PERCONA_SEQUENCE_TABLE(4); +ERROR 42000: Every table function must have an alias +### +### Simple usage scenarios +### +### SELECT value FROM PERCONA_SEQUENCE_TABLE(0) AS tt ### +SELECT value FROM PERCONA_SEQUENCE_TABLE(0) AS tt; +value +include/assert.inc [[SELECT COUNT(*) FROM PERCONA_SEQUENCE_TABLE(0) AS tt] should return 0 records] +include/assert.inc [[SELECT value FROM PERCONA_SEQUENCE_TABLE(0) AS tt] should return ""] +EXPLAIN SELECT value FROM PERCONA_SEQUENCE_TABLE(0) AS tt; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tt NULL ALL NULL NULL NULL NULL 2 100.00 Table function: percona_sequence_table; Using temporary +Warnings: +Note 1003 /* select#1 */ select `tt`.`value` AS `value` from percona_sequence_table(0) `tt` +EXPLAIN FORMAT=TREE SELECT value FROM PERCONA_SEQUENCE_TABLE(0) AS tt; +EXPLAIN +-> Materialize table function (cost=2.73 rows=2) + + +### SELECT value FROM PERCONA_SEQUENCE_TABLE(1) AS tt ### +SELECT value FROM PERCONA_SEQUENCE_TABLE(1) AS tt; +value +0 +include/assert.inc [[SELECT COUNT(*) FROM PERCONA_SEQUENCE_TABLE(1) AS tt] should return 1 records] +include/assert.inc [[SELECT value FROM PERCONA_SEQUENCE_TABLE(1) AS tt] should return "0"] +EXPLAIN SELECT value FROM PERCONA_SEQUENCE_TABLE(1) AS tt; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tt NULL ALL NULL NULL NULL NULL 2 100.00 Table function: percona_sequence_table; Using temporary +Warnings: +Note 1003 /* select#1 */ select `tt`.`value` AS `value` from percona_sequence_table(1) `tt` +EXPLAIN FORMAT=TREE SELECT value FROM PERCONA_SEQUENCE_TABLE(1) AS tt; +EXPLAIN +-> Materialize table function (cost=2.73 rows=2) + + +### SELECT value FROM PERCONA_SEQUENCE_TABLE(4) AS tt ### +SELECT value FROM PERCONA_SEQUENCE_TABLE(4) AS tt; +value +0 +1 +2 +3 +include/assert.inc [[SELECT COUNT(*) FROM PERCONA_SEQUENCE_TABLE(4) AS tt] should return 4 records] +include/assert.inc [[SELECT value FROM PERCONA_SEQUENCE_TABLE(4) AS tt] should return "0,1,2,3"] +EXPLAIN SELECT value FROM PERCONA_SEQUENCE_TABLE(4) AS tt; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tt NULL ALL NULL NULL NULL NULL 2 100.00 Table function: percona_sequence_table; Using temporary +Warnings: +Note 1003 /* select#1 */ select `tt`.`value` AS `value` from percona_sequence_table(4) `tt` +EXPLAIN FORMAT=TREE SELECT value FROM PERCONA_SEQUENCE_TABLE(4) AS tt; +EXPLAIN +-> Materialize table function (cost=2.73 rows=2) + + +### +### Checking PERCONA_SEQUENCE_TABLE() max records limit +### +SET @saved_tf_sequence_table_max_upper_bound = @@global.tf_sequence_table_max_upper_bound; +SELECT * FROM PERCONA_SEQUENCE_TABLE(@saved_tf_sequence_table_max_upper_bound) AS tt; +SELECT * FROM PERCONA_SEQUENCE_TABLE(@saved_tf_sequence_table_max_upper_bound + 1) AS tt; +ERROR HY000: The number of records generated by PERCONA_SEQUENCE_TABLE() cannot exceed 1048576 (1048577 requested). Try increasing @@tf_sequence_table_max_upper_bound to a larger value. +SET GLOBAL tf_sequence_table_max_upper_bound = @saved_tf_sequence_table_max_upper_bound + 1; +SELECT * FROM PERCONA_SEQUENCE_TABLE(@saved_tf_sequence_table_max_upper_bound + 1) AS tt; +SELECT * FROM PERCONA_SEQUENCE_TABLE(@saved_tf_sequence_table_max_upper_bound + 2) AS tt; +ERROR HY000: The number of records generated by PERCONA_SEQUENCE_TABLE() cannot exceed 1048577 (1048578 requested). Try increasing @@tf_sequence_table_max_upper_bound to a larger value. +SET GLOBAL tf_sequence_table_max_upper_bound = @saved_tf_sequence_table_max_upper_bound; +### +### Checking PERCONA_SEQUENCE_TABLE() upper bound value conversions +### +# Negative numbers +### SELECT value FROM PERCONA_SEQUENCE_TABLE(-1) AS tt ### +SELECT value FROM PERCONA_SEQUENCE_TABLE(-1) AS tt; +value +include/assert.inc [[SELECT COUNT(*) FROM PERCONA_SEQUENCE_TABLE(-1) AS tt] should return 0 records] +include/assert.inc [[SELECT value FROM PERCONA_SEQUENCE_TABLE(-1) AS tt] should return ""] +EXPLAIN SELECT value FROM PERCONA_SEQUENCE_TABLE(-1) AS tt; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tt NULL ALL NULL NULL NULL NULL 2 100.00 Table function: percona_sequence_table; Using temporary +Warnings: +Note 1003 /* select#1 */ select `tt`.`value` AS `value` from percona_sequence_table(-(1)) `tt` +EXPLAIN FORMAT=TREE SELECT value FROM PERCONA_SEQUENCE_TABLE(-1) AS tt; +EXPLAIN +-> Materialize table function (cost=2.73 rows=2) + + +# NULL value +### SELECT value FROM PERCONA_SEQUENCE_TABLE(NULL) AS tt ### +SELECT value FROM PERCONA_SEQUENCE_TABLE(NULL) AS tt; +value +include/assert.inc [[SELECT COUNT(*) FROM PERCONA_SEQUENCE_TABLE(NULL) AS tt] should return 0 records] +include/assert.inc [[SELECT value FROM PERCONA_SEQUENCE_TABLE(NULL) AS tt] should return ""] +EXPLAIN SELECT value FROM PERCONA_SEQUENCE_TABLE(NULL) AS tt; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tt NULL ALL NULL NULL NULL NULL 2 100.00 Table function: percona_sequence_table; Using temporary +Warnings: +Note 1003 /* select#1 */ select `tt`.`value` AS `value` from percona_sequence_table(NULL) `tt` +EXPLAIN FORMAT=TREE SELECT value FROM PERCONA_SEQUENCE_TABLE(NULL) AS tt; +EXPLAIN +-> Materialize table function (cost=2.73 rows=2) + + +# Floating point numbers +### SELECT value FROM PERCONA_SEQUENCE_TABLE(2.5) AS tt ### +SELECT value FROM PERCONA_SEQUENCE_TABLE(2.5) AS tt; +value +0 +1 +2 +include/assert.inc [[SELECT COUNT(*) FROM PERCONA_SEQUENCE_TABLE(2.5) AS tt] should return 3 records] +include/assert.inc [[SELECT value FROM PERCONA_SEQUENCE_TABLE(2.5) AS tt] should return "0,1,2"] +EXPLAIN SELECT value FROM PERCONA_SEQUENCE_TABLE(2.5) AS tt; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tt NULL ALL NULL NULL NULL NULL 2 100.00 Table function: percona_sequence_table; Using temporary +Warnings: +Note 1003 /* select#1 */ select `tt`.`value` AS `value` from percona_sequence_table(2.5) `tt` +EXPLAIN FORMAT=TREE SELECT value FROM PERCONA_SEQUENCE_TABLE(2.5) AS tt; +EXPLAIN +-> Materialize table function (cost=2.73 rows=2) + + +### SELECT value FROM PERCONA_SEQUENCE_TABLE(0.15E1) AS tt ### +SELECT value FROM PERCONA_SEQUENCE_TABLE(0.15E1) AS tt; +value +0 +1 +include/assert.inc [[SELECT COUNT(*) FROM PERCONA_SEQUENCE_TABLE(0.15E1) AS tt] should return 2 records] +include/assert.inc [[SELECT value FROM PERCONA_SEQUENCE_TABLE(0.15E1) AS tt] should return "0,1"] +EXPLAIN SELECT value FROM PERCONA_SEQUENCE_TABLE(0.15E1) AS tt; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tt NULL ALL NULL NULL NULL NULL 2 100.00 Table function: percona_sequence_table; Using temporary +Warnings: +Note 1003 /* select#1 */ select `tt`.`value` AS `value` from percona_sequence_table(0.15E1) `tt` +EXPLAIN FORMAT=TREE SELECT value FROM PERCONA_SEQUENCE_TABLE(0.15E1) AS tt; +EXPLAIN +-> Materialize table function (cost=2.73 rows=2) + + +### SELECT value FROM PERCONA_SEQUENCE_TABLE(0.15E-1) AS tt ### +SELECT value FROM PERCONA_SEQUENCE_TABLE(0.15E-1) AS tt; +value +include/assert.inc [[SELECT COUNT(*) FROM PERCONA_SEQUENCE_TABLE(0.15E-1) AS tt] should return 0 records] +include/assert.inc [[SELECT value FROM PERCONA_SEQUENCE_TABLE(0.15E-1) AS tt] should return ""] +EXPLAIN SELECT value FROM PERCONA_SEQUENCE_TABLE(0.15E-1) AS tt; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tt NULL ALL NULL NULL NULL NULL 2 100.00 Table function: percona_sequence_table; Using temporary +Warnings: +Note 1003 /* select#1 */ select `tt`.`value` AS `value` from percona_sequence_table(0.15E-1) `tt` +EXPLAIN FORMAT=TREE SELECT value FROM PERCONA_SEQUENCE_TABLE(0.15E-1) AS tt; +EXPLAIN +-> Materialize table function (cost=2.73 rows=2) + + +# String values +### SELECT value FROM PERCONA_SEQUENCE_TABLE("") AS tt ### +SELECT value FROM PERCONA_SEQUENCE_TABLE("") AS tt; +value +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '' +include/assert.inc [[SELECT COUNT(*) FROM PERCONA_SEQUENCE_TABLE("") AS tt] should return 0 records] +include/assert.inc [[SELECT value FROM PERCONA_SEQUENCE_TABLE("") AS tt] should return ""] +EXPLAIN SELECT value FROM PERCONA_SEQUENCE_TABLE("") AS tt; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tt NULL ALL NULL NULL NULL NULL 2 100.00 Table function: percona_sequence_table; Using temporary +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '' +Note 1003 /* select#1 */ select `tt`.`value` AS `value` from percona_sequence_table('') `tt` +EXPLAIN FORMAT=TREE SELECT value FROM PERCONA_SEQUENCE_TABLE("") AS tt; +EXPLAIN +-> Materialize table function (cost=2.73 rows=2) + +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '' + +### SELECT value FROM PERCONA_SEQUENCE_TABLE(" ") AS tt ### +SELECT value FROM PERCONA_SEQUENCE_TABLE(" ") AS tt; +value +Warnings: +Warning 1292 Truncated incorrect INTEGER value: ' ' +include/assert.inc [[SELECT COUNT(*) FROM PERCONA_SEQUENCE_TABLE(" ") AS tt] should return 0 records] +include/assert.inc [[SELECT value FROM PERCONA_SEQUENCE_TABLE(" ") AS tt] should return ""] +EXPLAIN SELECT value FROM PERCONA_SEQUENCE_TABLE(" ") AS tt; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tt NULL ALL NULL NULL NULL NULL 2 100.00 Table function: percona_sequence_table; Using temporary +Warnings: +Warning 1292 Truncated incorrect INTEGER value: ' ' +Note 1003 /* select#1 */ select `tt`.`value` AS `value` from percona_sequence_table(' ') `tt` +EXPLAIN FORMAT=TREE SELECT value FROM PERCONA_SEQUENCE_TABLE(" ") AS tt; +EXPLAIN +-> Materialize table function (cost=2.73 rows=2) + +Warnings: +Warning 1292 Truncated incorrect INTEGER value: ' ' + +### SELECT value FROM PERCONA_SEQUENCE_TABLE("2") AS tt ### +SELECT value FROM PERCONA_SEQUENCE_TABLE("2") AS tt; +value +0 +1 +include/assert.inc [[SELECT COUNT(*) FROM PERCONA_SEQUENCE_TABLE("2") AS tt] should return 2 records] +include/assert.inc [[SELECT value FROM PERCONA_SEQUENCE_TABLE("2") AS tt] should return "0,1"] +EXPLAIN SELECT value FROM PERCONA_SEQUENCE_TABLE("2") AS tt; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tt NULL ALL NULL NULL NULL NULL 2 100.00 Table function: percona_sequence_table; Using temporary +Warnings: +Note 1003 /* select#1 */ select `tt`.`value` AS `value` from percona_sequence_table('2') `tt` +EXPLAIN FORMAT=TREE SELECT value FROM PERCONA_SEQUENCE_TABLE("2") AS tt; +EXPLAIN +-> Materialize table function (cost=2.73 rows=2) + + +### +### Checking PERCONA_SEQUENCE_TABLE() upper bound expressions +### +# Session variables +SET @a = 4; +### SELECT value FROM PERCONA_SEQUENCE_TABLE(@a) AS tt ### +SELECT value FROM PERCONA_SEQUENCE_TABLE(@a) AS tt; +value +0 +1 +2 +3 +include/assert.inc [[SELECT COUNT(*) FROM PERCONA_SEQUENCE_TABLE(@a) AS tt] should return 4 records] +include/assert.inc [[SELECT value FROM PERCONA_SEQUENCE_TABLE(@a) AS tt] should return "0,1,2,3"] +EXPLAIN SELECT value FROM PERCONA_SEQUENCE_TABLE(@a) AS tt; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tt NULL ALL NULL NULL NULL NULL 2 100.00 Table function: percona_sequence_table; Using temporary +Warnings: +Note 1003 /* select#1 */ select `tt`.`value` AS `value` from percona_sequence_table((@`a`)) `tt` +EXPLAIN FORMAT=TREE SELECT value FROM PERCONA_SEQUENCE_TABLE(@a) AS tt; +EXPLAIN +-> Materialize table function (cost=2.73 rows=2) + + +SET @a = 3; +### SELECT value FROM PERCONA_SEQUENCE_TABLE(@a) AS tt ### +SELECT value FROM PERCONA_SEQUENCE_TABLE(@a) AS tt; +value +0 +1 +2 +include/assert.inc [[SELECT COUNT(*) FROM PERCONA_SEQUENCE_TABLE(@a) AS tt] should return 3 records] +include/assert.inc [[SELECT value FROM PERCONA_SEQUENCE_TABLE(@a) AS tt] should return "0,1,2"] +EXPLAIN SELECT value FROM PERCONA_SEQUENCE_TABLE(@a) AS tt; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tt NULL ALL NULL NULL NULL NULL 2 100.00 Table function: percona_sequence_table; Using temporary +Warnings: +Note 1003 /* select#1 */ select `tt`.`value` AS `value` from percona_sequence_table((@`a`)) `tt` +EXPLAIN FORMAT=TREE SELECT value FROM PERCONA_SEQUENCE_TABLE(@a) AS tt; +EXPLAIN +-> Materialize table function (cost=2.73 rows=2) + + +# Simple arithmetic expressions +SET @a = 2; +### SELECT value FROM PERCONA_SEQUENCE_TABLE(@a * @a - 1) AS tt ### +SELECT value FROM PERCONA_SEQUENCE_TABLE(@a * @a - 1) AS tt; +value +0 +1 +2 +include/assert.inc [[SELECT COUNT(*) FROM PERCONA_SEQUENCE_TABLE(@a * @a - 1) AS tt] should return 3 records] +include/assert.inc [[SELECT value FROM PERCONA_SEQUENCE_TABLE(@a * @a - 1) AS tt] should return "0,1,2"] +EXPLAIN SELECT value FROM PERCONA_SEQUENCE_TABLE(@a * @a - 1) AS tt; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tt NULL ALL NULL NULL NULL NULL 2 100.00 Table function: percona_sequence_table; Using temporary +Warnings: +Note 1003 /* select#1 */ select `tt`.`value` AS `value` from percona_sequence_table((((@`a`) * (@`a`)) - 1)) `tt` +EXPLAIN FORMAT=TREE SELECT value FROM PERCONA_SEQUENCE_TABLE(@a * @a - 1) AS tt; +EXPLAIN +-> Materialize table function (cost=2.73 rows=2) + + +SET @a = 1; +### SELECT value FROM PERCONA_SEQUENCE_TABLE(EXP(@a) - 1) AS tt ### +SELECT value FROM PERCONA_SEQUENCE_TABLE(EXP(@a) - 1) AS tt; +value +0 +1 +include/assert.inc [[SELECT COUNT(*) FROM PERCONA_SEQUENCE_TABLE(EXP(@a) - 1) AS tt] should return 2 records] +include/assert.inc [[SELECT value FROM PERCONA_SEQUENCE_TABLE(EXP(@a) - 1) AS tt] should return "0,1"] +EXPLAIN SELECT value FROM PERCONA_SEQUENCE_TABLE(EXP(@a) - 1) AS tt; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tt NULL ALL NULL NULL NULL NULL 2 100.00 Table function: percona_sequence_table; Using temporary +Warnings: +Note 1003 /* select#1 */ select `tt`.`value` AS `value` from percona_sequence_table((exp((@`a`)) - 1)) `tt` +EXPLAIN FORMAT=TREE SELECT value FROM PERCONA_SEQUENCE_TABLE(EXP(@a) - 1) AS tt; +EXPLAIN +-> Materialize table function (cost=2.73 rows=2) + + +### +### Checking PERCONA_SEQUENCE_TABLE() with WHERE clause +### +# Point selection +### SELECT value FROM PERCONA_SEQUENCE_TABLE(4) AS tt WHERE value = 1 ### +SELECT value FROM PERCONA_SEQUENCE_TABLE(4) AS tt WHERE value = 1; +value +1 +include/assert.inc [[SELECT COUNT(*) FROM PERCONA_SEQUENCE_TABLE(4) AS tt WHERE value = 1] should return 1 records] +include/assert.inc [[SELECT value FROM PERCONA_SEQUENCE_TABLE(4) AS tt WHERE value = 1] should return "1"] +EXPLAIN SELECT value FROM PERCONA_SEQUENCE_TABLE(4) AS tt WHERE value = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tt NULL ref 8 const 1 100.00 Table function: percona_sequence_table; Using temporary; Using index +Warnings: +Note 1003 /* select#1 */ select `tt`.`value` AS `value` from percona_sequence_table(4) `tt` where (`tt`.`value` = 1) +EXPLAIN FORMAT=TREE SELECT value FROM PERCONA_SEQUENCE_TABLE(4) AS tt WHERE value = 1; +EXPLAIN +-> Materialize table function (cost=0.35 rows=1) + + +# Range selection +### SELECT value FROM PERCONA_SEQUENCE_TABLE(4) AS tt WHERE value > 1 ### +SELECT value FROM PERCONA_SEQUENCE_TABLE(4) AS tt WHERE value > 1; +value +2 +3 +include/assert.inc [[SELECT COUNT(*) FROM PERCONA_SEQUENCE_TABLE(4) AS tt WHERE value > 1] should return 2 records] +include/assert.inc [[SELECT value FROM PERCONA_SEQUENCE_TABLE(4) AS tt WHERE value > 1] should return "2,3"] +EXPLAIN SELECT value FROM PERCONA_SEQUENCE_TABLE(4) AS tt WHERE value > 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tt NULL ALL NULL NULL NULL NULL 2 50.00 Table function: percona_sequence_table; Using temporary; Using where +Warnings: +Note 1003 /* select#1 */ select `tt`.`value` AS `value` from percona_sequence_table(4) `tt` where (`tt`.`value` > 1) +EXPLAIN FORMAT=TREE SELECT value FROM PERCONA_SEQUENCE_TABLE(4) AS tt WHERE value > 1; +EXPLAIN +-> Filter: (tt.`value` > 1) (cost=2.73 rows=1) + -> Materialize table function (cost=2.73 rows=2) + + +# Every second record +### SELECT value FROM PERCONA_SEQUENCE_TABLE(4) AS tt WHERE value %2 = 0 ### +SELECT value FROM PERCONA_SEQUENCE_TABLE(4) AS tt WHERE value %2 = 0; +value +0 +2 +include/assert.inc [[SELECT COUNT(*) FROM PERCONA_SEQUENCE_TABLE(4) AS tt WHERE value %2 = 0] should return 2 records] +include/assert.inc [[SELECT value FROM PERCONA_SEQUENCE_TABLE(4) AS tt WHERE value %2 = 0] should return "0,2"] +EXPLAIN SELECT value FROM PERCONA_SEQUENCE_TABLE(4) AS tt WHERE value %2 = 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tt NULL ALL NULL NULL NULL NULL 2 100.00 Table function: percona_sequence_table; Using temporary; Using where +Warnings: +Note 1003 /* select#1 */ select `tt`.`value` AS `value` from percona_sequence_table(4) `tt` where ((`tt`.`value` % 2) = 0) +EXPLAIN FORMAT=TREE SELECT value FROM PERCONA_SEQUENCE_TABLE(4) AS tt WHERE value %2 = 0; +EXPLAIN +-> Filter: ((tt.`value` % 2) = 0) (cost=2.73 rows=2) + -> Materialize table function (cost=2.73 rows=2) + + +### +### Selecting custom value expressions from PERCONA_SEQUENCE_TABLE() +### +# Shifted values +### SELECT value + 1 FROM PERCONA_SEQUENCE_TABLE(4) AS tt ### +SELECT value + 1 FROM PERCONA_SEQUENCE_TABLE(4) AS tt; +value + 1 +1 +2 +3 +4 +include/assert.inc [[SELECT COUNT(*) FROM PERCONA_SEQUENCE_TABLE(4) AS tt] should return 4 records] +include/assert.inc [[SELECT value + 1 FROM PERCONA_SEQUENCE_TABLE(4) AS tt] should return "1,2,3,4"] +EXPLAIN SELECT value + 1 FROM PERCONA_SEQUENCE_TABLE(4) AS tt; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tt NULL ALL NULL NULL NULL NULL 2 100.00 Table function: percona_sequence_table; Using temporary +Warnings: +Note 1003 /* select#1 */ select (`tt`.`value` + 1) AS `value + 1` from percona_sequence_table(4) `tt` +EXPLAIN FORMAT=TREE SELECT value + 1 FROM PERCONA_SEQUENCE_TABLE(4) AS tt; +EXPLAIN +-> Materialize table function (cost=2.73 rows=2) + + +# Odd numbers +### SELECT value * 2 + 1 FROM PERCONA_SEQUENCE_TABLE(4) AS tt ### +SELECT value * 2 + 1 FROM PERCONA_SEQUENCE_TABLE(4) AS tt; +value * 2 + 1 +1 +3 +5 +7 +include/assert.inc [[SELECT COUNT(*) FROM PERCONA_SEQUENCE_TABLE(4) AS tt] should return 4 records] +include/assert.inc [[SELECT value * 2 + 1 FROM PERCONA_SEQUENCE_TABLE(4) AS tt] should return "1,3,5,7"] +EXPLAIN SELECT value * 2 + 1 FROM PERCONA_SEQUENCE_TABLE(4) AS tt; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tt NULL ALL NULL NULL NULL NULL 2 100.00 Table function: percona_sequence_table; Using temporary +Warnings: +Note 1003 /* select#1 */ select ((`tt`.`value` * 2) + 1) AS `value * 2 + 1` from percona_sequence_table(4) `tt` +EXPLAIN FORMAT=TREE SELECT value * 2 + 1 FROM PERCONA_SEQUENCE_TABLE(4) AS tt; +EXPLAIN +-> Materialize table function (cost=2.73 rows=2) + + +# Reverse order +### SELECT 7 - value FROM PERCONA_SEQUENCE_TABLE(4) AS tt ### +SELECT 7 - value FROM PERCONA_SEQUENCE_TABLE(4) AS tt; +7 - value +7 +6 +5 +4 +include/assert.inc [[SELECT COUNT(*) FROM PERCONA_SEQUENCE_TABLE(4) AS tt] should return 4 records] +include/assert.inc [[SELECT 7 - value FROM PERCONA_SEQUENCE_TABLE(4) AS tt] should return "7,6,5,4"] +EXPLAIN SELECT 7 - value FROM PERCONA_SEQUENCE_TABLE(4) AS tt; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tt NULL ALL NULL NULL NULL NULL 2 100.00 Table function: percona_sequence_table; Using temporary +Warnings: +Note 1003 /* select#1 */ select (7 - `tt`.`value`) AS `7 - value` from percona_sequence_table(4) `tt` +EXPLAIN FORMAT=TREE SELECT 7 - value FROM PERCONA_SEQUENCE_TABLE(4) AS tt; +EXPLAIN +-> Materialize table function (cost=2.73 rows=2) + + +# Mapping with ELT() +### SELECT ELT(value + 1, "a", "b", "c", "d") FROM PERCONA_SEQUENCE_TABLE(4) AS tt ### +SELECT ELT(value + 1, "a", "b", "c", "d") FROM PERCONA_SEQUENCE_TABLE(4) AS tt; +ELT(value + 1, "a", "b", "c", "d") +a +b +c +d +include/assert.inc [[SELECT COUNT(*) FROM PERCONA_SEQUENCE_TABLE(4) AS tt] should return 4 records] +include/assert.inc [[SELECT ELT(value + 1, "a", "b", "c", "d") FROM PERCONA_SEQUENCE_TABLE(4) AS tt] should return "a,b,c,d"] +EXPLAIN SELECT ELT(value + 1, "a", "b", "c", "d") FROM PERCONA_SEQUENCE_TABLE(4) AS tt; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tt NULL ALL NULL NULL NULL NULL 2 100.00 Table function: percona_sequence_table; Using temporary +Warnings: +Note 1003 /* select#1 */ select elt((`tt`.`value` + 1),'a','b','c','d') AS `ELT(value + 1, "a", "b", "c", "d")` from percona_sequence_table(4) `tt` +EXPLAIN FORMAT=TREE SELECT ELT(value + 1, "a", "b", "c", "d") FROM PERCONA_SEQUENCE_TABLE(4) AS tt; +EXPLAIN +-> Materialize table function (cost=2.73 rows=2) + + +### +### Checking VIEWs based on PERCONA_SEQUENCE_TABLE() +### +CREATE VIEW v1 AS SELECT * FROM PERCONA_SEQUENCE_TABLE(4) AS tt; +SHOW CREATE VIEW v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `tt`.`value` AS `value` from percona_sequence_table(4) `tt` utf8mb4 utf8mb4_0900_ai_ci +### SELECT value FROM v1 ### +SELECT value FROM v1; +value +0 +1 +2 +3 +include/assert.inc [[SELECT COUNT(*) FROM v1] should return 4 records] +include/assert.inc [[SELECT value FROM v1] should return "0,1,2,3"] +EXPLAIN SELECT value FROM v1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tt NULL ALL NULL NULL NULL NULL 2 100.00 Table function: percona_sequence_table; Using temporary +Warnings: +Note 1003 /* select#1 */ select `tt`.`value` AS `value` from percona_sequence_table(4) `tt` +EXPLAIN FORMAT=TREE SELECT value FROM v1; +EXPLAIN +-> Materialize table function (cost=2.73 rows=2) + + +DROP VIEW v1; +### +### Checking stored procedures / functions +### +# Stored procedure +CREATE PROCEDURE p1(upper_bound BIGINT UNSIGNED) SELECT * FROM PERCONA_SEQUENCE_TABLE(upper_bound) AS tt; +CALL p1(4); +value +0 +1 +2 +3 +DROP PROCEDURE p1; +# Stored function +CREATE FUNCTION f1(upper_bound BIGINT UNSIGNED) RETURNS BIGINT UNSIGNED +BEGIN +DECLARE res BIGINT UNSIGNED; +SELECT SUM(value) INTO res FROM PERCONA_SEQUENCE_TABLE(upper_bound) AS tt; +RETURN res; +END| +include/assert.inc [SUM(0, ..., 3) should be 6] +SELECT f1(4); +f1(4) +6 +DROP FUNCTION f1; +### +### Checking prepared statements +### +PREPARE stmt1 FROM 'SELECT * FROM PERCONA_SEQUENCE_TABLE(?) AS tt'; +SET @a = 4; +EXECUTE stmt1 USING @a; +value +0 +1 +2 +3 +DEALLOCATE PREPARE stmt1; +### +### Checking SHOW CREATE TABLE +### +CREATE TABLE t1 AS SELECT value AS a FROM PERCONA_SEQUENCE_TABLE(3) AS tt; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bigint unsigned NOT NULL DEFAULT '0' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci +### +### Checking table joins +### +# Constant upper_bound +### SELECT t1.a * 10 + value FROM t1, PERCONA_SEQUENCE_TABLE(3) AS tt ### +SELECT t1.a * 10 + value FROM t1, PERCONA_SEQUENCE_TABLE(3) AS tt; +t1.a * 10 + value +2 +1 +0 +12 +11 +10 +22 +21 +20 +include/assert.inc [[SELECT COUNT(*) FROM t1, PERCONA_SEQUENCE_TABLE(3) AS tt] should return 9 records] +include/assert.inc [[SELECT t1.a * 10 + value FROM t1, PERCONA_SEQUENCE_TABLE(3) AS tt] should return "0,1,2,10,11,12,20,21,22"] +EXPLAIN SELECT t1.a * 10 + value FROM t1, PERCONA_SEQUENCE_TABLE(3) AS tt; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tt NULL ALL NULL NULL NULL NULL 2 100.00 Table function: percona_sequence_table; Using temporary +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using join buffer (hash join) +Warnings: +Note 1003 /* select#1 */ select ((`test`.`t1`.`a` * 10) + `tt`.`value`) AS `t1.a * 10 + value` from `test`.`t1` join percona_sequence_table(3) `tt` +EXPLAIN FORMAT=TREE SELECT t1.a * 10 + value FROM t1, PERCONA_SEQUENCE_TABLE(3) AS tt; +EXPLAIN +-> Inner hash join (no condition) (cost=3.58 rows=6) + -> Table scan on t1 (cost=0.275 rows=3) + -> Hash + -> Materialize table function (cost=2.73 rows=2) + + +# Join with UNION-based row set +### SELECT tt1.a * 10 + value FROM (SELECT 0 AS a UNION SELECT 1 UNION SELECT 2) AS tt1, PERCONA_SEQUENCE_TABLE(3) AS tt2 ### +SELECT tt1.a * 10 + value FROM (SELECT 0 AS a UNION SELECT 1 UNION SELECT 2) AS tt1, PERCONA_SEQUENCE_TABLE(3) AS tt2; +tt1.a * 10 + value +2 +1 +0 +12 +11 +10 +22 +21 +20 +include/assert.inc [[SELECT COUNT(*) FROM (SELECT 0 AS a UNION SELECT 1 UNION SELECT 2) AS tt1, PERCONA_SEQUENCE_TABLE(3) AS tt2] should return 9 records] +include/assert.inc [[SELECT tt1.a * 10 + value FROM (SELECT 0 AS a UNION SELECT 1 UNION SELECT 2) AS tt1, PERCONA_SEQUENCE_TABLE(3) AS tt2] should return "0,1,2,10,11,12,20,21,22"] +EXPLAIN SELECT tt1.a * 10 + value FROM (SELECT 0 AS a UNION SELECT 1 UNION SELECT 2) AS tt1, PERCONA_SEQUENCE_TABLE(3) AS tt2; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 PRIMARY tt2 NULL ALL NULL NULL NULL NULL 2 100.00 Table function: percona_sequence_table; Using temporary +1 PRIMARY NULL ALL NULL NULL NULL NULL 3 100.00 Using join buffer (hash join) +2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used +3 UNION NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used +4 UNION NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used +5 UNION RESULT NULL ALL NULL NULL NULL NULL NULL NULL Using temporary +Warnings: +Note 1003 /* select#1 */ select ((`tt1`.`a` * 10) + `tt2`.`value`) AS `tt1.a * 10 + value` from (/* select#2 */ select 0 AS `a` union /* select#3 */ select 1 AS `1` union /* select#4 */ select 2 AS `2`) `tt1` join percona_sequence_table(3) `tt2` +EXPLAIN FORMAT=TREE SELECT tt1.a * 10 + value FROM (SELECT 0 AS a UNION SELECT 1 UNION SELECT 2) AS tt1, PERCONA_SEQUENCE_TABLE(3) AS tt2; +EXPLAIN +-> Inner hash join (no condition) (cost=5.86 rows=6) + -> Table scan on tt1 (cost=1.15..2.84 rows=3) + -> Union materialize with deduplication (cost=0.3..0.3 rows=3) + -> Rows fetched before execution (cost=0..0 rows=1) + -> Rows fetched before execution (cost=0..0 rows=1) + -> Rows fetched before execution (cost=0..0 rows=1) + -> Hash + -> Materialize table function (cost=2.73 rows=2) + + +# Join with VALUES ROW-based row set +### SELECT tt1.column_0 * 10 + value FROM (VALUES ROW(0), ROW(1), ROW(2)) AS tt1, PERCONA_SEQUENCE_TABLE(3) AS tt2 ### +SELECT tt1.column_0 * 10 + value FROM (VALUES ROW(0), ROW(1), ROW(2)) AS tt1, PERCONA_SEQUENCE_TABLE(3) AS tt2; +tt1.column_0 * 10 + value +2 +1 +0 +12 +11 +10 +22 +21 +20 +include/assert.inc [[SELECT COUNT(*) FROM (VALUES ROW(0), ROW(1), ROW(2)) AS tt1, PERCONA_SEQUENCE_TABLE(3) AS tt2] should return 9 records] +include/assert.inc [[SELECT tt1.column_0 * 10 + value FROM (VALUES ROW(0), ROW(1), ROW(2)) AS tt1, PERCONA_SEQUENCE_TABLE(3) AS tt2] should return "0,1,2,10,11,12,20,21,22"] +EXPLAIN SELECT tt1.column_0 * 10 + value FROM (VALUES ROW(0), ROW(1), ROW(2)) AS tt1, PERCONA_SEQUENCE_TABLE(3) AS tt2; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 PRIMARY tt2 NULL ALL NULL NULL NULL NULL 2 100.00 Table function: percona_sequence_table; Using temporary +1 PRIMARY NULL ALL NULL NULL NULL NULL 3 100.00 Using join buffer (hash join) +2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 /* select#1 */ select ((`tt1`.`column_0` * 10) + `tt2`.`value`) AS `tt1.column_0 * 10 + value` from (values row(0),row(1),row(2)) `tt1` join percona_sequence_table(3) `tt2` +EXPLAIN FORMAT=TREE SELECT tt1.column_0 * 10 + value FROM (VALUES ROW(0), ROW(1), ROW(2)) AS tt1, PERCONA_SEQUENCE_TABLE(3) AS tt2; +EXPLAIN +-> Inner hash join (no condition) (cost=5.86 rows=6) + -> Table scan on tt1 (cost=1.15..2.84 rows=3) + -> Materialize (cost=0.3..0.3 rows=3) + -> Rows fetched before execution (cost=0..0 rows=3) + -> Hash + -> Materialize table function (cost=2.73 rows=2) + + +# Join with derived SELECT +### SELECT tt1.a * 10 + value FROM (SELECT * FROM t1) AS tt1, PERCONA_SEQUENCE_TABLE(3) AS tt2 ### +SELECT tt1.a * 10 + value FROM (SELECT * FROM t1) AS tt1, PERCONA_SEQUENCE_TABLE(3) AS tt2; +tt1.a * 10 + value +2 +1 +0 +12 +11 +10 +22 +21 +20 +include/assert.inc [[SELECT COUNT(*) FROM (SELECT * FROM t1) AS tt1, PERCONA_SEQUENCE_TABLE(3) AS tt2] should return 9 records] +include/assert.inc [[SELECT tt1.a * 10 + value FROM (SELECT * FROM t1) AS tt1, PERCONA_SEQUENCE_TABLE(3) AS tt2] should return "0,1,2,10,11,12,20,21,22"] +EXPLAIN SELECT tt1.a * 10 + value FROM (SELECT * FROM t1) AS tt1, PERCONA_SEQUENCE_TABLE(3) AS tt2; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tt2 NULL ALL NULL NULL NULL NULL 2 100.00 Table function: percona_sequence_table; Using temporary +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using join buffer (hash join) +Warnings: +Note 1003 /* select#1 */ select ((`test`.`t1`.`a` * 10) + `tt2`.`value`) AS `tt1.a * 10 + value` from `test`.`t1` join percona_sequence_table(3) `tt2` +EXPLAIN FORMAT=TREE SELECT tt1.a * 10 + value FROM (SELECT * FROM t1) AS tt1, PERCONA_SEQUENCE_TABLE(3) AS tt2; +EXPLAIN +-> Inner hash join (no condition) (cost=3.58 rows=6) + -> Table scan on t1 (cost=0.275 rows=3) + -> Hash + -> Materialize table function (cost=2.73 rows=2) + + +# Join with derived TABLE +### SELECT tt1.a * 10 + value FROM (TABLE t1) AS tt1, PERCONA_SEQUENCE_TABLE(3) AS tt2 ### +SELECT tt1.a * 10 + value FROM (TABLE t1) AS tt1, PERCONA_SEQUENCE_TABLE(3) AS tt2; +tt1.a * 10 + value +2 +1 +0 +12 +11 +10 +22 +21 +20 +include/assert.inc [[SELECT COUNT(*) FROM (TABLE t1) AS tt1, PERCONA_SEQUENCE_TABLE(3) AS tt2] should return 9 records] +include/assert.inc [[SELECT tt1.a * 10 + value FROM (TABLE t1) AS tt1, PERCONA_SEQUENCE_TABLE(3) AS tt2] should return "0,1,2,10,11,12,20,21,22"] +EXPLAIN SELECT tt1.a * 10 + value FROM (TABLE t1) AS tt1, PERCONA_SEQUENCE_TABLE(3) AS tt2; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tt2 NULL ALL NULL NULL NULL NULL 2 100.00 Table function: percona_sequence_table; Using temporary +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using join buffer (hash join) +Warnings: +Note 1003 /* select#1 */ select ((`test`.`t1`.`a` * 10) + `tt2`.`value`) AS `tt1.a * 10 + value` from `test`.`t1` join percona_sequence_table(3) `tt2` +EXPLAIN FORMAT=TREE SELECT tt1.a * 10 + value FROM (TABLE t1) AS tt1, PERCONA_SEQUENCE_TABLE(3) AS tt2; +EXPLAIN +-> Inner hash join (no condition) (cost=3.58 rows=6) + -> Table scan on t1 (cost=0.275 rows=3) + -> Hash + -> Materialize table function (cost=2.73 rows=2) + + +# Dependent upper_bound +### SELECT t1.a * 10 + value FROM t1, PERCONA_SEQUENCE_TABLE(a + 1) AS tt ### +SELECT t1.a * 10 + value FROM t1, PERCONA_SEQUENCE_TABLE(a + 1) AS tt; +t1.a * 10 + value +0 +10 +11 +20 +21 +22 +include/assert.inc [[SELECT COUNT(*) FROM t1, PERCONA_SEQUENCE_TABLE(a + 1) AS tt] should return 6 records] +include/assert.inc [[SELECT t1.a * 10 + value FROM t1, PERCONA_SEQUENCE_TABLE(a + 1) AS tt] should return "0,10,11,20,21,22"] +EXPLAIN SELECT t1.a * 10 + value FROM t1, PERCONA_SEQUENCE_TABLE(a + 1) AS tt; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 NULL +1 SIMPLE tt NULL ALL NULL NULL NULL NULL 2 100.00 Table function: percona_sequence_table; Using temporary +Warnings: +Note 1003 /* select#1 */ select ((`test`.`t1`.`a` * 10) + `tt`.`value`) AS `t1.a * 10 + value` from `test`.`t1` join percona_sequence_table((`test`.`t1`.`a` + 1)) `tt` +EXPLAIN FORMAT=TREE SELECT t1.a * 10 + value FROM t1, PERCONA_SEQUENCE_TABLE(a + 1) AS tt; +EXPLAIN +-> Nested loop inner join (cost=3.68 rows=6) + -> Table scan on t1 (cost=0.55 rows=3) + -> Materialize table function (cost=0.908 rows=2) + + +### +### Checking for various forbidden upper_bound constructs +### +# Derived SELECT +SELECT * FROM PERCONA_SEQUENCE_TABLE((SELECT 1)) AS tt; +ERROR HY000: Incorrect arguments to PERCONA_SEQUENCE_TABLE +# Aggregate function +SELECT * FROM PERCONA_SEQUENCE_TABLE(SUM(1)) AS tt; +ERROR HY000: Invalid use of group function +DROP TABLE t1; diff --git a/mysql-test/suite/percona/r/sequence_table_keyword.result b/mysql-test/suite/percona/r/sequence_table_keyword.result new file mode 100644 index 000000000000..602a07fa3508 --- /dev/null +++ b/mysql-test/suite/percona/r/sequence_table_keyword.result @@ -0,0 +1,163 @@ +CREATE TABLE t1(id INT UNSIGNED) ENGINE=InnoDB; +INSERT INTO t1 VALUES(1); +CREATE TABLE percona_sequence_table(id INT UNSIGNED) ENGINE=InnoDB; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'percona_sequence_table(id INT UNSIGNED) ENGINE=InnoDB' at line 1 +CREATE TABLE sequence_table(id INT UNSIGNED) ENGINE=InnoDB; +INSERT INTO sequence_table VALUES (1); +INSERT INTO sequence_table VALUES (2); +SELECT * FROM sequence_table; +id +1 +2 +SELECT * FROM sequence_table AS tt; +id +1 +2 +SELECT * FROM sequence_table tt; +id +1 +2 +SELECT * FROM (sequence_table); +id +1 +2 +SELECT * FROM (sequence_table AS tt); +id +1 +2 +SELECT * FROM (sequence_table tt); +id +1 +2 +SELECT * FROM (SELECT * FROM t1) AS sequence_table; +id +1 +SELECT * FROM (SELECT * FROM t1) sequence_table; +id +1 +SELECT sequence_table.* FROM (SELECT * FROM t1) AS sequence_table; +id +1 +SELECT sequence_table.* FROM (SELECT * FROM t1) sequence_table; +id +1 +SELECT * FROM (SELECT * FROM t1) AS sequence_table(val); +val +1 +SELECT * FROM (SELECT * FROM t1) sequence_table(val); +val +1 +SELECT sequence_table.* FROM (SELECT * FROM t1) AS sequence_table(val); +val +1 +SELECT sequence_table.* FROM (SELECT * FROM t1) sequence_table(val); +val +1 +SELECT sequence_table.val FROM (SELECT * FROM t1) AS sequence_table(val); +val +1 +SELECT sequence_table.val FROM (SELECT * FROM t1) sequence_table(val); +val +1 +SELECT val FROM (SELECT * FROM t1) AS sequence_table(val); +val +1 +SELECT val FROM (SELECT * FROM t1) sequence_table(val); +val +1 +SELECT * FROM (SELECT * FROM t1) AS tt(sequence_table); +sequence_table +1 +SELECT * FROM (SELECT * FROM t1) tt(sequence_table); +sequence_table +1 +SELECT tt.sequence_table FROM (SELECT * FROM t1) AS tt(sequence_table); +sequence_table +1 +SELECT tt.sequence_table FROM (SELECT * FROM t1) tt(sequence_table); +sequence_table +1 +SELECT sequence_table FROM (SELECT * FROM t1) AS tt(sequence_table); +sequence_table +1 +SELECT sequence_table FROM (SELECT * FROM t1) tt(sequence_table); +sequence_table +1 +SELECT * FROM (SELECT * FROM t1) AS sequence_table(sequence_table); +sequence_table +1 +SELECT * FROM (SELECT * FROM t1) sequence_table(sequence_table); +sequence_table +1 +SELECT sequence_table.sequence_table FROM (SELECT * FROM t1) AS sequence_table(sequence_table); +sequence_table +1 +SELECT sequence_table.sequence_table FROM (SELECT * FROM t1) sequence_table(sequence_table); +sequence_table +1 +SELECT sequence_table FROM (SELECT * FROM t1) AS sequence_table(sequence_table); +sequence_table +1 +SELECT sequence_table FROM (SELECT * FROM t1) sequence_table(sequence_table); +sequence_table +1 +SELECT * FROM t1 AS sequence_table; +id +1 +SELECT * FROM t1 sequence_table; +id +1 +SELECT * FROM t1 AS sequence_table WHERE id = 1; +id +1 +SELECT * FROM t1 sequence_table WHERE id = 1; +id +1 +SELECT * FROM t1 AS sequence_table WHERE sequence_table.id = 1; +id +1 +SELECT * FROM t1 sequence_table WHERE sequence_table.id = 1; +id +1 +SELECT * FROM SEQUENCE_TABLE(2) AS tt; +value +0 +1 +SELECT * FROM SEQUENCE_TABLE(2) tt; +value +0 +1 +SELECT * FROM SEQUENCE_TABLE(2) AS sequence_table; +value +0 +1 +SELECT sequence_table.* FROM SEQUENCE_TABLE(2) AS sequence_table; +value +0 +1 +SELECT value FROM SEQUENCE_TABLE(2) AS sequence_table; +value +0 +1 +SELECT sequence_table.value FROM SEQUENCE_TABLE(2) AS sequence_table; +value +0 +1 +SELECT * FROM sequence_table, SEQUENCE_TABLE(2) AS tt; +id value +2 0 +1 0 +2 1 +1 1 +INSERT INTO sequence_table VALUES (3); +INSERT INTO sequence_table SELECT value + 4 FROM SEQUENCE_TABLE(2) AS tt; +INSERT INTO t1 SELECT * FROM sequence_table; +UPDATE sequence_table SET id = id + 100; +UPDATE sequence_table SET id = id + 100 WHERE id IN (SELECT * FROM SEQUENCE_TABLE(10) AS tt); +UPDATE t1 SET id = id + 100 WHERE id IN (SELECT * FROM sequence_table); +DELETE FROM sequence_table WHERE id = 101; +DELETE FROM sequence_table WHERE id IN (SELECT * FROM SEQUENCE_TABLE(10) AS tt); +DELETE FROM t1 WHERE id IN (SELECT * FROM sequence_table); +TRUNCATE TABLE sequence_table; +DROP TABLE t1; +DROP TABLE sequence_table; diff --git a/mysql-test/suite/percona/t/sequence_table.test b/mysql-test/suite/percona/t/sequence_table.test new file mode 100644 index 000000000000..6405d4975a8f --- /dev/null +++ b/mysql-test/suite/percona/t/sequence_table.test @@ -0,0 +1,314 @@ +# +# Introduce SEQUENCE_TABLE() table-level SQL function +# https://jira.percona.com/browse/PS-5764 +# + +--echo ### +--echo ### Checking invalid PERCONA_SEQUENCE_TABLE() arguments +--echo ### +--echo # no arguments +--error ER_PARSE_ERROR +SELECT * FROM PERCONA_SEQUENCE_TABLE() AS tt; + +--echo # two arguments +--error ER_PARSE_ERROR +SELECT * FROM PERCONA_SEQUENCE_TABLE(1, 2) AS tt; + +--echo ### +--echo ### Checking PERCONA_SEQUENCE_TABLE() without table alias +--echo ### +--error ER_TF_MUST_HAVE_ALIAS +SELECT * FROM PERCONA_SEQUENCE_TABLE(4); + + +--echo ### +--echo ### Simple usage scenarios +--echo ### +--let $st_field_expression = value +--let $st_table_expression = PERCONA_SEQUENCE_TABLE(0) AS tt +--let $st_expected_number_of_records = 0 +--let $st_expected_signature = +--source ../include/percona_sequence_table.inc + +--let $st_table_expression = PERCONA_SEQUENCE_TABLE(1) AS tt +--let $st_expected_number_of_records = 1 +--let $st_expected_signature = 0 +--source ../include/percona_sequence_table.inc + +--let $st_table_expression = PERCONA_SEQUENCE_TABLE(4) AS tt +--let $st_expected_number_of_records = 4 +--let $st_expected_signature = 0,1,2,3 +--source ../include/percona_sequence_table.inc + + +--echo ### +--echo ### Checking PERCONA_SEQUENCE_TABLE() max records limit +--echo ### +SET @saved_tf_sequence_table_max_upper_bound = @@global.tf_sequence_table_max_upper_bound; + +--disable_result_log +SELECT * FROM PERCONA_SEQUENCE_TABLE(@saved_tf_sequence_table_max_upper_bound) AS tt; +--enable_result_log + +--error ER_SEQUENCE_TABLE_SIZE_LIMIT +SELECT * FROM PERCONA_SEQUENCE_TABLE(@saved_tf_sequence_table_max_upper_bound + 1) AS tt; + +SET GLOBAL tf_sequence_table_max_upper_bound = @saved_tf_sequence_table_max_upper_bound + 1; + +--disable_result_log +SELECT * FROM PERCONA_SEQUENCE_TABLE(@saved_tf_sequence_table_max_upper_bound + 1) AS tt; +--enable_result_log + +--error ER_SEQUENCE_TABLE_SIZE_LIMIT +SELECT * FROM PERCONA_SEQUENCE_TABLE(@saved_tf_sequence_table_max_upper_bound + 2) AS tt; + +SET GLOBAL tf_sequence_table_max_upper_bound = @saved_tf_sequence_table_max_upper_bound; + +--echo ### +--echo ### Checking PERCONA_SEQUENCE_TABLE() upper bound value conversions +--echo ### +--echo # Negative numbers +--let $st_table_expression = PERCONA_SEQUENCE_TABLE(-1) AS tt +--let $st_expected_number_of_records = 0 +--let $st_expected_signature = +--source ../include/percona_sequence_table.inc + +--echo # NULL value +--let $st_table_expression = PERCONA_SEQUENCE_TABLE(NULL) AS tt +--let $st_expected_number_of_records = 0 +--let $st_expected_signature = +--source ../include/percona_sequence_table.inc + +--echo # Floating point numbers +--let $st_table_expression = PERCONA_SEQUENCE_TABLE(2.5) AS tt +--let $st_expected_number_of_records = 3 +--let $st_expected_signature = 0,1,2 +--source ../include/percona_sequence_table.inc + +--let $st_table_expression = PERCONA_SEQUENCE_TABLE(0.15E1) AS tt +--let $st_expected_number_of_records = 2 +--let $st_expected_signature = 0,1 +--source ../include/percona_sequence_table.inc + +--let $st_table_expression = PERCONA_SEQUENCE_TABLE(0.15E-1) AS tt +--let $st_expected_number_of_records = 0 +--let $st_expected_signature = +--source ../include/percona_sequence_table.inc + +--echo # String values +--let $st_table_expression = PERCONA_SEQUENCE_TABLE("") AS tt +--let $st_expected_number_of_records = 0 +--let $st_expected_signature = +--source ../include/percona_sequence_table.inc + +--let $st_table_expression = PERCONA_SEQUENCE_TABLE(" ") AS tt +--let $st_expected_number_of_records = 0 +--let $st_expected_signature = +--source ../include/percona_sequence_table.inc + +--let $st_table_expression = PERCONA_SEQUENCE_TABLE("2") AS tt +--let $st_expected_number_of_records = 2 +--let $st_expected_signature = 0,1 +--source ../include/percona_sequence_table.inc + +--echo ### +--echo ### Checking PERCONA_SEQUENCE_TABLE() upper bound expressions +--echo ### +--echo # Session variables +SET @a = 4; +--let $st_table_expression = PERCONA_SEQUENCE_TABLE(@a) AS tt +--let $st_expected_number_of_records = 4 +--let $st_expected_signature = 0,1,2,3 +--source ../include/percona_sequence_table.inc + +SET @a = 3; +--let $st_table_expression = PERCONA_SEQUENCE_TABLE(@a) AS tt +--let $st_expected_number_of_records = 3 +--let $st_expected_signature = 0,1,2 +--source ../include/percona_sequence_table.inc + +--echo # Simple arithmetic expressions +SET @a = 2; +--let $st_table_expression = PERCONA_SEQUENCE_TABLE(@a * @a - 1) AS tt +--let $st_expected_number_of_records = 3 +--let $st_expected_signature = 0,1,2 +--source ../include/percona_sequence_table.inc + +SET @a = 1; +--let $st_table_expression = PERCONA_SEQUENCE_TABLE(EXP(@a) - 1) AS tt +--let $st_expected_number_of_records = 2 +--let $st_expected_signature = 0,1 +--source ../include/percona_sequence_table.inc + + +--echo ### +--echo ### Checking PERCONA_SEQUENCE_TABLE() with WHERE clause +--echo ### +--echo # Point selection +--let $st_table_expression = PERCONA_SEQUENCE_TABLE(4) AS tt +--let $st_where = value = 1 +--let $st_expected_number_of_records = 1 +--let $st_expected_signature = 1 +--source ../include/percona_sequence_table.inc + + +--echo # Range selection +--let $st_table_expression = PERCONA_SEQUENCE_TABLE(4) AS tt +--let $st_where = value > 1 +--let $st_expected_number_of_records = 2 +--let $st_expected_signature = 2,3 +--source ../include/percona_sequence_table.inc + +--echo # Every second record +--let $st_table_expression = PERCONA_SEQUENCE_TABLE(4) AS tt +--let $st_where = value %2 = 0 +--let $st_expected_number_of_records = 2 +--let $st_expected_signature = 0,2 +--source ../include/percona_sequence_table.inc + + +--let $st_where = + +--echo ### +--echo ### Selecting custom value expressions from PERCONA_SEQUENCE_TABLE() +--echo ### +--echo # Shifted values +--let $st_field_expression = value + 1 +--let $st_table_expression = PERCONA_SEQUENCE_TABLE(4) AS tt +--let $st_expected_number_of_records = 4 +--let $st_expected_signature = 1,2,3,4 +--source ../include/percona_sequence_table.inc + +--echo # Odd numbers +--let $st_field_expression = value * 2 + 1 +--let $st_table_expression = PERCONA_SEQUENCE_TABLE(4) AS tt +--let $st_expected_number_of_records = 4 +--let $st_expected_signature = 1,3,5,7 +--source ../include/percona_sequence_table.inc + +--echo # Reverse order +--let $st_field_expression = 7 - value +--let $st_table_expression = PERCONA_SEQUENCE_TABLE(4) AS tt +--let $st_expected_number_of_records = 4 +--let $st_expected_signature = 7,6,5,4 +--let $st_sort_order = DESC +--source ../include/percona_sequence_table.inc + +--echo # Mapping with ELT() +--let $st_field_expression = ELT(value + 1, "a", "b", "c", "d") +--let $st_table_expression = PERCONA_SEQUENCE_TABLE(4) AS tt +--let $st_expected_number_of_records = 4 +--let $st_expected_signature = a,b,c,d +--let $st_sort_order = +--source ../include/percona_sequence_table.inc + +--echo ### +--echo ### Checking VIEWs based on PERCONA_SEQUENCE_TABLE() +--echo ### +CREATE VIEW v1 AS SELECT * FROM PERCONA_SEQUENCE_TABLE(4) AS tt; +SHOW CREATE VIEW v1; +--let $st_field_expression = value +--let $st_table_expression = v1 +--let $st_expected_number_of_records = 4 +--let $st_expected_signature = 0,1,2,3 +--source ../include/percona_sequence_table.inc +DROP VIEW v1; + + +--echo ### +--echo ### Checking stored procedures / functions +--echo ### +--echo # Stored procedure +CREATE PROCEDURE p1(upper_bound BIGINT UNSIGNED) SELECT * FROM PERCONA_SEQUENCE_TABLE(upper_bound) AS tt; +CALL p1(4); +DROP PROCEDURE p1; + +--echo # Stored function +delimiter |; +CREATE FUNCTION f1(upper_bound BIGINT UNSIGNED) RETURNS BIGINT UNSIGNED +BEGIN + DECLARE res BIGINT UNSIGNED; + SELECT SUM(value) INTO res FROM PERCONA_SEQUENCE_TABLE(upper_bound) AS tt; + RETURN res; +END| +delimiter ;| +--let $assert_cond = "[SELECT f1(4)]" = 6 +--let $assert_text = SUM(0, ..., 3) should be 6 +--source include/assert.inc +SELECT f1(4); +DROP FUNCTION f1; + + +--echo ### +--echo ### Checking prepared statements +--echo ### +PREPARE stmt1 FROM 'SELECT * FROM PERCONA_SEQUENCE_TABLE(?) AS tt'; +SET @a = 4; +EXECUTE stmt1 USING @a; +DEALLOCATE PREPARE stmt1; + + +--echo ### +--echo ### Checking SHOW CREATE TABLE +--echo ### +CREATE TABLE t1 AS SELECT value AS a FROM PERCONA_SEQUENCE_TABLE(3) AS tt; +SHOW CREATE TABLE t1; + +--echo ### +--echo ### Checking table joins +--echo ### +--echo # Constant upper_bound +--let $st_field_expression = t1.a * 10 + value +--let $st_table_expression = t1, PERCONA_SEQUENCE_TABLE(3) AS tt +--let $st_expected_number_of_records = 9 +--let $st_expected_signature = 0,1,2,10,11,12,20,21,22 +--source ../include/percona_sequence_table.inc + +--echo # Join with UNION-based row set +--let $st_field_expression = tt1.a * 10 + value +--let $st_table_expression = (SELECT 0 AS a UNION SELECT 1 UNION SELECT 2) AS tt1, PERCONA_SEQUENCE_TABLE(3) AS tt2 +--let $st_expected_number_of_records = 9 +--let $st_expected_signature = 0,1,2,10,11,12,20,21,22 +--source ../include/percona_sequence_table.inc + +--echo # Join with VALUES ROW-based row set +--let $st_field_expression = tt1.column_0 * 10 + value +--let $st_table_expression = (VALUES ROW(0), ROW(1), ROW(2)) AS tt1, PERCONA_SEQUENCE_TABLE(3) AS tt2 +--let $st_expected_number_of_records = 9 +--let $st_expected_signature = 0,1,2,10,11,12,20,21,22 +--source ../include/percona_sequence_table.inc + +--echo # Join with derived SELECT +--let $st_field_expression = tt1.a * 10 + value +--let $st_table_expression = (SELECT * FROM t1) AS tt1, PERCONA_SEQUENCE_TABLE(3) AS tt2 +--let $st_expected_number_of_records = 9 +--let $st_expected_signature = 0,1,2,10,11,12,20,21,22 +--source ../include/percona_sequence_table.inc + +--echo # Join with derived TABLE +--let $st_field_expression = tt1.a * 10 + value +--let $st_table_expression = (TABLE t1) AS tt1, PERCONA_SEQUENCE_TABLE(3) AS tt2 +--let $st_expected_number_of_records = 9 +--let $st_expected_signature = 0,1,2,10,11,12,20,21,22 +--source ../include/percona_sequence_table.inc + +--echo # Dependent upper_bound +--let $st_field_expression = t1.a * 10 + value +--let $st_table_expression = t1, PERCONA_SEQUENCE_TABLE(a + 1) AS tt +--let $st_expected_number_of_records = 6 +--let $st_expected_signature = 0,10,11,20,21,22 +--source ../include/percona_sequence_table.inc + + +--echo ### +--echo ### Checking for various forbidden upper_bound constructs +--echo ### +--echo # Derived SELECT +--error ER_WRONG_ARGUMENTS +SELECT * FROM PERCONA_SEQUENCE_TABLE((SELECT 1)) AS tt; + +--echo # Aggregate function +--error ER_INVALID_GROUP_FUNC_USE +SELECT * FROM PERCONA_SEQUENCE_TABLE(SUM(1)) AS tt; + +DROP TABLE t1; diff --git a/mysql-test/suite/percona/t/sequence_table_keyword.test b/mysql-test/suite/percona/t/sequence_table_keyword.test new file mode 100644 index 000000000000..518071d512ec --- /dev/null +++ b/mysql-test/suite/percona/t/sequence_table_keyword.test @@ -0,0 +1,107 @@ +# +# PS-8963: SEQUENCE_TABLE reserved keyword issue +# https://perconadev.atlassian.net/browse/PS-8963 +# + +# creating a simple table for referencing +CREATE TABLE t1(id INT UNSIGNED) ENGINE=InnoDB; +INSERT INTO t1 VALUES(1); + +# creating a table with the 'percona_sequence_table' name must fail as +# this is a reserved keyword +--error ER_PARSE_ERROR +CREATE TABLE percona_sequence_table(id INT UNSIGNED) ENGINE=InnoDB; + +# disabling ER_WARN_DEPRECATED_SYNTAX as a number of 'sequence_table' +# identifiers used in table function context will generate this warning +--disable_warnings ER_WARN_DEPRECATED_SYNTAX + +# creating a table with the 'sequence_table' name +CREATE TABLE sequence_table(id INT UNSIGNED) ENGINE=InnoDB; + +INSERT INTO sequence_table VALUES (1); +INSERT INTO sequence_table VALUES (2); + +# +SELECT * FROM sequence_table; +SELECT * FROM sequence_table AS tt; +SELECT * FROM sequence_table tt; + +# +SELECT * FROM (sequence_table); +SELECT * FROM (sequence_table AS tt); +SELECT * FROM (sequence_table tt); + +# with optional alias and optional column list +SELECT * FROM (SELECT * FROM t1) AS sequence_table; +SELECT * FROM (SELECT * FROM t1) sequence_table; +SELECT sequence_table.* FROM (SELECT * FROM t1) AS sequence_table; +SELECT sequence_table.* FROM (SELECT * FROM t1) sequence_table; + +SELECT * FROM (SELECT * FROM t1) AS sequence_table(val); +SELECT * FROM (SELECT * FROM t1) sequence_table(val); +SELECT sequence_table.* FROM (SELECT * FROM t1) AS sequence_table(val); +SELECT sequence_table.* FROM (SELECT * FROM t1) sequence_table(val); +SELECT sequence_table.val FROM (SELECT * FROM t1) AS sequence_table(val); +SELECT sequence_table.val FROM (SELECT * FROM t1) sequence_table(val); +SELECT val FROM (SELECT * FROM t1) AS sequence_table(val); +SELECT val FROM (SELECT * FROM t1) sequence_table(val); + +SELECT * FROM (SELECT * FROM t1) AS tt(sequence_table); +SELECT * FROM (SELECT * FROM t1) tt(sequence_table); +SELECT tt.sequence_table FROM (SELECT * FROM t1) AS tt(sequence_table); +SELECT tt.sequence_table FROM (SELECT * FROM t1) tt(sequence_table); +SELECT sequence_table FROM (SELECT * FROM t1) AS tt(sequence_table); +SELECT sequence_table FROM (SELECT * FROM t1) tt(sequence_table); + +SELECT * FROM (SELECT * FROM t1) AS sequence_table(sequence_table); +SELECT * FROM (SELECT * FROM t1) sequence_table(sequence_table); +SELECT sequence_table.sequence_table FROM (SELECT * FROM t1) AS sequence_table(sequence_table); +SELECT sequence_table.sequence_table FROM (SELECT * FROM t1) sequence_table(sequence_table); +SELECT sequence_table FROM (SELECT * FROM t1) AS sequence_table(sequence_table); +SELECT sequence_table FROM (SELECT * FROM t1) sequence_table(sequence_table); + +# single table with 'sequence_table' as an alias +SELECT * FROM t1 AS sequence_table; +SELECT * FROM t1 sequence_table; +SELECT * FROM t1 AS sequence_table WHERE id = 1; +SELECT * FROM t1 sequence_table WHERE id = 1; +SELECT * FROM t1 AS sequence_table WHERE sequence_table.id = 1; +SELECT * FROM t1 sequence_table WHERE sequence_table.id = 1; + +# SEQUENCE_TABLE() as a table function +SELECT * FROM SEQUENCE_TABLE(2) AS tt; +SELECT * FROM SEQUENCE_TABLE(2) tt; + +# SEQUENCE_TABLE() as a table function with 'sequence_table' alias +SELECT * FROM SEQUENCE_TABLE(2) AS sequence_table; +SELECT sequence_table.* FROM SEQUENCE_TABLE(2) AS sequence_table; +SELECT value FROM SEQUENCE_TABLE(2) AS sequence_table; +SELECT sequence_table.value FROM SEQUENCE_TABLE(2) AS sequence_table; + +# the mixture of 'sequence_table' and the table function +SELECT * FROM sequence_table, SEQUENCE_TABLE(2) AS tt; + +# inserts +INSERT INTO sequence_table VALUES (3); +INSERT INTO sequence_table SELECT value + 4 FROM SEQUENCE_TABLE(2) AS tt; +INSERT INTO t1 SELECT * FROM sequence_table; + +# updates +UPDATE sequence_table SET id = id + 100; +UPDATE sequence_table SET id = id + 100 WHERE id IN (SELECT * FROM SEQUENCE_TABLE(10) AS tt); +UPDATE t1 SET id = id + 100 WHERE id IN (SELECT * FROM sequence_table); + +# deletes +DELETE FROM sequence_table WHERE id = 101; +DELETE FROM sequence_table WHERE id IN (SELECT * FROM SEQUENCE_TABLE(10) AS tt); +DELETE FROM t1 WHERE id IN (SELECT * FROM sequence_table); + +# truncates +TRUNCATE TABLE sequence_table; + +--enable_warnings ER_WARN_DEPRECATED_SYNTAX + +# cleaning up +DROP TABLE t1; +DROP TABLE sequence_table; diff --git a/mysql-test/suite/percona_innodb/r/optimizer_temporary_table_2.result b/mysql-test/suite/percona_innodb/r/optimizer_temporary_table_2.result index b7f6c9c00594..8c0ffb11d788 100644 --- a/mysql-test/suite/percona_innodb/r/optimizer_temporary_table_2.result +++ b/mysql-test/suite/percona_innodb/r/optimizer_temporary_table_2.result @@ -9,7 +9,7 @@ CREATE TABLE source (id INT PRIMARY KEY AUTO_INCREMENT, a VARCHAR(100), b VARCHA CREATE TABLE dest LIKE source; # Populate source table with 64K records. INSERT INTO source (a, b, c, d, e, hdl_source_id, hdl_created_date) -SELECT 'aaaaaaaaa', 'bbbbbbbbbb', 'cccccccccccccccc', 'dddddddddddddddddddddddddddd', 'eeeeeeeeeeeeeeeeee', value, NOW() FROM SEQUENCE_TABLE(65536) AS tt; +SELECT 'aaaaaaaaa', 'bbbbbbbbbb', 'cccccccccccccccc', 'dddddddddddddddddddddddddddd', 'eeeeeeeeeeeeeeeeee', value, NOW() FROM PERCONA_SEQUENCE_TABLE(65536) AS tt; SELECT count(*) FROM source; count(*) 65536 diff --git a/mysql-test/suite/percona_innodb/t/optimizer_temporary_table_2.test b/mysql-test/suite/percona_innodb/t/optimizer_temporary_table_2.test index 75d9f71454c4..9366dbd5a87c 100644 --- a/mysql-test/suite/percona_innodb/t/optimizer_temporary_table_2.test +++ b/mysql-test/suite/percona_innodb/t/optimizer_temporary_table_2.test @@ -15,7 +15,7 @@ CREATE TABLE dest LIKE source; --echo # Populate source table with 64K records. INSERT INTO source (a, b, c, d, e, hdl_source_id, hdl_created_date) - SELECT 'aaaaaaaaa', 'bbbbbbbbbb', 'cccccccccccccccc', 'dddddddddddddddddddddddddddd', 'eeeeeeeeeeeeeeeeee', value, NOW() FROM SEQUENCE_TABLE(65536) AS tt; + SELECT 'aaaaaaaaa', 'bbbbbbbbbb', 'cccccccccccccccc', 'dddddddddddddddddddddddddddd', 'eeeeeeeeeeeeeeeeee', value, NOW() FROM PERCONA_SEQUENCE_TABLE(65536) AS tt; SELECT count(*) FROM source; --echo # Run query that creates big intrinsic temporary table. Prior to the diff --git a/mysql-test/suite/sys_vars/r/tf_sequence_table_max_upper_bound_basic.result b/mysql-test/suite/sys_vars/r/tf_sequence_table_max_upper_bound_basic.result new file mode 100644 index 000000000000..ac97203b7bf6 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/tf_sequence_table_max_upper_bound_basic.result @@ -0,0 +1,170 @@ +######################################################################## +# START OF tf_sequence_table_max_upper_bound TESTS # +######################################################################## +SET @start_tf_sequence_table_max_upper_bound = @@global.tf_sequence_table_max_upper_bound; +SELECT @start_tf_sequence_table_max_upper_bound; +@start_tf_sequence_table_max_upper_bound +1048576 +######################################################################## +# Display the DEFAULT value of tf_sequence_table_max_upper_bound # +######################################################################## +SET @@global.tf_sequence_table_max_upper_bound = 5000; +SET @@global.tf_sequence_table_max_upper_bound = DEFAULT; +SELECT @@global.tf_sequence_table_max_upper_bound; +@@global.tf_sequence_table_max_upper_bound +1048576 +############################################### +# Verify default value of variable # +############################################### +SET @@global.tf_sequence_table_max_upper_bound = @start_tf_sequence_table_max_upper_bound; +SELECT @@global.tf_sequence_table_max_upper_bound = 18446744073709551615; +@@global.tf_sequence_table_max_upper_bound = 18446744073709551615 +0 +########################################################################## +# Change the value of tf_sequence_table_max_upper_bound to a valid value # +########################################################################## +SET @@global.tf_sequence_table_max_upper_bound = 1024; +SELECT @@global.tf_sequence_table_max_upper_bound; +@@global.tf_sequence_table_max_upper_bound +1024 +SET @@global.tf_sequence_table_max_upper_bound = 4294967294; +SELECT @@global.tf_sequence_table_max_upper_bound; +@@global.tf_sequence_table_max_upper_bound +4294967294 +SET @@global.tf_sequence_table_max_upper_bound = 4294967295; +SELECT @@global.tf_sequence_table_max_upper_bound; +@@global.tf_sequence_table_max_upper_bound +4294967295 +SET @@global.tf_sequence_table_max_upper_bound = 4294967296; +SELECT @@global.tf_sequence_table_max_upper_bound; +@@global.tf_sequence_table_max_upper_bound +4294967296 +SET @@global.tf_sequence_table_max_upper_bound = 18446744073709551614; +SELECT @@global.tf_sequence_table_max_upper_bound; +@@global.tf_sequence_table_max_upper_bound +18446744073709551614 +SET @@global.tf_sequence_table_max_upper_bound = 18446744073709551615; +SELECT @@global.tf_sequence_table_max_upper_bound; +@@global.tf_sequence_table_max_upper_bound +18446744073709551615 +########################################################################### +# Change the value of tf_sequence_table_max_upper_bound to invalid value # +########################################################################### +SET @@global.tf_sequence_table_max_upper_bound = -1; +Warnings: +Warning 1292 Truncated incorrect tf_sequence_table_max_upper_bound value: '-1' +SELECT @@global.tf_sequence_table_max_upper_bound; +@@global.tf_sequence_table_max_upper_bound +1024 +SET @@global.tf_sequence_table_max_upper_bound = 0; +Warnings: +Warning 1292 Truncated incorrect tf_sequence_table_max_upper_bound value: '0' +SELECT @@global.tf_sequence_table_max_upper_bound; +@@global.tf_sequence_table_max_upper_bound +1024 +SET @@global.tf_sequence_table_max_upper_bound = 1023; +Warnings: +Warning 1292 Truncated incorrect tf_sequence_table_max_upper_bound value: '1023' +SELECT @@global.tf_sequence_table_max_upper_bound; +@@global.tf_sequence_table_max_upper_bound +1024 +SET @@global.tf_sequence_table_max_upper_bound = 10000.01; +ERROR 42000: Incorrect argument type to variable 'tf_sequence_table_max_upper_bound' +SELECT @@global.tf_sequence_table_max_upper_bound; +@@global.tf_sequence_table_max_upper_bound +1024 +SET @@global.tf_sequence_table_max_upper_bound = -1024; +Warnings: +Warning 1292 Truncated incorrect tf_sequence_table_max_upper_bound value: '-1024' +SELECT @@global.tf_sequence_table_max_upper_bound; +@@global.tf_sequence_table_max_upper_bound +1024 +SET @@global.tf_sequence_table_max_upper_bound = 1024; +SELECT @@global.tf_sequence_table_max_upper_bound; +@@global.tf_sequence_table_max_upper_bound +1024 +SET @@global.tf_sequence_table_max_upper_bound = ON; +ERROR 42000: Incorrect argument type to variable 'tf_sequence_table_max_upper_bound' +SELECT @@global.tf_sequence_table_max_upper_bound; +@@global.tf_sequence_table_max_upper_bound +1024 +SET @@global.tf_sequence_table_max_upper_bound = 'test'; +ERROR 42000: Incorrect argument type to variable 'tf_sequence_table_max_upper_bound' +SELECT @@global.tf_sequence_table_max_upper_bound; +@@global.tf_sequence_table_max_upper_bound +1024 +SET @@global.tf_sequence_table_max_upper_bound = ' '; +ERROR 42000: Incorrect argument type to variable 'tf_sequence_table_max_upper_bound' +SELECT @@global.tf_sequence_table_max_upper_bound; +@@global.tf_sequence_table_max_upper_bound +1024 +########################################################################### +# Test if accessing session tf_sequence_table_max_upper_bound gives error # +########################################################################### +SET @@session.tf_sequence_table_max_upper_bound = 4096; +ERROR HY000: Variable 'tf_sequence_table_max_upper_bound' is a GLOBAL variable and should be set with SET GLOBAL +SELECT @@session.tf_sequence_table_max_upper_bound; +ERROR HY000: Variable 'tf_sequence_table_max_upper_bound' is a GLOBAL variable +############################################################################## +# Check if the value in GLOBAL & SESSION Tables matches values in variable # +############################################################################## +SELECT @@global.tf_sequence_table_max_upper_bound = VARIABLE_VALUE +FROM performance_schema.global_variables +WHERE VARIABLE_NAME='tf_sequence_table_max_upper_bound'; +@@global.tf_sequence_table_max_upper_bound = VARIABLE_VALUE +1 +SELECT @@tf_sequence_table_max_upper_bound = VARIABLE_VALUE +FROM performance_schema.session_variables +WHERE VARIABLE_NAME='tf_sequence_table_max_upper_bound'; +@@tf_sequence_table_max_upper_bound = VARIABLE_VALUE +1 +################################################################### +# Check if TRUE and FALSE values can be used on variable # +################################################################### +SET @@global.tf_sequence_table_max_upper_bound = TRUE; +Warnings: +Warning 1292 Truncated incorrect tf_sequence_table_max_upper_bound value: '1' +SELECT @@global.tf_sequence_table_max_upper_bound; +@@global.tf_sequence_table_max_upper_bound +1024 +SET @@global.tf_sequence_table_max_upper_bound = FALSE; +Warnings: +Warning 1292 Truncated incorrect tf_sequence_table_max_upper_bound value: '0' +SELECT @@global.tf_sequence_table_max_upper_bound; +@@global.tf_sequence_table_max_upper_bound +1024 +######################################################################################################## +# Check if accessing variable with SESSION,LOCAL and without SCOPE points to same session variable # +######################################################################################################## +SET @@global.tf_sequence_table_max_upper_bound = 5000; +SELECT @@tf_sequence_table_max_upper_bound = @@global.tf_sequence_table_max_upper_bound; +@@tf_sequence_table_max_upper_bound = @@global.tf_sequence_table_max_upper_bound +1 +####################################################################################### +# Check if tf_sequence_table_max_upper_bound can be accessed with and without @@ sign # +####################################################################################### +SET tf_sequence_table_max_upper_bound = 6000; +ERROR HY000: Variable 'tf_sequence_table_max_upper_bound' is a GLOBAL variable and should be set with SET GLOBAL +SELECT @@tf_sequence_table_max_upper_bound; +@@tf_sequence_table_max_upper_bound +5000 +SET local.tf_sequence_table_max_upper_bound = 7000; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'local.tf_sequence_table_max_upper_bound = 7000' at line 1 +SELECT local.tf_sequence_table_max_upper_bound; +ERROR 42S02: Unknown table 'local' in field list +SET global.tf_sequence_table_max_upper_bound = 8000; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'global.tf_sequence_table_max_upper_bound = 8000' at line 1 +SELECT global.tf_sequence_table_max_upper_bound; +ERROR 42S02: Unknown table 'global' in field list +SELECT tf_sequence_table_max_upper_bound; +ERROR 42S22: Unknown column 'tf_sequence_table_max_upper_bound' in 'field list' +############################## +# Restore initial value # +############################## +SET @@global.tf_sequence_table_max_upper_bound = @start_tf_sequence_table_max_upper_bound; +SELECT @@global.tf_sequence_table_max_upper_bound; +@@global.tf_sequence_table_max_upper_bound +1048576 +######################################################################## +# END OF tf_sequence_table_max_upper_bound TESTS # +######################################################################## diff --git a/mysql-test/suite/sys_vars/t/tf_sequence_table_max_upper_bound_basic.test b/mysql-test/suite/sys_vars/t/tf_sequence_table_max_upper_bound_basic.test new file mode 100644 index 000000000000..176f37977cd0 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/tf_sequence_table_max_upper_bound_basic.test @@ -0,0 +1,167 @@ +########## mysql-test\t\tf_sequence_table_max_upper_bound_basic.test ########## +# # +# Variable Name: tf_sequence_table_max_upper_bound # +# Scope: GLOBAL # +# Access Type: Dynamic # +# Data Type: numeric # +# Default Value:1048576 # +# Range: 1024-2^64-1 # +# # +# Description: Test Cases of Dynamic System Variable # +# tf_sequence_table_max_upper_bound that checks the behavior of # +# this variable in the following ways # +# * Default Value # +# * Valid & Invalid values # +# * Scope & Access method # +# * Data Integrity # +# # +# Reference: http://dev.mysql.com/doc/refman/5.1/en/ # +# server-system-variables.html # +# # +############################################################################### + +--source include/load_sysvars.inc + +--echo ######################################################################## +--echo # START OF tf_sequence_table_max_upper_bound TESTS # +--echo ######################################################################## +SET @start_tf_sequence_table_max_upper_bound = @@global.tf_sequence_table_max_upper_bound; +SELECT @start_tf_sequence_table_max_upper_bound; + + +--echo ######################################################################## +--echo # Display the DEFAULT value of tf_sequence_table_max_upper_bound # +--echo ######################################################################## + +SET @@global.tf_sequence_table_max_upper_bound = 5000; +SET @@global.tf_sequence_table_max_upper_bound = DEFAULT; +SELECT @@global.tf_sequence_table_max_upper_bound; + + +--echo ############################################### +--echo # Verify default value of variable # +--echo ############################################### + +SET @@global.tf_sequence_table_max_upper_bound = @start_tf_sequence_table_max_upper_bound; +SELECT @@global.tf_sequence_table_max_upper_bound = 18446744073709551615; + +--echo ########################################################################## +--echo # Change the value of tf_sequence_table_max_upper_bound to a valid value # +--echo ########################################################################## + +SET @@global.tf_sequence_table_max_upper_bound = 1024; +SELECT @@global.tf_sequence_table_max_upper_bound; +SET @@global.tf_sequence_table_max_upper_bound = 4294967294; +SELECT @@global.tf_sequence_table_max_upper_bound; +SET @@global.tf_sequence_table_max_upper_bound = 4294967295; +SELECT @@global.tf_sequence_table_max_upper_bound; +SET @@global.tf_sequence_table_max_upper_bound = 4294967296; +SELECT @@global.tf_sequence_table_max_upper_bound; +SET @@global.tf_sequence_table_max_upper_bound = 18446744073709551614; +SELECT @@global.tf_sequence_table_max_upper_bound; +SET @@global.tf_sequence_table_max_upper_bound = 18446744073709551615; +SELECT @@global.tf_sequence_table_max_upper_bound; + + +--echo ########################################################################### +--echo # Change the value of tf_sequence_table_max_upper_bound to invalid value # +--echo ########################################################################### + +SET @@global.tf_sequence_table_max_upper_bound = -1; +SELECT @@global.tf_sequence_table_max_upper_bound; +SET @@global.tf_sequence_table_max_upper_bound = 0; +SELECT @@global.tf_sequence_table_max_upper_bound; +SET @@global.tf_sequence_table_max_upper_bound = 1023; +SELECT @@global.tf_sequence_table_max_upper_bound; +--Error ER_WRONG_TYPE_FOR_VAR +SET @@global.tf_sequence_table_max_upper_bound = 10000.01; +SELECT @@global.tf_sequence_table_max_upper_bound; +SET @@global.tf_sequence_table_max_upper_bound = -1024; +SELECT @@global.tf_sequence_table_max_upper_bound; +SET @@global.tf_sequence_table_max_upper_bound = 1024; +SELECT @@global.tf_sequence_table_max_upper_bound; + +--Error ER_WRONG_TYPE_FOR_VAR +SET @@global.tf_sequence_table_max_upper_bound = ON; +SELECT @@global.tf_sequence_table_max_upper_bound; +--Error ER_WRONG_TYPE_FOR_VAR +SET @@global.tf_sequence_table_max_upper_bound = 'test'; +SELECT @@global.tf_sequence_table_max_upper_bound; +--Error ER_WRONG_TYPE_FOR_VAR +SET @@global.tf_sequence_table_max_upper_bound = ' '; +SELECT @@global.tf_sequence_table_max_upper_bound; + + +--echo ########################################################################### +--echo # Test if accessing session tf_sequence_table_max_upper_bound gives error # +--echo ########################################################################### + +--Error ER_GLOBAL_VARIABLE +SET @@session.tf_sequence_table_max_upper_bound = 4096; +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.tf_sequence_table_max_upper_bound; + + +--echo ############################################################################## +--echo # Check if the value in GLOBAL & SESSION Tables matches values in variable # +--echo ############################################################################## + +--disable_warnings +SELECT @@global.tf_sequence_table_max_upper_bound = VARIABLE_VALUE +FROM performance_schema.global_variables +WHERE VARIABLE_NAME='tf_sequence_table_max_upper_bound'; + +SELECT @@tf_sequence_table_max_upper_bound = VARIABLE_VALUE +FROM performance_schema.session_variables +WHERE VARIABLE_NAME='tf_sequence_table_max_upper_bound'; +--enable_warnings + + +--echo ################################################################### +--echo # Check if TRUE and FALSE values can be used on variable # +--echo ################################################################### + +SET @@global.tf_sequence_table_max_upper_bound = TRUE; +SELECT @@global.tf_sequence_table_max_upper_bound; +SET @@global.tf_sequence_table_max_upper_bound = FALSE; +SELECT @@global.tf_sequence_table_max_upper_bound; + + +--echo ######################################################################################################## +--echo # Check if accessing variable with SESSION,LOCAL and without SCOPE points to same session variable # +--echo ######################################################################################################## + +SET @@global.tf_sequence_table_max_upper_bound = 5000; +SELECT @@tf_sequence_table_max_upper_bound = @@global.tf_sequence_table_max_upper_bound; + + +--echo ####################################################################################### +--echo # Check if tf_sequence_table_max_upper_bound can be accessed with and without @@ sign # +--echo ####################################################################################### + +--Error ER_GLOBAL_VARIABLE +SET tf_sequence_table_max_upper_bound = 6000; +SELECT @@tf_sequence_table_max_upper_bound; +--Error ER_PARSE_ERROR +SET local.tf_sequence_table_max_upper_bound = 7000; +--Error ER_UNKNOWN_TABLE +SELECT local.tf_sequence_table_max_upper_bound; +--Error ER_PARSE_ERROR +SET global.tf_sequence_table_max_upper_bound = 8000; +--Error ER_UNKNOWN_TABLE +SELECT global.tf_sequence_table_max_upper_bound; +--Error ER_BAD_FIELD_ERROR +SELECT tf_sequence_table_max_upper_bound; + + +--echo ############################## +--echo # Restore initial value # +--echo ############################## + +SET @@global.tf_sequence_table_max_upper_bound = @start_tf_sequence_table_max_upper_bound; +SELECT @@global.tf_sequence_table_max_upper_bound; + + +--echo ######################################################################## +--echo # END OF tf_sequence_table_max_upper_bound TESTS # +--echo ######################################################################## diff --git a/share/messages_to_clients.txt b/share/messages_to_clients.txt index 179881b3ffcd..3642e4de62d4 100644 --- a/share/messages_to_clients.txt +++ b/share/messages_to_clients.txt @@ -10511,7 +10511,7 @@ ER_KEYRING_ILLEGAL_ENCRYPTION_OPTION eng "Encryption option is not allowed. %s" ER_SEQUENCE_TABLE_SIZE_LIMIT - eng "The number of records generated by SEQUENCE_TABLE() cannot exceed %llu (%llu requested). Try increasing @@tf_sequence_table_max_upper_bound to a larger value." + eng "The number of records generated by PERCONA_SEQUENCE_TABLE() cannot exceed %llu (%llu requested). Try increasing @@tf_sequence_table_max_upper_bound to a larger value." ER_SYSTEM_KEY_ROTATION_KEY_DOESNT_EXIST eng "InnoDB system key %lu cannot be rotated, because it does not exist." diff --git a/sql/lex.h b/sql/lex.h index 0d1900d458e4..0a4ba62e3b5c 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -497,6 +497,7 @@ static const SYMBOL symbols[] = { {SYM("PASSWORD", PASSWORD)}, {SYM("PASSWORD_LOCK_TIME", PASSWORD_LOCK_TIME_SYM)}, {SYM("PERCENT_RANK", PERCENT_RANK_SYM)}, + {SYM_PERCONA("PERCONA_SEQUENCE_TABLE", PERCONA_SEQUENCE_TABLE_SYM)}, {SYM("PERSIST", PERSIST_SYM)}, {SYM("PERSIST_ONLY", PERSIST_ONLY_SYM)}, {SYM("PHASE", PHASE_SYM)}, @@ -620,6 +621,7 @@ static const SYMBOL symbols[] = { {SYM("SERIAL", SERIAL_SYM)}, {SYM("SERIALIZABLE", SERIALIZABLE_SYM)}, {SYM("SESSION", SESSION_SYM)}, + {SYM_PERCONA("SEQUENCE_TABLE", SEQUENCE_TABLE_SYM)}, {SYM("SERVER", SERVER_SYM)}, {SYM("SET", SET_SYM)}, {SYM("SHARE", SHARE_SYM)}, diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 83a0e56be774..11e165bcec46 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1528,6 +1528,8 @@ char *opt_authentication_policy; bool encrypt_tmp_files; +ulonglong tf_sequence_table_max_upper_bound = 0; + /** name of reference on left expression in rewritten IN subquery */ const char *in_left_expr_name = ""; diff --git a/sql/mysqld.h b/sql/mysqld.h index fd740345ceb4..47eff8d18b9f 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -405,6 +405,7 @@ extern ulong connection_errors_peer_addr; extern char *opt_log_error_suppression_list; extern char *opt_log_error_services; extern bool encrypt_tmp_files; +extern ulonglong tf_sequence_table_max_upper_bound; extern char *opt_protocol_compression_algorithms; /** The size of the host_cache. */ extern uint host_cache_size; diff --git a/sql/parse_tree_nodes.cc b/sql/parse_tree_nodes.cc index 4de2e2287c68..8ed455bad548 100644 --- a/sql/parse_tree_nodes.cc +++ b/sql/parse_tree_nodes.cc @@ -1395,6 +1395,29 @@ bool PT_table_factor_function::do_contextualize(Parse_context *pc) { return false; } +bool PT_table_sequence_function::do_contextualize(Parse_context *pc) { + if (super::do_contextualize(pc) || m_expr->itemize(pc, &m_expr)) return true; + + auto stf = new (pc->mem_root) + Table_function_sequence(m_table_alias.str, m_expr); + if (stf == nullptr) return true; // OOM + + LEX_CSTRING alias; + alias.length = strlen(stf->func_name()); + alias.str = sql_strmake(stf->func_name(), alias.length); + if (alias.str == nullptr) return true; // OOM + + auto ti = new (pc->mem_root) Table_ident(alias, stf); + if (ti == nullptr) return true; + + m_table_ref = pc->select->add_table_to_list(pc->thd, ti, m_table_alias.str, 0, + TL_READ, MDL_SHARED_READ); + if (m_table_ref == nullptr) return true; + if (pc->select->add_joined_table(m_table_ref)) return true; + + return false; +} + PT_derived_table::PT_derived_table(const POS &pos, bool lateral, PT_subquery *subquery, const LEX_CSTRING &table_alias, diff --git a/sql/parse_tree_nodes.h b/sql/parse_tree_nodes.h index 1a4ecbfb9bbf..be048579112f 100644 --- a/sql/parse_tree_nodes.h +++ b/sql/parse_tree_nodes.h @@ -525,6 +525,20 @@ class PT_table_factor_function : public PT_table_reference { const LEX_STRING m_table_alias; }; +class PT_table_sequence_function : public PT_table_reference { + typedef PT_table_reference super; + + public: + PT_table_sequence_function(const POS &pos, Item *expr, const LEX_CSTRING &table_alias) + : super(pos), m_expr(expr), m_table_alias(table_alias) {} + + bool do_contextualize(Parse_context *pc) override; + + private: + Item *m_expr; + LEX_CSTRING m_table_alias; +}; + class PT_table_reference_list_parens : public PT_table_reference { typedef PT_table_reference super; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index de7a057ed689..4d9c6491a28e 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1475,6 +1475,8 @@ void warn_on_deprecated_user_defined_collation( Tokens from Percona Server 8.0 */ %token EFFECTIVE_SYM 1350 +%token SEQUENCE_TABLE_SYM 1351 +%token PERCONA_SEQUENCE_TABLE_SYM 1352 /* Precedence rules used to resolve the ambiguity when using keywords as idents @@ -12138,6 +12140,29 @@ table_function: $$= NEW_PTN PT_table_factor_function(@$, $3, $5, $6, to_lex_string($8)); } + | SEQUENCE_TABLE_SYM '(' expr ')' opt_table_alias + { + // Alias isn't optional, follow derived's behavior + if ($5 == NULL_CSTR) + { + my_message(ER_TF_MUST_HAVE_ALIAS, + ER_THD(YYTHD, ER_TF_MUST_HAVE_ALIAS), MYF(0)); + MYSQL_YYABORT; + } + push_deprecated_warn(YYTHD, "SEQUENCE_TABLE", "PERCONA_SEQUENCE_TABLE"); + $$= NEW_PTN PT_table_sequence_function(@$, $3, $5); + } + | PERCONA_SEQUENCE_TABLE_SYM '(' expr ')' opt_table_alias + { + // Alias isn't optional, follow derived's behavior + if ($5 == NULL_CSTR) + { + my_message(ER_TF_MUST_HAVE_ALIAS, + ER_THD(YYTHD, ER_TF_MUST_HAVE_ALIAS), MYF(0)); + MYSQL_YYABORT; + } + $$= NEW_PTN PT_table_sequence_function(@$, $3, $5); + } ; columns_clause: @@ -15767,6 +15792,7 @@ ident_keywords_unambiguous: | SECONDARY_UNLOAD_SYM | SECOND_SYM | SECURITY_SYM + | SEQUENCE_TABLE_SYM | SERIALIZABLE_SYM | SERIAL_SYM | SERVER_SYM diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 8dc12b698507..95192baca2c0 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -7864,6 +7864,13 @@ static Sys_var_bool Sys_skip_replica_start( DEFAULT(false), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(nullptr), ON_UPDATE(nullptr)); +static Sys_var_ulonglong Sys_tf_sequence_table_max_upper_bound( + "tf_sequence_table_max_upper_bound", + "Maximum number of records PERCONA_SEQUENCE_TABLE() table function " + "is allowed to generate.", + GLOBAL_VAR(tf_sequence_table_max_upper_bound), CMD_LINE(REQUIRED_ARG), + VALID_RANGE(1024, ULLONG_MAX), DEFAULT(1048576), BLOCK_SIZE(1)); + static bool check_authentication_policy(sys_var *, THD *, set_var *var) { if (!(var->save_result.string_value.str)) return true; return authentication_policy::policy_validate( diff --git a/sql/table_function.cc b/sql/table_function.cc index b84178092a3a..28a71669969d 100644 --- a/sql/table_function.cc +++ b/sql/table_function.cc @@ -774,3 +774,115 @@ void JT_data_source::cleanup() { v.clear(); producing_records = false; } + +Table_function_sequence::Table_function_sequence(const char *alias, Item *a) + : Table_function(), + m_table_alias(alias), + m_source(a), + m_vt_list(), + m_upper_bound_precalculated(false), + m_precalculated_upper_bound(0) { + m_value_field.init_for_tmp_table(MYSQL_TYPE_LONGLONG, // sql_type_arg + 20, // length_arg + 0, // decimals_arg + false, // maybe_null_arg + true, // is_unsigned_arg + 8, // pack_length_override_arg + value_field_name); // fld_name +} + +bool Table_function_sequence::init() { + return m_vt_list.push_back(&m_value_field); +} + +List *Table_function_sequence::get_field_list() { + return &m_vt_list; +} + +bool Table_function_sequence::fill_result_table() { + assert(!table->materialized); + // reset table + empty_table(); + + ulonglong upper_bound; + if (m_upper_bound_precalculated) { + upper_bound = m_precalculated_upper_bound; + } else { + upper_bound = calculate_upper_bound(); + if (m_source->const_item()) m_upper_bound_precalculated = true; + } + + if (upper_bound > tf_sequence_table_max_upper_bound) { + my_error(ER_SEQUENCE_TABLE_SIZE_LIMIT, MYF(0), + tf_sequence_table_max_upper_bound, upper_bound); + return true; + } + + for (ulonglong u = 0; u < upper_bound; ++u) { + if (get_field(0)->store(u, true)) return true; + if (write_row()) return true; + } + return false; +} + +table_map Table_function_sequence::used_tables() const { + return m_source->used_tables(); +} + +bool Table_function_sequence::print(const THD *thd, String *str, + enum_query_type query_type) const { + if (str->append(STRING_WITH_LEN("percona_sequence_table("))) return true; + m_source->print(thd, str, query_type); + if (thd->is_error()) return true; + return str->append(')'); +} + +bool Table_function_sequence::walk(Item_processor processor, enum_walk walk, + uchar *arg) { + // Only 'source' may reference columns of other tables; rest is literals. + return m_source->walk(processor, walk, arg); +} + +bool Table_function_sequence::do_init_args() { + assert(!m_upper_bound_precalculated); + + Item *dummy = m_source; + if (m_source->fix_fields(current_thd, &dummy)) return true; + + // Set the default type of '?' + if (m_source->propagate_type(current_thd, MYSQL_TYPE_LONGLONG)) return true; + + assert(m_source->data_type() != MYSQL_TYPE_VAR_STRING); + if (m_source->has_aggregation() || m_source->has_subquery() || + m_source != dummy) { + my_error(ER_WRONG_ARGUMENTS, MYF(0), "PERCONA_SEQUENCE_TABLE"); + return true; + } + + if (m_source->const_item()) { + m_precalculated_upper_bound = calculate_upper_bound(); + m_upper_bound_precalculated = true; + } + + return false; +} + +void Table_function_sequence::do_cleanup() { + m_source->cleanup(); + m_vt_list.clear(); + m_upper_bound_precalculated = false; + m_precalculated_upper_bound = 0; +} + +ulonglong Table_function_sequence::calculate_upper_bound() const { + ulonglong res = 0; + if (!m_source->is_null()) { + if (m_source->unsigned_flag) { + res = m_source->val_uint(); + } else { + auto signed_res = m_source->val_int(); + if (signed_res > 0) res = static_cast(signed_res); + } + } + return res; +} diff --git a/sql/table_function.h b/sql/table_function.h index 85e3eafce4b2..87022978e57b 100644 --- a/sql/table_function.h +++ b/sql/table_function.h @@ -433,6 +433,78 @@ class Table_function_json final : public Table_function { void do_cleanup() override; }; +class Table_function_sequence final : public Table_function { + static constexpr const char *value_field_name = "value"; + + public: + Table_function_sequence(const char *alias, Item *a); + + /** + Returns function's name + */ + const char *func_name() const override { return "percona_sequence_table"; } + /** + Initialize the table function before creation of result table + + @returns + true on error + false on success + */ + virtual bool init() override; + + /** + Execute table function + + @returns + true on error + false on success + */ + virtual bool fill_result_table() override; + + /** + Return table_map of tables used by function's data source + */ + virtual table_map used_tables() const override; + + /** + PERCONA_SEQUENCE_TABLE printout + + @param str string to print to + @param query_type type of query + + @returns + true on error + false on success + */ + virtual bool print(const THD *thd, String *str, + enum_query_type query_type) const override; + + virtual bool walk(Item_processor processor, enum_walk walk, + uchar *arg) override; + + private: + /// PERCONA_SEQUENCE_TABLE's alias, for error reporting + const char *m_table_alias; + + /// PERCONA_SEQUENCE_TABLE's data source expression + Item *m_source; + + Create_field m_value_field; + List m_vt_list; + + bool m_upper_bound_precalculated; + ulonglong m_precalculated_upper_bound; + + /** + Return list of fields to create result table from + */ + virtual List *get_field_list() override; + virtual bool do_init_args() override; + virtual void do_cleanup() override; + + ulonglong calculate_upper_bound() const; +}; + /** Print ON EMPTY or ON ERROR clauses.