From cc3c63cbae27c04939de4848cac39d0766894626 Mon Sep 17 00:00:00 2001 From: Kosov Eugene Date: Tue, 8 Nov 2016 21:57:22 +0300 Subject: Scripts: Ninja build system fix --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 4efe3a24e24..eafbb2e85a5 100644 --- a/.gitignore +++ b/.gitignore @@ -482,3 +482,7 @@ UpgradeLog*.htm # Microsoft Fakes FakesAssemblies/ + +compile_commands.json +.clang-format +storage/innobase/.clang-format \ No newline at end of file -- cgit v1.2.1 From 14bdfa85416471e4ccd4aaa65397f282a2b508c3 Mon Sep 17 00:00:00 2001 From: Daniel Fiala Date: Fri, 2 Sep 2016 19:03:36 +0200 Subject: Scripts: .gitignore --- .gitignore | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index eafbb2e85a5..0f240cd4619 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,17 @@ *-t *.ctest *.reject +*.orig *.spec *.bak *.dgcov *.rpm .*.swp +.#* +.vimrc +.editorconfig +.kateconfig +*.kdev4 *.ninja .ninja_* .gdb_history @@ -485,4 +491,4 @@ FakesAssemblies/ compile_commands.json .clang-format -storage/innobase/.clang-format \ No newline at end of file +.kscope/ -- cgit v1.2.1 From be6f2d302cd71677e1fafbeea9347c196f21e1bd Mon Sep 17 00:00:00 2001 From: Daniel Fiala Date: Sun, 19 Jun 2016 07:38:28 +0100 Subject: 0.1: SQL-level System Versioning --- include/mysql_com.h | 10 + mysql-test/extra/binlog_tests/blackhole.test | 4 +- mysql-test/include/common-tests.inc | 76 +++---- mysql-test/r/auto_increment.result | 59 +++++ mysql-test/r/compress.result | 114 +++++----- mysql-test/r/create.result | 91 +++++++- mysql-test/r/delete.result | 86 ++++++++ mysql-test/r/fulltext.result | 2 +- mysql-test/r/func_group.result | 2 +- mysql-test/r/func_time.result | 2 +- mysql-test/r/func_time_hires.result | 10 +- mysql-test/r/insert.result | 109 ++++++++++ mysql-test/r/insert_select.result | 118 ++++++++++ mysql-test/r/insert_update.result | 90 ++++++++ mysql-test/r/multi_update.result | 212 ++++++++++++++++++ mysql-test/r/named_pipe.result | 114 +++++----- mysql-test/r/pool_of_threads.result | 114 +++++----- mysql-test/r/select.result | 179 ++++++++++----- mysql-test/r/select_jcl6.result | 179 ++++++++++----- mysql-test/r/select_pkeycache.result | 179 ++++++++++----- mysql-test/r/shm.result | 114 +++++----- mysql-test/r/ssl.result | 114 +++++----- mysql-test/r/ssl_compress.result | 114 +++++----- mysql-test/r/update.result | 100 +++++++++ mysql-test/r/variables.result | 165 -------------- mysql-test/suite/archive/archive.result | 10 +- mysql-test/suite/archive/archive.test | 4 +- .../suite/binlog/r/binlog_stm_blackhole.result | 10 +- mysql-test/suite/csv/csv.result | 16 +- mysql-test/suite/csv/csv.test | 8 +- mysql-test/suite/funcs_1/r/innodb_views.result | 8 +- mysql-test/suite/funcs_1/r/memory_views.result | 8 +- mysql-test/suite/funcs_1/r/myisam_views-big.result | 8 +- mysql-test/suite/funcs_1/r/storedproc.result | 11 +- mysql-test/suite/innodb_fts/r/fulltext.result | 2 +- .../suite/sys_vars/r/delay_key_write_basic.result | 4 +- .../sys_vars/r/foreign_key_checks_basic.result | 4 +- .../sys_vars/r/innodb_support_xa_basic.result | 227 +++++++++++++++++++ .../sys_vars/r/innodb_table_locks_basic.result | 4 +- .../sys_vars/r/keep_files_on_create_basic.result | 4 +- .../r/log_bin_trust_function_creators_basic.result | 4 +- .../sys_vars/r/low_priority_updates_basic.result | 4 +- .../suite/sys_vars/r/old_passwords_basic.result | 4 +- .../sys_vars/r/optimizer_prune_level_basic.result | 2 +- .../sys_vars/r/pseudo_slave_mode_basic.result | 4 +- .../r/query_cache_wlock_invalidate_basic.result | 8 +- .../suite/sys_vars/r/sql_big_selects_basic.result | 4 +- .../suite/sys_vars/r/sql_big_tables_basic.result | 2 +- .../sys_vars/r/sql_buffer_result_basic.result | 4 +- .../suite/sys_vars/r/sql_log_bin_basic.result | 4 +- .../suite/sys_vars/r/sql_log_off_basic.result | 4 +- .../r/sql_low_priority_updates_basic.result | 4 +- mysql-test/suite/sys_vars/r/sql_notes_basic.result | 4 +- .../sys_vars/r/sql_quote_show_create_basic.result | 4 +- .../suite/sys_vars/r/sql_safe_updates_basic.result | 4 +- .../suite/sys_vars/r/sql_warnings_basic.result | 4 +- .../suite/sys_vars/r/tx_read_only_basic.result | 4 +- .../suite/sys_vars/t/delay_key_write_basic.test | 2 +- .../suite/sys_vars/t/foreign_key_checks_basic.test | 2 +- .../suite/sys_vars/t/innodb_support_xa_basic.test | 240 +++++++++++++++++++++ .../suite/sys_vars/t/innodb_table_locks_basic.test | 4 +- .../sys_vars/t/keep_files_on_create_basic.test | 2 +- .../t/log_bin_trust_function_creators_basic.test | 2 +- .../sys_vars/t/low_priority_updates_basic.test | 2 +- .../suite/sys_vars/t/old_passwords_basic.test | 2 +- .../sys_vars/t/optimizer_prune_level_basic.test | 2 +- .../suite/sys_vars/t/pseudo_slave_mode_basic.test | 2 +- .../t/query_cache_wlock_invalidate_basic.test | 4 +- .../suite/sys_vars/t/sql_big_selects_basic.test | 2 +- .../suite/sys_vars/t/sql_buffer_result_basic.test | 2 +- mysql-test/suite/sys_vars/t/sql_log_bin_basic.test | 2 +- mysql-test/suite/sys_vars/t/sql_log_off_basic.test | 2 +- mysql-test/suite/sys_vars/t/sql_notes_basic.test | 2 +- .../sys_vars/t/sql_quote_show_create_basic.test | 2 +- .../suite/sys_vars/t/sql_safe_updates_basic.test | 2 +- .../suite/sys_vars/t/sql_warnings_basic.test | 2 +- .../suite/sys_vars/t/tx_read_only_basic.test | 2 +- mysql-test/t/auto_increment.test | 34 +++ mysql-test/t/create.test | 98 +++++++++ mysql-test/t/delete.test | 44 ++++ mysql-test/t/insert.test | 73 +++++++ mysql-test/t/insert_select.test | 65 ++++++ mysql-test/t/insert_update.test | 45 ++++ mysql-test/t/multi_update.test | 116 ++++++++++ mysql-test/t/select.test | 110 ++++++---- mysql-test/t/update.test | 39 ++++ mysql-test/t/variables.test | 160 -------------- sql/field.cc | 16 ++ sql/field.h | 67 ++++++ sql/handler.h | 43 ++++ sql/item_timefunc.cc | 9 + sql/item_timefunc.h | 3 +- sql/lex.h | 4 + sql/share/errmsg-utf8.txt | 47 ++++ sql/sql_base.cc | 19 +- sql/sql_class.h | 11 +- sql/sql_delete.cc | 49 ++++- sql/sql_insert.cc | 90 +++++++- sql/sql_insert.h | 1 + sql/sql_lex.cc | 24 ++- sql/sql_lex.h | 6 + sql/sql_parse.cc | 64 ++++++ sql/sql_select.cc | 113 +++++++++- sql/sql_show.cc | 25 +++ sql/sql_table.cc | 132 +++++++++++- sql/sql_trigger.h | 2 +- sql/sql_update.cc | 140 +++++++++--- sql/sql_view.cc | 4 +- sql/sql_yacc.yy | 159 +++++++++++++- sql/table.cc | 124 ++++++++++- sql/table.h | 100 ++++++++- sql/unireg.cc | 80 +++++++ sql/unireg.h | 1 + .../mysql-test/tokudb/r/tokudb_support_xa.result | 2 +- .../mysql-test/tokudb/t/tokudb_support_xa.test | 2 +- 115 files changed, 4055 insertions(+), 1101 deletions(-) create mode 100644 mysql-test/suite/sys_vars/r/innodb_support_xa_basic.result create mode 100644 mysql-test/suite/sys_vars/t/innodb_support_xa_basic.test diff --git a/include/mysql_com.h b/include/mysql_com.h index ace54767b06..904a64b08f8 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -184,6 +184,16 @@ enum enum_indicator_type #define FIELD_FLAGS_COLUMN_FORMAT_MASK (3U << FIELD_FLAGS_COLUMN_FORMAT) #define FIELD_IS_DROPPED (1U << 26) /* Intern: Field is being dropped */ +#define GENERATED_ROW_START_FLAG (1 << 27) /* autogenerated column declared with + `generated always at row start` + (see II.a SQL Standard) */ +#define GENERATED_ROW_END_FLAG (1 << 28) /* autogenerated column declared with + `generated always at row end` + (see II.a SQL Standard).*/ +#define WITHOUT_SYSTEM_VERSIONING_FLAG (1 << 29) /* column that doesn't support + system versioning when table + itself supports it*/ + #define REFRESH_GRANT (1ULL << 0) /* Refresh grant tables */ #define REFRESH_LOG (1ULL << 1) /* Start on new log file */ #define REFRESH_TABLES (1ULL << 2) /* close all tables */ diff --git a/mysql-test/extra/binlog_tests/blackhole.test b/mysql-test/extra/binlog_tests/blackhole.test index 90146d41471..0ffd24adc03 100644 --- a/mysql-test/extra/binlog_tests/blackhole.test +++ b/mysql-test/extra/binlog_tests/blackhole.test @@ -17,13 +17,13 @@ drop table if exists t1,t2; --enable_warnings CREATE TABLE t1 ( - Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, + Period_ smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL ) ENGINE=blackhole; INSERT INTO t1 VALUES (9410,9412); -select period from t1; +select period_ from t1; select * from t1; select t1.* from t1; diff --git a/mysql-test/include/common-tests.inc b/mysql-test/include/common-tests.inc index 204b6d4dd6b..c0ed1427215 100644 --- a/mysql-test/include/common-tests.inc +++ b/mysql-test/include/common-tests.inc @@ -14,13 +14,13 @@ drop table if exists t1,t2,t3,t4; --enable_warnings CREATE TABLE t1 ( - Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, + Period_ smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL ); INSERT INTO t1 VALUES (9410,9412); -select period from t1; +select period_ from t1; select * from t1; select t1.* from t1; @@ -1349,7 +1349,7 @@ select fld1,fld3 from t2 where fld1 like "25050_"; select distinct companynr from t2; select distinct companynr from t2 order by companynr; select distinct companynr from t2 order by companynr desc; -select distinct t2.fld3,period from t2,t1 where companynr=37 and fld3 like "O%"; +select distinct t2.fld3,period_ from t2,t1 where companynr=37 and fld3 like "O%"; select distinct fld3 from t2 where companynr = 34 order by fld3; select distinct fld3 from t2 limit 10; @@ -1362,26 +1362,26 @@ select distinct substring(fld3,1,3) as a from t2 having a like "A%" limit 10; # make a big table. create table t3 ( - period int not null, + period_ int not null, name char(32) not null, companynr int not null, price double(11,0), price2 double(11,0), - key (period), + key (period_), key (name) ); --disable_query_log -INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1001,"Iranizes",37,5987435,234724); -INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1002,"violinist",37,28357832,8723648); -INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1003,"extramarital",37,39654943,235872); -INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1004,"spates",78,726498,72987523); -INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1005,"cloakroom",78,98439034,823742); -INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1006,"gazer",101,834598,27348324); -INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1007,"hand",154,983543950,29837423); -INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1008,"tucked",311,234298,3275892); -INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1009,"gems",447,2374834,9872392); -INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1010,"clinker",512,786542,76234234); +INSERT INTO t3 (period_,name,companynr,price,price2) VALUES (1001,"Iranizes",37,5987435,234724); +INSERT INTO t3 (period_,name,companynr,price,price2) VALUES (1002,"violinist",37,28357832,8723648); +INSERT INTO t3 (period_,name,companynr,price,price2) VALUES (1003,"extramarital",37,39654943,235872); +INSERT INTO t3 (period_,name,companynr,price,price2) VALUES (1004,"spates",78,726498,72987523); +INSERT INTO t3 (period_,name,companynr,price,price2) VALUES (1005,"cloakroom",78,98439034,823742); +INSERT INTO t3 (period_,name,companynr,price,price2) VALUES (1006,"gazer",101,834598,27348324); +INSERT INTO t3 (period_,name,companynr,price,price2) VALUES (1007,"hand",154,983543950,29837423); +INSERT INTO t3 (period_,name,companynr,price,price2) VALUES (1008,"tucked",311,234298,3275892); +INSERT INTO t3 (period_,name,companynr,price,price2) VALUES (1009,"gems",447,2374834,9872392); +INSERT INTO t3 (period_,name,companynr,price,price2) VALUES (1010,"clinker",512,786542,76234234); --enable_query_log create temporary table tmp engine = myisam select * from t3; @@ -1450,39 +1450,39 @@ explain select t3.t2nr,fld3 from t2,t3 where t2.companynr = 34 and t2.fld1=t3.t2 # Some test with ORDER BY and limit # -explain select * from t3 as t1,t3 where t1.period=t3.period order by t3.period; -explain select * from t3 as t1,t3 where t1.period=t3.period order by t3.period limit 10; -explain select * from t3 as t1,t3 where t1.period=t3.period order by t1.period limit 10; +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t3.period_; +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t3.period_ limit 10; +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t1.period_ limit 10; # # Search with a constant table. # -select period from t1; -select period from t1 where period=1900; -select fld3,period from t1,t2 where fld1 = 011401 order by period; +select period_ from t1; +select period_ from t1 where period_=1900; +select fld3,period_ from t1,t2 where fld1 = 011401 order by period_; # # Search with a constant table and several keyparts. (Rows are read only once # in the beginning of the search) # -select fld3,period from t2,t3 where t2.fld1 = 011401 and t2.fld1=t3.t2nr and t3.period=1001; +select fld3,period_ from t2,t3 where t2.fld1 = 011401 and t2.fld1=t3.t2nr and t3.period_=1001; -explain select fld3,period from t2,t3 where t2.fld1 = 011401 and t3.t2nr=t2.fld1 and 1001 = t3.period; +explain select fld3,period_ from t2,t3 where t2.fld1 = 011401 and t3.t2nr=t2.fld1 and 1001 = t3.period_; # # Search with a constant table and several rows from another table # -select fld3,period from t2,t1 where companynr*10 = 37*10; +select fld3,period_ from t2,t1 where companynr*10 = 37*10; # # Search with a table reference and without a key. # t3 will be the main table. # -select fld3,period,price,price2 from t2,t3 where t2.fld1=t3.t2nr and period >= 1001 and period <= 1002 and t2.companynr = 37 order by fld3,period, price; +select fld3,period_,price,price2 from t2,t3 where t2.fld1=t3.t2nr and period_ >= 1001 and period_ <= 1002 and t2.companynr = 37 order by fld3,period_, price; # # Search with an interval on a table with full key on reference table. @@ -1490,7 +1490,7 @@ select fld3,period,price,price2 from t2,t3 where t2.fld1=t3.t2nr and period >= 1 # t2nr will be checked. # -select t2.fld1,fld3,period,price,price2 from t2,t3 where t2.fld1>= 18201 and t2.fld1 <= 18811 and t2.fld1=t3.t2nr and period = 1001 and t2.companynr = 37; +select t2.fld1,fld3,period_,price,price2 from t2,t3 where t2.fld1>= 18201 and t2.fld1 <= 18811 and t2.fld1=t3.t2nr and period_ = 1001 and t2.companynr = 37; # # We need another table for join stuff.. @@ -1588,18 +1588,18 @@ explain select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr= # each record # -select t2.fld1,t2.companynr,fld3,period from t3,t2 where t2.fld1 = 38208 and t2.fld1=t3.t2nr and period = 1008 or t2.fld1 = 38008 and t2.fld1 =t3.t2nr and period = 1008; +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where t2.fld1 = 38208 and t2.fld1=t3.t2nr and period_ = 1008 or t2.fld1 = 38008 and t2.fld1 =t3.t2nr and period_ = 1008; -select t2.fld1,t2.companynr,fld3,period from t3,t2 where (t2.fld1 = 38208 or t2.fld1 = 38008) and t2.fld1=t3.t2nr and period>=1008 and period<=1009; +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where (t2.fld1 = 38208 or t2.fld1 = 38008) and t2.fld1=t3.t2nr and period_>=1008 and period_<=1009; -select t2.fld1,t2.companynr,fld3,period from t3,t2 where (t3.t2nr = 38208 or t3.t2nr = 38008) and t2.fld1=t3.t2nr and period>=1008 and period<=1009; +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where (t3.t2nr = 38208 or t3.t2nr = 38008) and t2.fld1=t3.t2nr and period_>=1008 and period_<=1009; # # Test of many parenthesis levels # -select period from t1 where (((period > 0) or period < 10000 or (period = 1900)) and (period=1900 and period <= 1901) or (period=1903 and (period=1903)) and period>=1902) or ((period=1904 or period=1905) or (period=1906 or period>1907)) or (period=1908 and period = 1909); -select period from t1 where ((period > 0 and period < 1) or (((period > 0 and period < 100) and (period > 10)) or (period > 10)) or (period > 0 and (period > 5 or period > 6))); +select period_ from t1 where (((period_ > 0) or period_ < 10000 or (period_ = 1900)) and (period_=1900 and period_ <= 1901) or (period_=1903 and (period_=1903)) and period_>=1902) or ((period_=1904 or period_=1905) or (period_=1906 or period_>1907)) or (period_=1908 and period_ = 1909); +select period_ from t1 where ((period_ > 0 and period_ < 1) or (((period_ > 0 and period_ < 100) and (period_ > 10)) or (period_ > 10)) or (period_ > 0 and (period_ > 5 or period_ > 6))); select a.fld1 from t2 as a,t2 b where ((a.fld1 = 250501 and a.fld1=b.fld1) or a.fld1=250502 or a.fld1=250503 or (a.fld1=250505 and a.fld1<=b.fld1 and b.fld1>=a.fld1)) and a.fld1=b.fld1; @@ -1657,7 +1657,7 @@ select t2.fld1,count(*) from t2,t3 where t2.fld1=158402 and t3.name=t2.fld3 grou # Calculation with group functions # -select sum(Period)/count(*) from t1; +select sum(Period_)/count(*) from t1; select companynr,count(price) as "count",sum(price) as "sum" ,abs(sum(price)/count(price)-avg(price)) as "diff",(0+count(price))*companynr as func from t3 group by companynr; select companynr,sum(price)/count(price) as avg from t3 group by companynr having avg > 70000000 order by avg; @@ -1747,13 +1747,13 @@ select max(t2nr) from t3 where price=983543950; # Test of alias # -select t1.period from t3 = t1 limit 1; -select t1.period from t1 as t1 limit 1; -select t1.period as "Nuvarande period" from t1 as t1 limit 1; -select period as ok_period from t1 limit 1; -select period as ok_period from t1 group by ok_period limit 1; +select t1.period_ from t3 = t1 limit 1; +select t1.period_ from t1 as t1 limit 1; +select t1.period_ as "Nuvarande period_" from t1 as t1 limit 1; +select period_ as ok_period from t1 limit 1; +select period_ as ok_period from t1 group by ok_period limit 1; select 1+1 as summa from t1 group by summa limit 1; -select period as "Nuvarande period" from t1 group by "Nuvarande period" limit 1; +select period_ as "Nuvarande period_" from t1 group by "Nuvarande period_" limit 1; # # Some simple show commands diff --git a/mysql-test/r/auto_increment.result b/mysql-test/r/auto_increment.result index 12cbf294b69..bb684d1930f 100644 --- a/mysql-test/r/auto_increment.result +++ b/mysql-test/r/auto_increment.result @@ -537,3 +537,62 @@ pk -5 1 drop table t1; +# +# System Versioning Support +# +# +CREATE TABLE t1(id INT UNSIGNED AUTO_INCREMENT, x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end), PRIMARY KEY (id)) WITH SYSTEM VERSIONING; +CREATE TABLE T1(id INT UNSIGNED AUTO_INCREMENT, x INT UNSIGNED, y INT UNSIGNED, PRIMARY KEY (id)); +INSERT INTO t1(x, y) VALUES(1, 11); +INSERT INTO T1(x, y) VALUES(1, 11); +INSERT INTO t1(x, y) VALUES(2, 12); +INSERT INTO T1(x, y) VALUES(2, 12); +INSERT INTO t1(x, y) VALUES(3, 13); +INSERT INTO T1(x, y) VALUES(3, 13); +INSERT INTO t1(x, y) VALUES(4, 14); +INSERT INTO T1(x, y) VALUES(4, 14); +INSERT INTO t1(x, y) VALUES(5, 15); +INSERT INTO T1(x, y) VALUES(5, 15); +INSERT INTO t1(x, y) VALUES(6, 16); +INSERT INTO T1(x, y) VALUES(6, 16); +INSERT INTO t1(x, y) VALUES(7, 17); +INSERT INTO T1(x, y) VALUES(7, 17); +INSERT INTO t1(x, y) VALUES(8, 18); +INSERT INTO T1(x, y) VALUES(8, 18); +INSERT INTO t1(x, y) VALUES(9, 19); +INSERT INTO T1(x, y) VALUES(9, 19); +SELECT t1.x = T1.x AND t1.y = T1.y, t1.x, t1.y, T1.x, T1.y FROM t1 INNER JOIN T1 ON(t1.id = T1.id); +t1.x = T1.x AND t1.y = T1.y x y x y +1 1 11 1 11 +1 2 12 2 12 +1 3 13 3 13 +1 4 14 4 14 +1 5 15 5 15 +1 6 16 6 16 +1 7 17 7 17 +1 8 18 8 18 +1 9 19 9 19 +DELETE FROM t1 WHERE x=2; +DELETE FROM T1 WHERE x=2; +SELECT t1.x = T1.x AND t1.y = T1.y, t1.x, t1.y, T1.x, T1.y FROM t1 INNER JOIN T1 ON(t1.id = T1.id); +t1.x = T1.x AND t1.y = T1.y x y x y +1 1 11 1 11 +1 3 13 3 13 +1 4 14 4 14 +1 5 15 5 15 +1 6 16 6 16 +1 7 17 7 17 +1 8 18 8 18 +1 9 19 9 19 +DELETE FROM t1 WHERE x>7; +DELETE FROM T1 WHERE x>7; +SELECT t1.x = T1.x AND t1.y = T1.y, t1.x, t1.y, T1.x, T1.y FROM t1 INNER JOIN T1 ON(t1.id = T1.id); +t1.x = T1.x AND t1.y = T1.y x y x y +1 1 11 1 11 +1 3 13 3 13 +1 4 14 4 14 +1 5 15 5 15 +1 6 16 6 16 +1 7 17 7 17 +DROP TABLE t1; +DROP TABLE T1; diff --git a/mysql-test/r/compress.result b/mysql-test/r/compress.result index 762ab6630d8..b16a95cc702 100644 --- a/mysql-test/r/compress.result +++ b/mysql-test/r/compress.result @@ -7,18 +7,18 @@ VARIABLE_NAME VARIABLE_VALUE COMPRESSION ON drop table if exists t1,t2,t3,t4; CREATE TABLE t1 ( -Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, +Period_ smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL ); INSERT INTO t1 VALUES (9410,9412); -select period from t1; -period +select period_ from t1; +period_ 9410 select * from t1; -Period Varor_period +Period_ Varor_period 9410 9412 select t1.* from t1; -Period Varor_period +Period_ Varor_period 9410 9412 CREATE TABLE t2 ( auto int not null auto_increment, @@ -282,8 +282,8 @@ companynr 34 29 00 -select distinct t2.fld3,period from t2,t1 where companynr=37 and fld3 like "O%"; -fld3 period +select distinct t2.fld3,period_ from t2,t1 where companynr=37 and fld3 like "O%"; +fld3 period_ obliterates 9410 offload 9410 opaquely 9410 @@ -487,12 +487,12 @@ acu Ade adj create table t3 ( -period int not null, +period_ int not null, name char(32) not null, companynr int not null, price double(11,0), price2 double(11,0), -key (period), +key (period_), key (name) ); create temporary table tmp engine = myisam select * from t3; @@ -606,35 +606,35 @@ explain select t3.t2nr,fld3 from t2,t3 where t2.companynr = 34 and t2.fld1=t3.t2 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL fld1 NULL NULL NULL 1199 Using where; Using temporary; Using filesort 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.fld1 1 Using where; Using index -explain select * from t3 as t1,t3 where t1.period=t3.period order by t3.period; +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t3.period_; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL period NULL NULL NULL 41810 Using filesort -1 SIMPLE t3 ref period period 4 test.t1.period 4181 -explain select * from t3 as t1,t3 where t1.period=t3.period order by t3.period limit 10; +1 SIMPLE t1 ALL period_ NULL NULL NULL 41810 Using filesort +1 SIMPLE t3 ref period_ period_ 4 test.t1.period_ 4181 +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t3.period_ limit 10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t3 index period period 4 NULL 1 -1 SIMPLE t1 ref period period 4 test.t3.period 4181 -explain select * from t3 as t1,t3 where t1.period=t3.period order by t1.period limit 10; +1 SIMPLE t3 index period_ period_ 4 NULL 1 +1 SIMPLE t1 ref period_ period_ 4 test.t3.period_ 4181 +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t1.period_ limit 10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index period period 4 NULL 1 -1 SIMPLE t3 ref period period 4 test.t1.period 4181 -select period from t1; -period +1 SIMPLE t1 index period_ period_ 4 NULL 1 +1 SIMPLE t3 ref period_ period_ 4 test.t1.period_ 4181 +select period_ from t1; +period_ 9410 -select period from t1 where period=1900; -period -select fld3,period from t1,t2 where fld1 = 011401 order by period; -fld3 period +select period_ from t1 where period_=1900; +period_ +select fld3,period_ from t1,t2 where fld1 = 011401 order by period_; +fld3 period_ breaking 9410 -select fld3,period from t2,t3 where t2.fld1 = 011401 and t2.fld1=t3.t2nr and t3.period=1001; -fld3 period +select fld3,period_ from t2,t3 where t2.fld1 = 011401 and t2.fld1=t3.t2nr and t3.period_=1001; +fld3 period_ breaking 1001 -explain select fld3,period from t2,t3 where t2.fld1 = 011401 and t3.t2nr=t2.fld1 and 1001 = t3.period; +explain select fld3,period_ from t2,t3 where t2.fld1 = 011401 and t3.t2nr=t2.fld1 and 1001 = t3.period_; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 const fld1 fld1 4 const 1 -1 SIMPLE t3 const PRIMARY,period PRIMARY 4 const 1 -select fld3,period from t2,t1 where companynr*10 = 37*10; -fld3 period +1 SIMPLE t3 const PRIMARY,period_ PRIMARY 4 const 1 +select fld3,period_ from t2,t1 where companynr*10 = 37*10; +fld3 period_ breaking 9410 Romans 9410 intercepted 9410 @@ -1223,8 +1223,8 @@ dusted 9410 encompasses 9410 presentation 9410 Kantian 9410 -select fld3,period,price,price2 from t2,t3 where t2.fld1=t3.t2nr and period >= 1001 and period <= 1002 and t2.companynr = 37 order by fld3,period, price; -fld3 period price price2 +select fld3,period_,price,price2 from t2,t3 where t2.fld1=t3.t2nr and period_ >= 1001 and period_ <= 1002 and t2.companynr = 37 order by fld3,period_, price; +fld3 period_ price price2 admonishing 1002 28357832 8723648 analyzable 1002 28357832 8723648 annihilates 1001 5987435 234724 @@ -1284,8 +1284,8 @@ ventilate 1001 5987435 234724 wallet 1001 5987435 234724 Weissmuller 1002 28357832 8723648 Wotan 1002 28357832 8723648 -select t2.fld1,fld3,period,price,price2 from t2,t3 where t2.fld1>= 18201 and t2.fld1 <= 18811 and t2.fld1=t3.t2nr and period = 1001 and t2.companynr = 37; -fld1 fld3 period price price2 +select t2.fld1,fld3,period_,price,price2 from t2,t3 where t2.fld1>= 18201 and t2.fld1 <= 18811 and t2.fld1=t3.t2nr and period_ = 1001 and t2.companynr = 37; +fld1 fld3 period_ price price2 018201 relaxing 1001 5987435 234724 018601 vacuuming 1001 5987435 234724 018801 inch 1001 5987435 234724 @@ -1325,7 +1325,7 @@ companynr companyname 65 company 9 68 company 10 select * from t1,t1 t12; -Period Varor_period Period Varor_period +Period_ Varor_period Period_ Varor_period 9410 9412 9410 9412 select t2.fld1,t22.fld1 from t2,t2 t22 where t2.fld1 >= 250501 and t2.fld1 <= 250505 and t22.fld1 >= 250501 and t22.fld1 <= 250505; fld1 fld1 @@ -1440,23 +1440,23 @@ explain select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr= id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t4 index NULL PRIMARY 1 NULL 12 Using index; Using temporary 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where; Using join buffer (flat, BNL join) -select t2.fld1,t2.companynr,fld3,period from t3,t2 where t2.fld1 = 38208 and t2.fld1=t3.t2nr and period = 1008 or t2.fld1 = 38008 and t2.fld1 =t3.t2nr and period = 1008; -fld1 companynr fld3 period +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where t2.fld1 = 38208 and t2.fld1=t3.t2nr and period_ = 1008 or t2.fld1 = 38008 and t2.fld1 =t3.t2nr and period_ = 1008; +fld1 companynr fld3 period_ 038008 37 reporters 1008 038208 37 Selfridge 1008 -select t2.fld1,t2.companynr,fld3,period from t3,t2 where (t2.fld1 = 38208 or t2.fld1 = 38008) and t2.fld1=t3.t2nr and period>=1008 and period<=1009; -fld1 companynr fld3 period +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where (t2.fld1 = 38208 or t2.fld1 = 38008) and t2.fld1=t3.t2nr and period_>=1008 and period_<=1009; +fld1 companynr fld3 period_ 038008 37 reporters 1008 038208 37 Selfridge 1008 -select t2.fld1,t2.companynr,fld3,period from t3,t2 where (t3.t2nr = 38208 or t3.t2nr = 38008) and t2.fld1=t3.t2nr and period>=1008 and period<=1009; -fld1 companynr fld3 period +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where (t3.t2nr = 38208 or t3.t2nr = 38008) and t2.fld1=t3.t2nr and period_>=1008 and period_<=1009; +fld1 companynr fld3 period_ 038008 37 reporters 1008 038208 37 Selfridge 1008 -select period from t1 where (((period > 0) or period < 10000 or (period = 1900)) and (period=1900 and period <= 1901) or (period=1903 and (period=1903)) and period>=1902) or ((period=1904 or period=1905) or (period=1906 or period>1907)) or (period=1908 and period = 1909); -period +select period_ from t1 where (((period_ > 0) or period_ < 10000 or (period_ = 1900)) and (period_=1900 and period_ <= 1901) or (period_=1903 and (period_=1903)) and period_>=1902) or ((period_=1904 or period_=1905) or (period_=1906 or period_>1907)) or (period_=1908 and period_ = 1909); +period_ 9410 -select period from t1 where ((period > 0 and period < 1) or (((period > 0 and period < 100) and (period > 10)) or (period > 10)) or (period > 0 and (period > 5 or period > 6))); -period +select period_ from t1 where ((period_ > 0 and period_ < 1) or (((period_ > 0 and period_ < 100) and (period_ > 10)) or (period_ > 10)) or (period_ > 0 and (period_ > 5 or period_ > 6))); +period_ 9410 select a.fld1 from t2 as a,t2 b where ((a.fld1 = 250501 and a.fld1=b.fld1) or a.fld1=250502 or a.fld1=250503 or (a.fld1=250505 and a.fld1<=b.fld1 and b.fld1>=a.fld1)) and a.fld1=b.fld1; fld1 @@ -1713,8 +1713,8 @@ companynr companyname count(*) select t2.fld1,count(*) from t2,t3 where t2.fld1=158402 and t3.name=t2.fld3 group by t3.name; fld1 count(*) 158402 4181 -select sum(Period)/count(*) from t1; -sum(Period)/count(*) +select sum(Period_)/count(*) from t1; +sum(Period_)/count(*) 9410.0000 select companynr,count(price) as "count",sum(price) as "sum" ,abs(sum(price)/count(price)-avg(price)) as "diff",(0+count(price))*companynr as func from t3 group by companynr; companynr count sum diff func @@ -2044,26 +2044,26 @@ t2nr count(*) select max(t2nr) from t3 where price=983543950; max(t2nr) 41807 -select t1.period from t3 = t1 limit 1; -period +select t1.period_ from t3 = t1 limit 1; +period_ 1001 -select t1.period from t1 as t1 limit 1; -period +select t1.period_ from t1 as t1 limit 1; +period_ 9410 -select t1.period as "Nuvarande period" from t1 as t1 limit 1; -Nuvarande period +select t1.period_ as "Nuvarande period_" from t1 as t1 limit 1; +Nuvarande period_ 9410 -select period as ok_period from t1 limit 1; +select period_ as ok_period from t1 limit 1; ok_period 9410 -select period as ok_period from t1 group by ok_period limit 1; +select period_ as ok_period from t1 group by ok_period limit 1; ok_period 9410 select 1+1 as summa from t1 group by summa limit 1; summa 2 -select period as "Nuvarande period" from t1 group by "Nuvarande period" limit 1; -Nuvarande period +select period_ as "Nuvarande period_" from t1 group by "Nuvarande period_" limit 1; +Nuvarande period_ 9410 show tables; Tables_in_test diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 81b65c420cd..941ba2837d2 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -132,7 +132,7 @@ drop table t2; create table t2 select now() as a , curtime() as b, curdate() as c , 1+1 as d , 1.0 + 1 as e , 33333333333333333 + 3 as f; describe t2; Field Type Null Key Default Extra -a datetime NO NULL +a datetime YES NULL b time NO NULL c date NO NULL d int(3) NO NULL @@ -1931,3 +1931,92 @@ create table t1 (i int, j int, key(i), key(i)) as select 1 as i, 2 as j; Warnings: Note 1831 Duplicate index `i_2`. This is deprecated and will be disallowed in a future release drop table t1; +# +# Test for SYSTEM VERSIONING CREATE +# +create table t1 ( +XNo INT UNSIGNED, +Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, +Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, +PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) +) WITH SYSTEM VERSIONING; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `XNo` int(10) unsigned DEFAULT NULL, + `Sys_start` timestamp(6) NOT NULL GENERATED AS ROW START, + `Sys_end` timestamp(6) NOT NULL GENERATED AS ROW END, + PERIOD FOR SYSTEM_TIME (`Sys_start`, `Sys_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +drop table if exists t1; +create table t1 ( +XNo INT UNSIGNED, +Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, +Sys_start2 TIMESTAMP(6) GENERATED ALWAYS AS ROW START, +Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, +PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) +) WITH SYSTEM VERSIONING; +ERROR HY000: 'Generated as row start' specified more than once +create table t1 ( +XNo INT UNSIGNED, +Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, +Sys_end2 TIMESTAMP(6) GENERATED ALWAYS AS ROW END, +PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) +) WITH SYSTEM VERSIONING; +ERROR HY000: Second column in 'period for system time' must be equal to 'generated as row end' column +create table t1 ( +XNo INT UNSIGNED, +Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, +Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, +Sys_end2 TIMESTAMP(6) GENERATED ALWAYS AS ROW END, +PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) +) WITH SYSTEM VERSIONING; +ERROR HY000: Generated as row end specified more than once +create table t1 ( +XNo INT UNSIGNED, +PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) +) WITH SYSTEM VERSIONING; +ERROR HY000: 'Generated as row start' not specified +create table t1 ( +XNo INT UNSIGNED, +Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, +Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, +Sys_end2 TIMESTAMP(6) GENERATED ALWAYS AS ROW END, +PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) +); +ERROR HY000: Generated as row end specified more than once +create table t1 ( +XNo INT UNSIGNED, +Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, +Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, +PERIOD FOR SYSTEM_TIME (Sys_insert, Sys_remove) +) WITH SYSTEM VERSIONING; +ERROR HY000: First column in 'period for system time' must be equal to 'generated as row start' column +create table t1 ( +XNo INT UNSIGNED, +Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, +Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, +PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) +); +ERROR HY000: 'With system versioning' is missing +create table t1 ( +XNo INT UNSIGNED, +Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, +Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, +PERIOD FOR SYSTEM_TIME (Sys_start, Sys_start) +); +ERROR HY000: 'Period for system_time' must contain two different columns +create table t1 ( +XNo INT UNSIGNED, +Sys_start INT GENERATED ALWAYS AS ROW START, +Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, +PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) +) WITH SYSTEM VERSIONING; +ERROR HY000: System start field must be of type TIMESTAMP +create table t1 ( +XNo INT UNSIGNED, +Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, +Sys_end INT GENERATED ALWAYS AS ROW END, +PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) +) WITH SYSTEM VERSIONING; +ERROR HY000: System end field must be of type TIMESTAMP diff --git a/mysql-test/r/delete.result b/mysql-test/r/delete.result index ed3683d52f9..1ee160b6864 100644 --- a/mysql-test/r/delete.result +++ b/mysql-test/r/delete.result @@ -525,3 +525,89 @@ DELETE v2 FROM v2; ERROR HY000: Can not delete from join view 'test.v2' DROP VIEW v2, v1; DROP TABLE t1, t2; +# +# Test for SYSTEM VERSIONING +# +SET @@session.time_zone='+00:00'; +create table t1 ( +XNo INT UNSIGNED, +Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, +Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, +PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) +) WITH SYSTEM VERSIONING; +INSERT INTO t1(XNo) VALUES(0); +INSERT INTO t1(XNo) VALUES(1); +INSERT INTO t1(XNo) VALUES(2); +INSERT INTO t1(XNo) VALUES(3); +INSERT INTO t1(XNo) VALUES(4); +INSERT INTO t1(XNo) VALUES(5); +INSERT INTO t1(XNo) VALUES(6); +INSERT INTO t1(XNo) VALUES(7); +INSERT INTO t1(XNo) VALUES(8); +INSERT INTO t1(XNo) VALUES(9); +SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; +XNo Sys_end < '2038-01-19 03:14:07' +0 0 +1 0 +2 0 +3 0 +4 0 +5 0 +6 0 +7 0 +8 0 +9 0 +DELETE FROM t1 WHERE XNo = 0; +SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; +XNo Sys_end < '2038-01-19 03:14:07' +0 1 +1 0 +2 0 +3 0 +4 0 +5 0 +6 0 +7 0 +8 0 +9 0 +DELETE FROM t1 WHERE XNo = 1; +SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; +XNo Sys_end < '2038-01-19 03:14:07' +0 1 +1 1 +2 0 +3 0 +4 0 +5 0 +6 0 +7 0 +8 0 +9 0 +DELETE FROM t1 WHERE XNo > 5; +CREATE VIEW vt1 AS SELECT XNo FROM t1; +SELECT XNo FROM vt1; +XNo +2 +3 +4 +5 +DELETE FROM vt1 WHERE XNo = 3; +SELECT XNo FROM vt1; +XNo +2 +4 +5 +SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; +XNo Sys_end < '2038-01-19 03:14:07' +0 1 +1 1 +2 0 +3 1 +4 0 +5 0 +6 1 +7 1 +8 1 +9 1 +DROP VIEW vt1; +DROP TABLE t1; diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result index 7ee5a68ca90..fa09d13b868 100644 --- a/mysql-test/r/fulltext.result +++ b/mysql-test/r/fulltext.result @@ -49,7 +49,7 @@ a b Full-text indexes are called collections Only MyISAM tables support collections select * from t1 where MATCH(a,b) AGAINST ("indexes" IN BOOLEAN MODE WITH QUERY EXPANSION); -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'QUERY EXPANSION)' at line 1 +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WITH QUERY EXPANSION)' at line 1 explain select * from t1 where MATCH(a,b) AGAINST ("collections"); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 fulltext a a 0 1 Using where diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index c85a50b2ea9..2b06467ce13 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -787,7 +787,7 @@ drop table t2; create table t2 select f2 from (select now() f2 from t1) a; show columns from t2; Field Type Null Key Default Extra -f2 datetime NO NULL +f2 datetime YES NULL drop table t2, t1; CREATE TABLE t1( id int PRIMARY KEY, diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index 54da823c439..b721d7e1146 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -950,7 +950,7 @@ sec_to_time(1) + 0, from_unixtime(1) + 0; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `now() - now()` bigint(21) NOT NULL, + `now() - now()` bigint(21) DEFAULT NULL, `curtime() - curtime()` bigint(12) NOT NULL, `sec_to_time(1) + 0` bigint(12) DEFAULT NULL, `from_unixtime(1) + 0` bigint(21) DEFAULT NULL diff --git a/mysql-test/r/func_time_hires.result b/mysql-test/r/func_time_hires.result index 0f822456724..17c55d554bc 100644 --- a/mysql-test/r/func_time_hires.result +++ b/mysql-test/r/func_time_hires.result @@ -39,14 +39,14 @@ t1 CREATE TABLE `t1` ( `sec_to_time(12345)` time DEFAULT NULL, `sec_to_time(12345.6789)` time(4) DEFAULT NULL, `sec_to_time(1234567e-2)` time(6) DEFAULT NULL, - `now()` datetime NOT NULL, + `now()` datetime DEFAULT NULL, `curtime(0)` time NOT NULL, - `utc_timestamp(1)` datetime(1) NOT NULL, + `utc_timestamp(1)` datetime(1) DEFAULT NULL, `utc_time(2)` time(2) NOT NULL, `current_time(3)` time(3) NOT NULL, - `current_timestamp(4)` datetime(4) NOT NULL, - `localtime(5)` datetime(5) NOT NULL, - `localtimestamp(6)` datetime(6) NOT NULL, + `current_timestamp(4)` datetime(4) DEFAULT NULL, + `localtime(5)` datetime(5) DEFAULT NULL, + `localtimestamp(6)` datetime(6) DEFAULT NULL, `time_to_sec(123456)` bigint(17) DEFAULT NULL, `time_to_sec('12:34:56.789')` decimal(19,3) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 diff --git a/mysql-test/r/insert.result b/mysql-test/r/insert.result index c9e3dc7b253..5837e1faa44 100644 --- a/mysql-test/r/insert.result +++ b/mysql-test/r/insert.result @@ -717,3 +717,112 @@ insert ignore into t1 values (1,12); Warnings: Warning 1062 Duplicate entry '1' for key 'f1' DROP TABLE t1; +# +# System Versioning Support +# +# +SET @@session.time_zone='+00:00'; +CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; +INSERT INTO t1(x, y) VALUES(3, 4); +INSERT INTO t1(x, y) VALUES(2, 3); +INSERT INTO t1 VALUES(40, 33); +SELECT x, y, Sys_end FROM t1; +x y Sys_end +3 4 2038-01-19 03:14:07.000000 +2 3 2038-01-19 03:14:07.000000 +40 33 2038-01-19 03:14:07.000000 +DROP TABLE t1; +CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; +INSERT INTO t1(x, y) VALUES(3, 4); +INSERT INTO t1(x, y) VALUES(2, 3); +INSERT INTO t1 VALUES(40, 33); +SELECT x, y, Sys_end FROM t1; +x y Sys_end +3 4 2038-01-19 03:14:07.000000 +2 3 2038-01-19 03:14:07.000000 +40 33 2038-01-19 03:14:07.000000 +DROP TABLE t1; +CREATE TABLE t1(id INT UNSIGNED NOT NULL AUTO_INCREMENT, x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end), PRIMARY KEY(id)) WITH SYSTEM VERSIONING; +INSERT INTO t1(x, y) VALUES(33, 44); +INSERT INTO t1(id, x, y) VALUES(20, 33, 44); +INSERT INTO t1 VALUES(40, 33, 44); +SELECT id, x, y, Sys_end FROM t1; +id x y Sys_end +1 33 44 2038-01-19 03:14:07.000000 +20 33 44 2038-01-19 03:14:07.000000 +40 33 44 2038-01-19 03:14:07.000000 +DROP TABLE t1; +CREATE TABLE t1(id INT UNSIGNED NOT NULL AUTO_INCREMENT, x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end), PRIMARY KEY(id)) WITH SYSTEM VERSIONING ENGINE=InnoDB; +INSERT INTO t1(x, y) VALUES(33, 44); +INSERT INTO t1(id, x, y) VALUES(20, 33, 44); +INSERT INTO t1 VALUES(40, 33, 44); +SELECT id, x, y, Sys_end FROM t1; +id x y Sys_end +1 33 44 2038-01-19 03:14:07.000000 +20 33 44 2038-01-19 03:14:07.000000 +40 33 44 2038-01-19 03:14:07.000000 +DROP TABLE t1; +CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; +CREATE VIEW vt1_1 AS SELECT x, y FROM t1; +CREATE VIEW vt1_2 AS SELECT x, y, Sys_end FROM t1; +INSERT INTO t1(x, y) VALUES(8001, 9001); +INSERT INTO t1(x, y, Sys_end) VALUES(8001, 9001, '2015-1-1 0:0:0'); +ERROR HY000: Generated field for System Versioning cannot be set by user +INSERT INTO vt1_1(x, y) VALUES(1001, 2001); +INSERT INTO vt1_1 VALUES(1002, 2002); +INSERT INTO vt1_2(x, y) VALUES(3001, 4001); +INSERT INTO vt1_2 VALUES(3002, 4002, '2015-1-1 0:0:0'); +ERROR HY000: Generated field for System Versioning cannot be set by user +SELECT x, y, Sys_end FROM t1; +x y Sys_end +8001 9001 2038-01-19 03:14:07.000000 +1001 2001 2038-01-19 03:14:07.000000 +1002 2002 2038-01-19 03:14:07.000000 +3001 4001 2038-01-19 03:14:07.000000 +SELECT x, y FROM vt1_1; +x y +8001 9001 +1001 2001 +1002 2002 +3001 4001 +SELECT x, y, Sys_end FROM vt1_2; +x y Sys_end +8001 9001 2038-01-19 03:14:07.000000 +1001 2001 2038-01-19 03:14:07.000000 +1002 2002 2038-01-19 03:14:07.000000 +3001 4001 2038-01-19 03:14:07.000000 +DROP TABLE t1; +DROP VIEW vt1_1; +DROP VIEW vt1_2; +CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; +CREATE VIEW vt1_1 AS SELECT x, y FROM t1; +CREATE VIEW vt1_2 AS SELECT x, y, Sys_end FROM t1; +INSERT INTO t1(x, y) VALUES(8001, 9001); +INSERT INTO t1(x, y, Sys_end) VALUES(8001, 9001, '2015-1-1 0:0:0'); +ERROR HY000: Generated field for System Versioning cannot be set by user +INSERT INTO vt1_1(x, y) VALUES(1001, 2001); +INSERT INTO vt1_1 VALUES(1002, 2002); +INSERT INTO vt1_2(x, y) VALUES(3001, 4001); +INSERT INTO vt1_2 VALUES(3002, 4002, '2015-1-1 0:0:0'); +ERROR HY000: Generated field for System Versioning cannot be set by user +SELECT x, y, Sys_end FROM t1; +x y Sys_end +8001 9001 2038-01-19 03:14:07.000000 +1001 2001 2038-01-19 03:14:07.000000 +1002 2002 2038-01-19 03:14:07.000000 +3001 4001 2038-01-19 03:14:07.000000 +SELECT x, y FROM vt1_1; +x y +8001 9001 +1001 2001 +1002 2002 +3001 4001 +SELECT x, y, Sys_end FROM vt1_2; +x y Sys_end +8001 9001 2038-01-19 03:14:07.000000 +1001 2001 2038-01-19 03:14:07.000000 +1002 2002 2038-01-19 03:14:07.000000 +3001 4001 2038-01-19 03:14:07.000000 +DROP TABLE t1; +DROP VIEW vt1_1; +DROP VIEW vt1_2; diff --git a/mysql-test/r/insert_select.result b/mysql-test/r/insert_select.result index 1a3a38b1f35..da236c53825 100644 --- a/mysql-test/r/insert_select.result +++ b/mysql-test/r/insert_select.result @@ -856,3 +856,121 @@ INSERT IGNORE INTO t1 SELECT t1.a FROM t1,t1 t2,t1 t3,t1 t4,t1 t5,t1 t6,t1 t7; SET GLOBAL myisam_data_pointer_size = @old_myisam_data_pointer_size; DROP TABLE t1; End of 5.1 tests +# +# System Versioning Support +# +# +CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=MyISAM; +CREATE TABLE t2(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=MyISAM; +INSERT INTO t1(x, y) VALUES +(1, 1000), +(2, 2000), +(3, 3000), +(4, 4000), +(5, 5000), +(6, 6000), +(7, 7000), +(8, 8000), +(9, 9000); +DELETE FROM t1 WHERE x >= 1; +INSERT INTO t1(x, y) VALUES +(1, 1001), +(2, 2001), +(3, 3001), +(4, 4001), +(5, 5001), +(6, 6001), +(7, 7001), +(8, 8001), +(9, 9001); +INSERT INTO t2 SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; +SELECT x, y FROM t1; +x y +1 1001 +2 2001 +3 3001 +4 4001 +5 5001 +6 6001 +7 7001 +8 8001 +9 9001 +SELECT x, y FROM t2; +x y +1 1000 +2 2000 +3 3000 +4 4000 +5 5000 +6 6000 +7 7000 +8 8000 +9 9000 +1 1001 +2 2001 +3 3001 +4 4001 +5 5001 +6 6001 +7 7001 +8 8001 +9 9001 +DROP TABLE t1; +DROP TABLE t2; +CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; +CREATE TABLE t2(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; +INSERT INTO t1(x, y) VALUES +(1, 1000), +(2, 2000), +(3, 3000), +(4, 4000), +(5, 5000), +(6, 6000), +(7, 7000), +(8, 8000), +(9, 9000); +DELETE FROM t1 WHERE x >= 1; +INSERT INTO t1(x, y) VALUES +(1, 1001), +(2, 2001), +(3, 3001), +(4, 4001), +(5, 5001), +(6, 6001), +(7, 7001), +(8, 8001), +(9, 9001); +INSERT INTO t2 SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; +SELECT x, y FROM t1; +x y +1 1001 +2 2001 +3 3001 +4 4001 +5 5001 +6 6001 +7 7001 +8 8001 +9 9001 +SELECT x, y FROM t2; +x y +1 1000 +2 2000 +3 3000 +4 4000 +5 5000 +6 6000 +7 7000 +8 8000 +9 9000 +1 1001 +2 2001 +3 3001 +4 4001 +5 5001 +6 6001 +7 7001 +8 8001 +9 9001 +DROP TABLE t1; +DROP TABLE t2; diff --git a/mysql-test/r/insert_update.result b/mysql-test/r/insert_update.result index e8e6e16fe5a..6f25fd18b6a 100644 --- a/mysql-test/r/insert_update.result +++ b/mysql-test/r/insert_update.result @@ -412,3 +412,93 @@ select if( @stamp1 = @stamp2, "correct", "wrong"); if( @stamp1 = @stamp2, "correct", "wrong") correct drop table t1; +# +# System Versioning Support +# +# +CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end), PRIMARY KEY(x, y)) WITH SYSTEM VERSIONING; +INSERT INTO t1(x, y) VALUES +(1, 1000), +(2, 2000), +(3, 3000), +(4, 4000), +(5, 5000), +(6, 6000), +(7, 7000), +(8, 8000), +(9, 9000); +INSERT INTO t1(x, y) VALUES(3, 3000) ON DUPLICATE KEY UPDATE y = y+1; +INSERT INTO t1(x, y) VALUES(4, 4000) ON DUPLICATE KEY UPDATE y = y+1; +INSERT INTO t1(x, y) VALUES(4, 4001) ON DUPLICATE KEY UPDATE y = y+1; +INSERT INTO t1(x, y) VALUES(4, 4444) ON DUPLICATE KEY UPDATE y = y+1; +SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; +x y +1 1000 +2 2000 +3 3001 +4 4002 +5 5000 +6 6000 +7 7000 +8 8000 +9 9000 +3 3000 +4 4000 +4 4001 +4 4444 +SELECT x, y FROM t1; +x y +1 1000 +2 2000 +3 3001 +4 4002 +5 5000 +6 6000 +7 7000 +8 8000 +9 9000 +4 4444 +DROP TABLE t1; +CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end), PRIMARY KEY(x, y)) WITH SYSTEM VERSIONING ENGINE=InnoDB; +INSERT INTO t1(x, y) VALUES +(1, 1000), +(2, 2000), +(3, 3000), +(4, 4000), +(5, 5000), +(6, 6000), +(7, 7000), +(8, 8000), +(9, 9000); +INSERT INTO t1(x, y) VALUES(3, 3000) ON DUPLICATE KEY UPDATE y = y+1; +INSERT INTO t1(x, y) VALUES(4, 4000) ON DUPLICATE KEY UPDATE y = y+1; +INSERT INTO t1(x, y) VALUES(4, 4001) ON DUPLICATE KEY UPDATE y = y+1; +INSERT INTO t1(x, y) VALUES(4, 4444) ON DUPLICATE KEY UPDATE y = y+1; +SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; +x y +1 1000 +2 2000 +3 3000 +3 3001 +4 4000 +4 4001 +4 4002 +4 4444 +5 5000 +6 6000 +7 7000 +8 8000 +9 9000 +SELECT x, y FROM t1; +x y +1 1000 +2 2000 +3 3001 +4 4002 +4 4444 +5 5000 +6 6000 +7 7000 +8 8000 +9 9000 +DROP TABLE t1; diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result index 634b3897ba0..35966f5ac1b 100644 --- a/mysql-test/r/multi_update.result +++ b/mysql-test/r/multi_update.result @@ -1002,3 +1002,215 @@ deallocate prepare stmt1; drop view v3,v2,v1; drop table t1,t2,t3; end of 5.5 tests + +# Bug mdev-5970 +# Bug#13256831 - ERROR 1032 (HY000): CAN'T FIND RECORD + +CREATE TABLE t1 (f1 INT PRIMARY KEY, f2 INT) ENGINE=InnoDB; +CREATE TABLE t2 (f1 INT PRIMARY KEY, f2 INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (5, 7); +INSERT INTO t2 VALUES (6, 97); +CREATE ALGORITHM = MERGE VIEW v1 AS +SELECT a2.f1 AS f1, a2.f2 AS f2 +FROM t1 AS a1 JOIN t2 AS a2 ON a1.f2 > a2.f1 +WITH LOCAL CHECK OPTION; +SELECT * FROM v1; +f1 f2 +6 97 +UPDATE v1 SET f1 = 1; +SELECT * FROM v1; +f1 f2 +1 97 +DROP TABLE t1, t2; +DROP VIEW v1; +# +# MDEV-5973: MySQL Bug#11757486:49539: NON-DESCRIPTIVE ERR (ERROR 0 +# FROM STORAGE ENGINE) WITH MULTI-TABLE UPDATE +# +CREATE TABLE table_11757486 (field1 tinyint) ENGINE=INNODB; +INSERT INTO table_11757486 VALUES (0),(0); +SET SESSION SQL_MODE='STRICT_ALL_TABLES'; +UPDATE IGNORE (SELECT 128 as col1) x, table_11757486 SET field1=x.col1; +Warnings: +Warning 1264 Out of range value for column 'field1' at row 1 +Warning 1264 Out of range value for column 'field1' at row 2 +UPDATE IGNORE table_11757486 SET field1=128; +Warnings: +Warning 1264 Out of range value for column 'field1' at row 1 +Warning 1264 Out of range value for column 'field1' at row 2 +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. UPDATE IGNORE is unsafe because the order in which rows are updated determines which (if any) rows are ignored. This order cannot be predicted and may differ on master and the slave. +UPDATE (SELECT 128 as col1) x, table_11757486 SET field1=x.col1; +ERROR 22003: Out of range value for column 'field1' at row 1 +UPDATE table_11757486 SET field1=128; +ERROR 22003: Out of range value for column 'field1' at row 1 +SET SESSION SQL_MODE=''; +UPDATE IGNORE (SELECT 128 as col1) x, table_11757486 SET field1=x.col1; +Warnings: +Warning 1264 Out of range value for column 'field1' at row 1 +Warning 1264 Out of range value for column 'field1' at row 2 +UPDATE IGNORE table_11757486 SET field1=128; +Warnings: +Warning 1264 Out of range value for column 'field1' at row 1 +Warning 1264 Out of range value for column 'field1' at row 2 +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. UPDATE IGNORE is unsafe because the order in which rows are updated determines which (if any) rows are ignored. This order cannot be predicted and may differ on master and the slave. +DROP TABLE table_11757486; +SET SESSION SQL_MODE=default; +end of 10.0 tests +# +# System Versioning Support +# +# +CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; +CREATE TABLE t2(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; +INSERT INTO t1(x, y) VALUES +(1, 1000), +(2, 2000), +(3, 3000), +(4, 4000), +(5, 5000), +(6, 6000), +(7, 7000), +(8, 8000), +(9, 9000); +INSERT INTO t2(x, y) VALUES +(1, 1010), +(2, 2010), +(3, 3010), +(4, 4010), +(5, 5010), +(6, 6010), +(7, 7010), +(8, 8010), +(9, 9010); +UPDATE t1, t2 SET t1.y = t1.x + t1.y, t2.y = t2.x + t2.y WHERE t1.x > 7 AND t2.x < 7; +SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; +x y +1 1000 +2 2000 +3 3000 +4 4000 +5 5000 +6 6000 +7 7000 +8 8008 +9 9009 +8 8000 +9 9000 +SELECT x, y FROM t1; +x y +1 1000 +2 2000 +3 3000 +4 4000 +5 5000 +6 6000 +7 7000 +8 8008 +9 9009 +SELECT x, y FROM t2 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; +x y +1 1011 +2 2012 +3 3013 +4 4014 +5 5015 +6 6016 +7 7010 +8 8010 +9 9010 +1 1010 +2 2010 +3 3010 +4 4010 +5 5010 +6 6010 +SELECT x, y FROM t2; +x y +1 1011 +2 2012 +3 3013 +4 4014 +5 5015 +6 6016 +7 7010 +8 8010 +9 9010 +DROP TABLE t1; +DROP TABLE t2; +CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; +CREATE TABLE t2(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; +INSERT INTO t1(x, y) VALUES +(1, 1000), +(2, 2000), +(3, 3000), +(4, 4000), +(5, 5000), +(6, 6000), +(7, 7000), +(8, 8000), +(9, 9000); +INSERT INTO t2(x, y) VALUES +(1, 1010), +(2, 2010), +(3, 3010), +(4, 4010), +(5, 5010), +(6, 6010), +(7, 7010), +(8, 8010), +(9, 9010); +UPDATE t1, t2 SET t1.y = t1.x + t1.y, t2.y = t2.x + t2.y WHERE t1.x > 7 AND t2.x < 7; +SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; +x y +1 1000 +2 2000 +3 3000 +4 4000 +5 5000 +6 6000 +7 7000 +8 8008 +9 9009 +8 8000 +9 9000 +SELECT x, y FROM t1; +x y +1 1000 +2 2000 +3 3000 +4 4000 +5 5000 +6 6000 +7 7000 +8 8008 +9 9009 +SELECT x, y FROM t2 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; +x y +1 1011 +2 2012 +3 3013 +4 4014 +5 5015 +6 6016 +7 7010 +8 8010 +9 9010 +1 1010 +2 2010 +3 3010 +4 4010 +5 5010 +6 6010 +SELECT x, y FROM t2; +x y +1 1011 +2 2012 +3 3013 +4 4014 +5 5015 +6 6016 +7 7010 +8 8010 +9 9010 +DROP TABLE t1; +DROP TABLE t2; diff --git a/mysql-test/r/named_pipe.result b/mysql-test/r/named_pipe.result index 66da9a874b4..b6c409e4590 100644 --- a/mysql-test/r/named_pipe.result +++ b/mysql-test/r/named_pipe.result @@ -1,18 +1,18 @@ connect pipe_con,localhost,root,,,,,PIPE; drop table if exists t1,t2,t3,t4; CREATE TABLE t1 ( -Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, +Period_ smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL ); INSERT INTO t1 VALUES (9410,9412); -select period from t1; -period +select period_ from t1; +period_ 9410 select * from t1; -Period Varor_period +Period_ Varor_period 9410 9412 select t1.* from t1; -Period Varor_period +Period_ Varor_period 9410 9412 CREATE TABLE t2 ( auto int not null auto_increment, @@ -276,8 +276,8 @@ companynr 34 29 00 -select distinct t2.fld3,period from t2,t1 where companynr=37 and fld3 like "O%"; -fld3 period +select distinct t2.fld3,period_ from t2,t1 where companynr=37 and fld3 like "O%"; +fld3 period_ obliterates 9410 offload 9410 opaquely 9410 @@ -481,12 +481,12 @@ acu Ade adj create table t3 ( -period int not null, +period_ int not null, name char(32) not null, companynr int not null, price double(11,0), price2 double(11,0), -key (period), +key (period_), key (name) ); create temporary table tmp engine = myisam select * from t3; @@ -600,35 +600,35 @@ explain select t3.t2nr,fld3 from t2,t3 where t2.companynr = 34 and t2.fld1=t3.t2 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL fld1 NULL NULL NULL 1199 Using where; Using temporary; Using filesort 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.fld1 1 Using where; Using index -explain select * from t3 as t1,t3 where t1.period=t3.period order by t3.period; +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t3.period_; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL period NULL NULL NULL 41810 Using filesort -1 SIMPLE t3 ref period period 4 test.t1.period 4181 -explain select * from t3 as t1,t3 where t1.period=t3.period order by t3.period limit 10; +1 SIMPLE t1 ALL period_ NULL NULL NULL 41810 Using temporary; Using filesort +1 SIMPLE t3 ref period_ period_ 4 test.t1.period_ 4181 +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t3.period_ limit 10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t3 index period period 4 NULL 1 -1 SIMPLE t1 ref period period 4 test.t3.period 4181 -explain select * from t3 as t1,t3 where t1.period=t3.period order by t1.period limit 10; +1 SIMPLE t3 index period_ period_ 4 NULL 1 +1 SIMPLE t1 ref period_ period_ 4 test.t3.period_ 4181 +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t1.period_ limit 10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index period period 4 NULL 1 -1 SIMPLE t3 ref period period 4 test.t1.period 4181 -select period from t1; -period +1 SIMPLE t1 index period_ period_ 4 NULL 1 +1 SIMPLE t3 ref period_ period_ 4 test.t1.period_ 4181 +select period_ from t1; +period_ 9410 -select period from t1 where period=1900; -period -select fld3,period from t1,t2 where fld1 = 011401 order by period; -fld3 period +select period_ from t1 where period_=1900; +period_ +select fld3,period_ from t1,t2 where fld1 = 011401 order by period_; +fld3 period_ breaking 9410 -select fld3,period from t2,t3 where t2.fld1 = 011401 and t2.fld1=t3.t2nr and t3.period=1001; -fld3 period +select fld3,period_ from t2,t3 where t2.fld1 = 011401 and t2.fld1=t3.t2nr and t3.period_=1001; +fld3 period_ breaking 1001 -explain select fld3,period from t2,t3 where t2.fld1 = 011401 and t3.t2nr=t2.fld1 and 1001 = t3.period; +explain select fld3,period_ from t2,t3 where t2.fld1 = 011401 and t3.t2nr=t2.fld1 and 1001 = t3.period_; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 const fld1 fld1 4 const 1 -1 SIMPLE t3 const PRIMARY,period PRIMARY 4 const 1 -select fld3,period from t2,t1 where companynr*10 = 37*10; -fld3 period +1 SIMPLE t3 const PRIMARY,period_ PRIMARY 4 const 1 +select fld3,period_ from t2,t1 where companynr*10 = 37*10; +fld3 period_ breaking 9410 Romans 9410 intercepted 9410 @@ -1217,8 +1217,8 @@ dusted 9410 encompasses 9410 presentation 9410 Kantian 9410 -select fld3,period,price,price2 from t2,t3 where t2.fld1=t3.t2nr and period >= 1001 and period <= 1002 and t2.companynr = 37 order by fld3,period, price; -fld3 period price price2 +select fld3,period_,price,price2 from t2,t3 where t2.fld1=t3.t2nr and period_ >= 1001 and period_ <= 1002 and t2.companynr = 37 order by fld3,period_, price; +fld3 period_ price price2 admonishing 1002 28357832 8723648 analyzable 1002 28357832 8723648 annihilates 1001 5987435 234724 @@ -1278,8 +1278,8 @@ ventilate 1001 5987435 234724 wallet 1001 5987435 234724 Weissmuller 1002 28357832 8723648 Wotan 1002 28357832 8723648 -select t2.fld1,fld3,period,price,price2 from t2,t3 where t2.fld1>= 18201 and t2.fld1 <= 18811 and t2.fld1=t3.t2nr and period = 1001 and t2.companynr = 37; -fld1 fld3 period price price2 +select t2.fld1,fld3,period_,price,price2 from t2,t3 where t2.fld1>= 18201 and t2.fld1 <= 18811 and t2.fld1=t3.t2nr and period_ = 1001 and t2.companynr = 37; +fld1 fld3 period_ price price2 018201 relaxing 1001 5987435 234724 018601 vacuuming 1001 5987435 234724 018801 inch 1001 5987435 234724 @@ -1319,7 +1319,7 @@ companynr companyname 65 company 9 68 company 10 select * from t1,t1 t12; -Period Varor_period Period Varor_period +Period_ Varor_period Period_ Varor_period 9410 9412 9410 9412 select t2.fld1,t22.fld1 from t2,t2 t22 where t2.fld1 >= 250501 and t2.fld1 <= 250505 and t22.fld1 >= 250501 and t22.fld1 <= 250505; fld1 fld1 @@ -1434,23 +1434,23 @@ explain select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr= id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t4 index NULL PRIMARY 1 NULL 12 Using index; Using temporary 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where; Using join buffer (flat, BNL join) -select t2.fld1,t2.companynr,fld3,period from t3,t2 where t2.fld1 = 38208 and t2.fld1=t3.t2nr and period = 1008 or t2.fld1 = 38008 and t2.fld1 =t3.t2nr and period = 1008; -fld1 companynr fld3 period +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where t2.fld1 = 38208 and t2.fld1=t3.t2nr and period_ = 1008 or t2.fld1 = 38008 and t2.fld1 =t3.t2nr and period_ = 1008; +fld1 companynr fld3 period_ 038008 37 reporters 1008 038208 37 Selfridge 1008 -select t2.fld1,t2.companynr,fld3,period from t3,t2 where (t2.fld1 = 38208 or t2.fld1 = 38008) and t2.fld1=t3.t2nr and period>=1008 and period<=1009; -fld1 companynr fld3 period +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where (t2.fld1 = 38208 or t2.fld1 = 38008) and t2.fld1=t3.t2nr and period_>=1008 and period_<=1009; +fld1 companynr fld3 period_ 038008 37 reporters 1008 038208 37 Selfridge 1008 -select t2.fld1,t2.companynr,fld3,period from t3,t2 where (t3.t2nr = 38208 or t3.t2nr = 38008) and t2.fld1=t3.t2nr and period>=1008 and period<=1009; -fld1 companynr fld3 period +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where (t3.t2nr = 38208 or t3.t2nr = 38008) and t2.fld1=t3.t2nr and period_>=1008 and period_<=1009; +fld1 companynr fld3 period_ 038008 37 reporters 1008 038208 37 Selfridge 1008 -select period from t1 where (((period > 0) or period < 10000 or (period = 1900)) and (period=1900 and period <= 1901) or (period=1903 and (period=1903)) and period>=1902) or ((period=1904 or period=1905) or (period=1906 or period>1907)) or (period=1908 and period = 1909); -period +select period_ from t1 where (((period_ > 0) or period_ < 10000 or (period_ = 1900)) and (period_=1900 and period_ <= 1901) or (period_=1903 and (period_=1903)) and period_>=1902) or ((period_=1904 or period_=1905) or (period_=1906 or period_>1907)) or (period_=1908 and period_ = 1909); +period_ 9410 -select period from t1 where ((period > 0 and period < 1) or (((period > 0 and period < 100) and (period > 10)) or (period > 10)) or (period > 0 and (period > 5 or period > 6))); -period +select period_ from t1 where ((period_ > 0 and period_ < 1) or (((period_ > 0 and period_ < 100) and (period_ > 10)) or (period_ > 10)) or (period_ > 0 and (period_ > 5 or period_ > 6))); +period_ 9410 select a.fld1 from t2 as a,t2 b where ((a.fld1 = 250501 and a.fld1=b.fld1) or a.fld1=250502 or a.fld1=250503 or (a.fld1=250505 and a.fld1<=b.fld1 and b.fld1>=a.fld1)) and a.fld1=b.fld1; fld1 @@ -1707,8 +1707,8 @@ companynr companyname count(*) select t2.fld1,count(*) from t2,t3 where t2.fld1=158402 and t3.name=t2.fld3 group by t3.name; fld1 count(*) 158402 4181 -select sum(Period)/count(*) from t1; -sum(Period)/count(*) +select sum(Period_)/count(*) from t1; +sum(Period_)/count(*) 9410.0000 select companynr,count(price) as "count",sum(price) as "sum" ,abs(sum(price)/count(price)-avg(price)) as "diff",(0+count(price))*companynr as func from t3 group by companynr; companynr count sum diff func @@ -2038,26 +2038,26 @@ t2nr count(*) select max(t2nr) from t3 where price=983543950; max(t2nr) 41807 -select t1.period from t3 = t1 limit 1; -period +select t1.period_ from t3 = t1 limit 1; +period_ 1001 -select t1.period from t1 as t1 limit 1; -period +select t1.period_ from t1 as t1 limit 1; +period_ 9410 -select t1.period as "Nuvarande period" from t1 as t1 limit 1; -Nuvarande period +select t1.period_ as "Nuvarande period_" from t1 as t1 limit 1; +Nuvarande period_ 9410 -select period as ok_period from t1 limit 1; +select period_ as ok_period from t1 limit 1; ok_period 9410 -select period as ok_period from t1 group by ok_period limit 1; +select period_ as ok_period from t1 group by ok_period limit 1; ok_period 9410 select 1+1 as summa from t1 group by summa limit 1; summa 2 -select period as "Nuvarande period" from t1 group by "Nuvarande period" limit 1; -Nuvarande period +select period_ as "Nuvarande period_" from t1 group by "Nuvarande period_" limit 1; +Nuvarande period_ 9410 show tables; Tables_in_test diff --git a/mysql-test/r/pool_of_threads.result b/mysql-test/r/pool_of_threads.result index b25d8d1e50e..85ab577829a 100644 --- a/mysql-test/r/pool_of_threads.result +++ b/mysql-test/r/pool_of_threads.result @@ -2,18 +2,18 @@ SET @save_optimizer_switch=@@optimizer_switch; SET optimizer_switch='outer_join_with_cache=off'; drop table if exists t1,t2,t3,t4; CREATE TABLE t1 ( -Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, +Period_ smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL ); INSERT INTO t1 VALUES (9410,9412); -select period from t1; -period +select period_ from t1; +period_ 9410 select * from t1; -Period Varor_period +Period_ Varor_period 9410 9412 select t1.* from t1; -Period Varor_period +Period_ Varor_period 9410 9412 CREATE TABLE t2 ( auto int not null auto_increment, @@ -277,8 +277,8 @@ companynr 34 29 00 -select distinct t2.fld3,period from t2,t1 where companynr=37 and fld3 like "O%"; -fld3 period +select distinct t2.fld3,period_ from t2,t1 where companynr=37 and fld3 like "O%"; +fld3 period_ obliterates 9410 offload 9410 opaquely 9410 @@ -482,12 +482,12 @@ acu Ade adj create table t3 ( -period int not null, +period_ int not null, name char(32) not null, companynr int not null, price double(11,0), price2 double(11,0), -key (period), +key (period_), key (name) ); create temporary table tmp engine = myisam select * from t3; @@ -601,35 +601,35 @@ explain select t3.t2nr,fld3 from t2,t3 where t2.companynr = 34 and t2.fld1=t3.t2 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL fld1 NULL NULL NULL 1199 Using where; Using temporary; Using filesort 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.fld1 1 Using where; Using index -explain select * from t3 as t1,t3 where t1.period=t3.period order by t3.period; +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t3.period_; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL period NULL NULL NULL 41810 Using filesort -1 SIMPLE t3 ref period period 4 test.t1.period 4181 -explain select * from t3 as t1,t3 where t1.period=t3.period order by t3.period limit 10; +1 SIMPLE t1 ALL period_ NULL NULL NULL 41810 Using filesort +1 SIMPLE t3 ref period_ period_ 4 test.t1.period_ 4181 +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t3.period_ limit 10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t3 index period period 4 NULL 1 -1 SIMPLE t1 ref period period 4 test.t3.period 4181 -explain select * from t3 as t1,t3 where t1.period=t3.period order by t1.period limit 10; +1 SIMPLE t3 index period_ period_ 4 NULL 1 +1 SIMPLE t1 ref period_ period_ 4 test.t3.period_ 4181 +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t1.period_ limit 10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index period period 4 NULL 1 -1 SIMPLE t3 ref period period 4 test.t1.period 4181 -select period from t1; -period +1 SIMPLE t1 index period_ period_ 4 NULL 1 +1 SIMPLE t3 ref period_ period_ 4 test.t1.period_ 4181 +select period_ from t1; +period_ 9410 -select period from t1 where period=1900; -period -select fld3,period from t1,t2 where fld1 = 011401 order by period; -fld3 period +select period_ from t1 where period_=1900; +period_ +select fld3,period_ from t1,t2 where fld1 = 011401 order by period_; +fld3 period_ breaking 9410 -select fld3,period from t2,t3 where t2.fld1 = 011401 and t2.fld1=t3.t2nr and t3.period=1001; -fld3 period +select fld3,period_ from t2,t3 where t2.fld1 = 011401 and t2.fld1=t3.t2nr and t3.period_=1001; +fld3 period_ breaking 1001 -explain select fld3,period from t2,t3 where t2.fld1 = 011401 and t3.t2nr=t2.fld1 and 1001 = t3.period; +explain select fld3,period_ from t2,t3 where t2.fld1 = 011401 and t3.t2nr=t2.fld1 and 1001 = t3.period_; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 const fld1 fld1 4 const 1 -1 SIMPLE t3 const PRIMARY,period PRIMARY 4 const 1 -select fld3,period from t2,t1 where companynr*10 = 37*10; -fld3 period +1 SIMPLE t3 const PRIMARY,period_ PRIMARY 4 const 1 +select fld3,period_ from t2,t1 where companynr*10 = 37*10; +fld3 period_ breaking 9410 Romans 9410 intercepted 9410 @@ -1218,8 +1218,8 @@ dusted 9410 encompasses 9410 presentation 9410 Kantian 9410 -select fld3,period,price,price2 from t2,t3 where t2.fld1=t3.t2nr and period >= 1001 and period <= 1002 and t2.companynr = 37 order by fld3,period, price; -fld3 period price price2 +select fld3,period_,price,price2 from t2,t3 where t2.fld1=t3.t2nr and period_ >= 1001 and period_ <= 1002 and t2.companynr = 37 order by fld3,period_, price; +fld3 period_ price price2 admonishing 1002 28357832 8723648 analyzable 1002 28357832 8723648 annihilates 1001 5987435 234724 @@ -1279,8 +1279,8 @@ ventilate 1001 5987435 234724 wallet 1001 5987435 234724 Weissmuller 1002 28357832 8723648 Wotan 1002 28357832 8723648 -select t2.fld1,fld3,period,price,price2 from t2,t3 where t2.fld1>= 18201 and t2.fld1 <= 18811 and t2.fld1=t3.t2nr and period = 1001 and t2.companynr = 37; -fld1 fld3 period price price2 +select t2.fld1,fld3,period_,price,price2 from t2,t3 where t2.fld1>= 18201 and t2.fld1 <= 18811 and t2.fld1=t3.t2nr and period_ = 1001 and t2.companynr = 37; +fld1 fld3 period_ price price2 018201 relaxing 1001 5987435 234724 018601 vacuuming 1001 5987435 234724 018801 inch 1001 5987435 234724 @@ -1320,7 +1320,7 @@ companynr companyname 65 company 9 68 company 10 select * from t1,t1 t12; -Period Varor_period Period Varor_period +Period_ Varor_period Period_ Varor_period 9410 9412 9410 9412 select t2.fld1,t22.fld1 from t2,t2 t22 where t2.fld1 >= 250501 and t2.fld1 <= 250505 and t22.fld1 >= 250501 and t22.fld1 <= 250505; fld1 fld1 @@ -1435,23 +1435,23 @@ explain select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr= id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t4 index NULL PRIMARY 1 NULL 12 Using index; Using temporary 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where; Using join buffer (flat, BNL join) -select t2.fld1,t2.companynr,fld3,period from t3,t2 where t2.fld1 = 38208 and t2.fld1=t3.t2nr and period = 1008 or t2.fld1 = 38008 and t2.fld1 =t3.t2nr and period = 1008; -fld1 companynr fld3 period +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where t2.fld1 = 38208 and t2.fld1=t3.t2nr and period_ = 1008 or t2.fld1 = 38008 and t2.fld1 =t3.t2nr and period_ = 1008; +fld1 companynr fld3 period_ 038008 37 reporters 1008 038208 37 Selfridge 1008 -select t2.fld1,t2.companynr,fld3,period from t3,t2 where (t2.fld1 = 38208 or t2.fld1 = 38008) and t2.fld1=t3.t2nr and period>=1008 and period<=1009; -fld1 companynr fld3 period +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where (t2.fld1 = 38208 or t2.fld1 = 38008) and t2.fld1=t3.t2nr and period_>=1008 and period_<=1009; +fld1 companynr fld3 period_ 038008 37 reporters 1008 038208 37 Selfridge 1008 -select t2.fld1,t2.companynr,fld3,period from t3,t2 where (t3.t2nr = 38208 or t3.t2nr = 38008) and t2.fld1=t3.t2nr and period>=1008 and period<=1009; -fld1 companynr fld3 period +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where (t3.t2nr = 38208 or t3.t2nr = 38008) and t2.fld1=t3.t2nr and period_>=1008 and period_<=1009; +fld1 companynr fld3 period_ 038008 37 reporters 1008 038208 37 Selfridge 1008 -select period from t1 where (((period > 0) or period < 10000 or (period = 1900)) and (period=1900 and period <= 1901) or (period=1903 and (period=1903)) and period>=1902) or ((period=1904 or period=1905) or (period=1906 or period>1907)) or (period=1908 and period = 1909); -period +select period_ from t1 where (((period_ > 0) or period_ < 10000 or (period_ = 1900)) and (period_=1900 and period_ <= 1901) or (period_=1903 and (period_=1903)) and period_>=1902) or ((period_=1904 or period_=1905) or (period_=1906 or period_>1907)) or (period_=1908 and period_ = 1909); +period_ 9410 -select period from t1 where ((period > 0 and period < 1) or (((period > 0 and period < 100) and (period > 10)) or (period > 10)) or (period > 0 and (period > 5 or period > 6))); -period +select period_ from t1 where ((period_ > 0 and period_ < 1) or (((period_ > 0 and period_ < 100) and (period_ > 10)) or (period_ > 10)) or (period_ > 0 and (period_ > 5 or period_ > 6))); +period_ 9410 select a.fld1 from t2 as a,t2 b where ((a.fld1 = 250501 and a.fld1=b.fld1) or a.fld1=250502 or a.fld1=250503 or (a.fld1=250505 and a.fld1<=b.fld1 and b.fld1>=a.fld1)) and a.fld1=b.fld1; fld1 @@ -1708,8 +1708,8 @@ companynr companyname count(*) select t2.fld1,count(*) from t2,t3 where t2.fld1=158402 and t3.name=t2.fld3 group by t3.name; fld1 count(*) 158402 4181 -select sum(Period)/count(*) from t1; -sum(Period)/count(*) +select sum(Period_)/count(*) from t1; +sum(Period_)/count(*) 9410.0000 select companynr,count(price) as "count",sum(price) as "sum" ,abs(sum(price)/count(price)-avg(price)) as "diff",(0+count(price))*companynr as func from t3 group by companynr; companynr count sum diff func @@ -2039,26 +2039,26 @@ t2nr count(*) select max(t2nr) from t3 where price=983543950; max(t2nr) 41807 -select t1.period from t3 = t1 limit 1; -period +select t1.period_ from t3 = t1 limit 1; +period_ 1001 -select t1.period from t1 as t1 limit 1; -period +select t1.period_ from t1 as t1 limit 1; +period_ 9410 -select t1.period as "Nuvarande period" from t1 as t1 limit 1; -Nuvarande period +select t1.period_ as "Nuvarande period_" from t1 as t1 limit 1; +Nuvarande period_ 9410 -select period as ok_period from t1 limit 1; +select period_ as ok_period from t1 limit 1; ok_period 9410 -select period as ok_period from t1 group by ok_period limit 1; +select period_ as ok_period from t1 group by ok_period limit 1; ok_period 9410 select 1+1 as summa from t1 group by summa limit 1; summa 2 -select period as "Nuvarande period" from t1 group by "Nuvarande period" limit 1; -Nuvarande period +select period_ as "Nuvarande period_" from t1 group by "Nuvarande period_" limit 1; +Nuvarande period_ 9410 show tables; Tables_in_test diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 5859bd0fae6..c260e2ff333 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -5,18 +5,18 @@ SET @save_optimizer_switch=@@optimizer_switch; SET optimizer_switch=ifnull(@optimizer_switch_for_select_test,'outer_join_with_cache=off'); set join_cache_level=1; CREATE TABLE t1 ( -Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, +Period_ smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL ); INSERT INTO t1 VALUES (9410,9412); -select period from t1; -period +select period_ from t1; +period_ 9410 select * from t1; -Period Varor_period +Period_ Varor_period 9410 9412 select t1.* from t1; -Period Varor_period +Period_ Varor_period 9410 9412 CREATE TABLE t2 ( auto int not null auto_increment, @@ -280,8 +280,8 @@ companynr 34 29 00 -select distinct t2.fld3,period from t2,t1 where companynr=37 and fld3 like "O%"; -fld3 period +select distinct t2.fld3,period_ from t2,t1 where companynr=37 and fld3 like "O%"; +fld3 period_ obliterates 9410 offload 9410 opaquely 9410 @@ -485,12 +485,12 @@ acu Ade adj create table t3 ( -period int not null, +period_ int not null, name char(32) not null, companynr int not null, price double(11,0), price2 double(11,0), -key (period), +key (period_), key (name) ); create temporary table tmp engine = myisam select * from t3; @@ -604,35 +604,35 @@ explain select t3.t2nr,fld3 from t2,t3 where t2.companynr = 34 and t2.fld1=t3.t2 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL fld1 NULL NULL NULL 1199 Using where; Using temporary; Using filesort 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.fld1 1 Using where; Using index -explain select * from t3 as t1,t3 where t1.period=t3.period order by t3.period; +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t3.period_; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL period NULL NULL NULL 41810 Using filesort -1 SIMPLE t3 ref period period 4 test.t1.period 4181 -explain select * from t3 as t1,t3 where t1.period=t3.period order by t3.period limit 10; +1 SIMPLE t1 ALL period_ NULL NULL NULL 41810 Using filesort +1 SIMPLE t3 ref period_ period_ 4 test.t1.period_ 4181 +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t3.period_ limit 10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t3 index period period 4 NULL 1 -1 SIMPLE t1 ref period period 4 test.t3.period 4181 -explain select * from t3 as t1,t3 where t1.period=t3.period order by t1.period limit 10; +1 SIMPLE t3 index period_ period_ 4 NULL 1 +1 SIMPLE t1 ref period_ period_ 4 test.t3.period_ 4181 +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t1.period_ limit 10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index period period 4 NULL 1 -1 SIMPLE t3 ref period period 4 test.t1.period 4181 -select period from t1; -period +1 SIMPLE t1 index period_ period_ 4 NULL 1 +1 SIMPLE t3 ref period_ period_ 4 test.t1.period_ 4181 +select period_ from t1; +period_ 9410 -select period from t1 where period=1900; -period -select fld3,period from t1,t2 where fld1 = 011401 order by period; -fld3 period +select period_ from t1 where period_=1900; +period_ +select fld3,period_ from t1,t2 where fld1 = 011401 order by period_; +fld3 period_ breaking 9410 -select fld3,period from t2,t3 where t2.fld1 = 011401 and t2.fld1=t3.t2nr and t3.period=1001; -fld3 period +select fld3,period_ from t2,t3 where t2.fld1 = 011401 and t2.fld1=t3.t2nr and t3.period_=1001; +fld3 period_ breaking 1001 -explain select fld3,period from t2,t3 where t2.fld1 = 011401 and t3.t2nr=t2.fld1 and 1001 = t3.period; +explain select fld3,period_ from t2,t3 where t2.fld1 = 011401 and t3.t2nr=t2.fld1 and 1001 = t3.period_; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 const fld1 fld1 4 const 1 -1 SIMPLE t3 const PRIMARY,period PRIMARY 4 const 1 -select fld3,period from t2,t1 where companynr*10 = 37*10; -fld3 period +1 SIMPLE t3 const PRIMARY,period_ PRIMARY 4 const 1 +select fld3,period_ from t2,t1 where companynr*10 = 37*10; +fld3 period_ breaking 9410 Romans 9410 intercepted 9410 @@ -1221,8 +1221,8 @@ dusted 9410 encompasses 9410 presentation 9410 Kantian 9410 -select fld3,period,price,price2 from t2,t3 where t2.fld1=t3.t2nr and period >= 1001 and period <= 1002 and t2.companynr = 37 order by fld3,period, price; -fld3 period price price2 +select fld3,period_,price,price2 from t2,t3 where t2.fld1=t3.t2nr and period_ >= 1001 and period_ <= 1002 and t2.companynr = 37 order by fld3,period_, price; +fld3 period_ price price2 admonishing 1002 28357832 8723648 analyzable 1002 28357832 8723648 annihilates 1001 5987435 234724 @@ -1282,8 +1282,8 @@ ventilate 1001 5987435 234724 wallet 1001 5987435 234724 Weissmuller 1002 28357832 8723648 Wotan 1002 28357832 8723648 -select t2.fld1,fld3,period,price,price2 from t2,t3 where t2.fld1>= 18201 and t2.fld1 <= 18811 and t2.fld1=t3.t2nr and period = 1001 and t2.companynr = 37; -fld1 fld3 period price price2 +select t2.fld1,fld3,period_,price,price2 from t2,t3 where t2.fld1>= 18201 and t2.fld1 <= 18811 and t2.fld1=t3.t2nr and period_ = 1001 and t2.companynr = 37; +fld1 fld3 period_ price price2 018201 relaxing 1001 5987435 234724 018601 vacuuming 1001 5987435 234724 018801 inch 1001 5987435 234724 @@ -1323,7 +1323,7 @@ companynr companyname 65 company 9 68 company 10 select * from t1,t1 t12; -Period Varor_period Period Varor_period +Period_ Varor_period Period_ Varor_period 9410 9412 9410 9412 select t2.fld1,t22.fld1 from t2,t2 t22 where t2.fld1 >= 250501 and t2.fld1 <= 250505 and t22.fld1 >= 250501 and t22.fld1 <= 250505; fld1 fld1 @@ -1435,23 +1435,23 @@ explain select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr= id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t4 index NULL PRIMARY 1 NULL 12 Using index; Using temporary 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where; Using join buffer (flat, BNL join) -select t2.fld1,t2.companynr,fld3,period from t3,t2 where t2.fld1 = 38208 and t2.fld1=t3.t2nr and period = 1008 or t2.fld1 = 38008 and t2.fld1 =t3.t2nr and period = 1008; -fld1 companynr fld3 period +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where t2.fld1 = 38208 and t2.fld1=t3.t2nr and period_ = 1008 or t2.fld1 = 38008 and t2.fld1 =t3.t2nr and period_ = 1008; +fld1 companynr fld3 period_ 038008 37 reporters 1008 038208 37 Selfridge 1008 -select t2.fld1,t2.companynr,fld3,period from t3,t2 where (t2.fld1 = 38208 or t2.fld1 = 38008) and t2.fld1=t3.t2nr and period>=1008 and period<=1009; -fld1 companynr fld3 period +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where (t2.fld1 = 38208 or t2.fld1 = 38008) and t2.fld1=t3.t2nr and period_>=1008 and period_<=1009; +fld1 companynr fld3 period_ 038008 37 reporters 1008 038208 37 Selfridge 1008 -select t2.fld1,t2.companynr,fld3,period from t3,t2 where (t3.t2nr = 38208 or t3.t2nr = 38008) and t2.fld1=t3.t2nr and period>=1008 and period<=1009; -fld1 companynr fld3 period +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where (t3.t2nr = 38208 or t3.t2nr = 38008) and t2.fld1=t3.t2nr and period_>=1008 and period_<=1009; +fld1 companynr fld3 period_ 038008 37 reporters 1008 038208 37 Selfridge 1008 -select period from t1 where (((period > 0) or period < 10000 or (period = 1900)) and (period=1900 and period <= 1901) or (period=1903 and (period=1903)) and period>=1902) or ((period=1904 or period=1905) or (period=1906 or period>1907)) or (period=1908 and period = 1909); -period +select period_ from t1 where (((period_ > 0) or period_ < 10000 or (period_ = 1900)) and (period_=1900 and period_ <= 1901) or (period_=1903 and (period_=1903)) and period_>=1902) or ((period_=1904 or period_=1905) or (period_=1906 or period_>1907)) or (period_=1908 and period_ = 1909); +period_ 9410 -select period from t1 where ((period > 0 and period < 1) or (((period > 0 and period < 100) and (period > 10)) or (period > 10)) or (period > 0 and (period > 5 or period > 6))); -period +select period_ from t1 where ((period_ > 0 and period_ < 1) or (((period_ > 0 and period_ < 100) and (period_ > 10)) or (period_ > 10)) or (period_ > 0 and (period_ > 5 or period_ > 6))); +period_ 9410 select a.fld1 from t2 as a,t2 b where ((a.fld1 = 250501 and a.fld1=b.fld1) or a.fld1=250502 or a.fld1=250503 or (a.fld1=250505 and a.fld1<=b.fld1 and b.fld1>=a.fld1)) and a.fld1=b.fld1; fld1 @@ -1708,8 +1708,8 @@ companynr companyname count(*) select t2.fld1,count(*) from t2,t3 where t2.fld1=158402 and t3.name=t2.fld3 group by t3.name; fld1 count(*) 158402 4181 -select sum(Period)/count(*) from t1; -sum(Period)/count(*) +select sum(Period_)/count(*) from t1; +sum(Period_)/count(*) 9410.0000 select companynr,count(price) as "count",sum(price) as "sum" ,abs(sum(price)/count(price)-avg(price)) as "diff",(0+count(price))*companynr as func from t3 group by companynr; companynr count sum diff func @@ -2039,26 +2039,26 @@ t2nr count(*) select max(t2nr) from t3 where price=983543950; max(t2nr) 41807 -select t1.period from t3 = t1 limit 1; -period +select t1.period_ from t3 = t1 limit 1; +period_ 1001 -select t1.period from t1 as t1 limit 1; -period +select t1.period_ from t1 as t1 limit 1; +period_ 9410 -select t1.period as "Nuvarande period" from t1 as t1 limit 1; -Nuvarande period +select t1.period_ as "Nuvarande period_" from t1 as t1 limit 1; +Nuvarande period_ 9410 -select period as ok_period from t1 limit 1; +select period_ as ok_period from t1 limit 1; ok_period 9410 -select period as ok_period from t1 group by ok_period limit 1; +select period_ as ok_period from t1 group by ok_period limit 1; ok_period 9410 select 1+1 as summa from t1 group by summa limit 1; summa 2 -select period as "Nuvarande period" from t1 group by "Nuvarande period" limit 1; -Nuvarande period +select period_ as "Nuvarande period_" from t1 group by "Nuvarande period_" limit 1; +Nuvarande period_ 9410 show tables; Tables_in_test @@ -5548,3 +5548,68 @@ select (SELECT name FROM t1 WHERE name='tom' AND pw=PASSWORD(@undefined)); NULL drop table t1; End of 10.0 tests +# +# System Versioning Support +# +# +CREATE TABLE t1( x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; +INSERT INTO t1(x, y) VALUES +(0, 100), +(1, 101), +(2, 102), +(3, 103), +(4, 104), +(5, 105), +(6, 106), +(7, 107), +(8, 108), +(9, 109); +DELETE FROM t1 WHERE x = 3; +DELETE FROM t1 WHERE x > 7; +INSERT INTO t1(x, y) VALUES(3, 33); +SELECT @time := Sys_start FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07' WHERE x = 3 AND y = 33; +@time := Sys_start +Sys_start +SELECT x, y FROM t1; +x y +0 100 +1 101 +2 102 +4 104 +5 105 +6 106 +7 107 +3 33 +SET @query=CONCAT('SELECT x, y FROM t1 FOR SYSTEM_TIME FROM TIMESTAMP \'0-0-0 0:0:0\' TO TIMESTAMP \'', @time, '\''); +PREPARE stmt_t1 FROM @query; +EXECUTE stmt_t1; +x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +SET @query=CONCAT('SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP \'0-0-0 0:0:0\' AND TIMESTAMP \'', @time, '\''); +PREPARE stmt_t1 FROM @query; +EXECUTE stmt_t1; +x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +3 33 +SET @time=NULL; +SET @query=NULL; +DEALLOCATE PREPARE stmt_t1; +DROP TABLE t1; diff --git a/mysql-test/r/select_jcl6.result b/mysql-test/r/select_jcl6.result index c9d582bb75a..ade583db19e 100644 --- a/mysql-test/r/select_jcl6.result +++ b/mysql-test/r/select_jcl6.result @@ -16,18 +16,18 @@ SET @save_optimizer_switch=@@optimizer_switch; SET optimizer_switch=ifnull(@optimizer_switch_for_select_test,'outer_join_with_cache=off'); set join_cache_level=@join_cache_level_for_select_test; CREATE TABLE t1 ( -Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, +Period_ smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL ); INSERT INTO t1 VALUES (9410,9412); -select period from t1; -period +select period_ from t1; +period_ 9410 select * from t1; -Period Varor_period +Period_ Varor_period 9410 9412 select t1.* from t1; -Period Varor_period +Period_ Varor_period 9410 9412 CREATE TABLE t2 ( auto int not null auto_increment, @@ -291,8 +291,8 @@ companynr 34 29 00 -select distinct t2.fld3,period from t2,t1 where companynr=37 and fld3 like "O%"; -fld3 period +select distinct t2.fld3,period_ from t2,t1 where companynr=37 and fld3 like "O%"; +fld3 period_ obliterates 9410 offload 9410 opaquely 9410 @@ -496,12 +496,12 @@ acu Ade adj create table t3 ( -period int not null, +period_ int not null, name char(32) not null, companynr int not null, price double(11,0), price2 double(11,0), -key (period), +key (period_), key (name) ); create temporary table tmp engine = myisam select * from t3; @@ -615,35 +615,35 @@ explain select t3.t2nr,fld3 from t2,t3 where t2.companynr = 34 and t2.fld1=t3.t2 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL fld1 NULL NULL NULL 1199 Using where; Using temporary; Using filesort 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.fld1 1 Using where; Using index -explain select * from t3 as t1,t3 where t1.period=t3.period order by t3.period; +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t3.period_; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL period NULL NULL NULL 41810 Using temporary; Using filesort -1 SIMPLE t3 ref period period 4 test.t1.period 4181 Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan -explain select * from t3 as t1,t3 where t1.period=t3.period order by t3.period limit 10; +1 SIMPLE t1 ALL period_ NULL NULL NULL 41810 Using temporary; Using filesort +1 SIMPLE t3 ref period_ period_ 4 test.t1.period_ 4181 Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t3.period_ limit 10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t3 ALL period NULL NULL NULL 41810 Using temporary; Using filesort -1 SIMPLE t1 ref period period 4 test.t3.period 4181 Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan -explain select * from t3 as t1,t3 where t1.period=t3.period order by t1.period limit 10; +1 SIMPLE t3 ALL period_ NULL NULL NULL 41810 Using temporary; Using filesort +1 SIMPLE t1 ref period_ period_ 4 test.t3.period_ 4181 Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t1.period_ limit 10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL period NULL NULL NULL 41810 Using temporary; Using filesort -1 SIMPLE t3 ref period period 4 test.t1.period 4181 Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan -select period from t1; -period +1 SIMPLE t1 ALL period_ NULL NULL NULL 41810 Using temporary; Using filesort +1 SIMPLE t3 ref period_ period_ 4 test.t1.period_ 4181 Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan +select period_ from t1; +period_ 9410 -select period from t1 where period=1900; -period -select fld3,period from t1,t2 where fld1 = 011401 order by period; -fld3 period +select period_ from t1 where period_=1900; +period_ +select fld3,period_ from t1,t2 where fld1 = 011401 order by period_; +fld3 period_ breaking 9410 -select fld3,period from t2,t3 where t2.fld1 = 011401 and t2.fld1=t3.t2nr and t3.period=1001; -fld3 period +select fld3,period_ from t2,t3 where t2.fld1 = 011401 and t2.fld1=t3.t2nr and t3.period_=1001; +fld3 period_ breaking 1001 -explain select fld3,period from t2,t3 where t2.fld1 = 011401 and t3.t2nr=t2.fld1 and 1001 = t3.period; +explain select fld3,period_ from t2,t3 where t2.fld1 = 011401 and t3.t2nr=t2.fld1 and 1001 = t3.period_; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 const fld1 fld1 4 const 1 -1 SIMPLE t3 const PRIMARY,period PRIMARY 4 const 1 -select fld3,period from t2,t1 where companynr*10 = 37*10; -fld3 period +1 SIMPLE t3 const PRIMARY,period_ PRIMARY 4 const 1 +select fld3,period_ from t2,t1 where companynr*10 = 37*10; +fld3 period_ breaking 9410 Romans 9410 intercepted 9410 @@ -1232,8 +1232,8 @@ dusted 9410 encompasses 9410 presentation 9410 Kantian 9410 -select fld3,period,price,price2 from t2,t3 where t2.fld1=t3.t2nr and period >= 1001 and period <= 1002 and t2.companynr = 37 order by fld3,period, price; -fld3 period price price2 +select fld3,period_,price,price2 from t2,t3 where t2.fld1=t3.t2nr and period_ >= 1001 and period_ <= 1002 and t2.companynr = 37 order by fld3,period_, price; +fld3 period_ price price2 admonishing 1002 28357832 8723648 analyzable 1002 28357832 8723648 annihilates 1001 5987435 234724 @@ -1293,8 +1293,8 @@ ventilate 1001 5987435 234724 wallet 1001 5987435 234724 Weissmuller 1002 28357832 8723648 Wotan 1002 28357832 8723648 -select t2.fld1,fld3,period,price,price2 from t2,t3 where t2.fld1>= 18201 and t2.fld1 <= 18811 and t2.fld1=t3.t2nr and period = 1001 and t2.companynr = 37; -fld1 fld3 period price price2 +select t2.fld1,fld3,period_,price,price2 from t2,t3 where t2.fld1>= 18201 and t2.fld1 <= 18811 and t2.fld1=t3.t2nr and period_ = 1001 and t2.companynr = 37; +fld1 fld3 period_ price price2 018201 relaxing 1001 5987435 234724 018601 vacuuming 1001 5987435 234724 018801 inch 1001 5987435 234724 @@ -1334,7 +1334,7 @@ companynr companyname 65 company 9 68 company 10 select * from t1,t1 t12; -Period Varor_period Period Varor_period +Period_ Varor_period Period_ Varor_period 9410 9412 9410 9412 select t2.fld1,t22.fld1 from t2,t2 t22 where t2.fld1 >= 250501 and t2.fld1 <= 250505 and t22.fld1 >= 250501 and t22.fld1 <= 250505; fld1 fld1 @@ -1446,23 +1446,23 @@ explain select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr= id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t4 index NULL PRIMARY 1 NULL 12 Using index; Using temporary 1 SIMPLE t2 hash_ALL NULL #hash#$hj 1 func 1199 Using where; Using join buffer (flat, BNLH join) -select t2.fld1,t2.companynr,fld3,period from t3,t2 where t2.fld1 = 38208 and t2.fld1=t3.t2nr and period = 1008 or t2.fld1 = 38008 and t2.fld1 =t3.t2nr and period = 1008; -fld1 companynr fld3 period +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where t2.fld1 = 38208 and t2.fld1=t3.t2nr and period_ = 1008 or t2.fld1 = 38008 and t2.fld1 =t3.t2nr and period_ = 1008; +fld1 companynr fld3 period_ 038008 37 reporters 1008 038208 37 Selfridge 1008 -select t2.fld1,t2.companynr,fld3,period from t3,t2 where (t2.fld1 = 38208 or t2.fld1 = 38008) and t2.fld1=t3.t2nr and period>=1008 and period<=1009; -fld1 companynr fld3 period +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where (t2.fld1 = 38208 or t2.fld1 = 38008) and t2.fld1=t3.t2nr and period_>=1008 and period_<=1009; +fld1 companynr fld3 period_ 038008 37 reporters 1008 038208 37 Selfridge 1008 -select t2.fld1,t2.companynr,fld3,period from t3,t2 where (t3.t2nr = 38208 or t3.t2nr = 38008) and t2.fld1=t3.t2nr and period>=1008 and period<=1009; -fld1 companynr fld3 period +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where (t3.t2nr = 38208 or t3.t2nr = 38008) and t2.fld1=t3.t2nr and period_>=1008 and period_<=1009; +fld1 companynr fld3 period_ 038008 37 reporters 1008 038208 37 Selfridge 1008 -select period from t1 where (((period > 0) or period < 10000 or (period = 1900)) and (period=1900 and period <= 1901) or (period=1903 and (period=1903)) and period>=1902) or ((period=1904 or period=1905) or (period=1906 or period>1907)) or (period=1908 and period = 1909); -period +select period_ from t1 where (((period_ > 0) or period_ < 10000 or (period_ = 1900)) and (period_=1900 and period_ <= 1901) or (period_=1903 and (period_=1903)) and period_>=1902) or ((period_=1904 or period_=1905) or (period_=1906 or period_>1907)) or (period_=1908 and period_ = 1909); +period_ 9410 -select period from t1 where ((period > 0 and period < 1) or (((period > 0 and period < 100) and (period > 10)) or (period > 10)) or (period > 0 and (period > 5 or period > 6))); -period +select period_ from t1 where ((period_ > 0 and period_ < 1) or (((period_ > 0 and period_ < 100) and (period_ > 10)) or (period_ > 10)) or (period_ > 0 and (period_ > 5 or period_ > 6))); +period_ 9410 select a.fld1 from t2 as a,t2 b where ((a.fld1 = 250501 and a.fld1=b.fld1) or a.fld1=250502 or a.fld1=250503 or (a.fld1=250505 and a.fld1<=b.fld1 and b.fld1>=a.fld1)) and a.fld1=b.fld1; fld1 @@ -1719,8 +1719,8 @@ companynr companyname count(*) select t2.fld1,count(*) from t2,t3 where t2.fld1=158402 and t3.name=t2.fld3 group by t3.name; fld1 count(*) 158402 4181 -select sum(Period)/count(*) from t1; -sum(Period)/count(*) +select sum(Period_)/count(*) from t1; +sum(Period_)/count(*) 9410.0000 select companynr,count(price) as "count",sum(price) as "sum" ,abs(sum(price)/count(price)-avg(price)) as "diff",(0+count(price))*companynr as func from t3 group by companynr; companynr count sum diff func @@ -2050,26 +2050,26 @@ t2nr count(*) select max(t2nr) from t3 where price=983543950; max(t2nr) 41807 -select t1.period from t3 = t1 limit 1; -period +select t1.period_ from t3 = t1 limit 1; +period_ 1001 -select t1.period from t1 as t1 limit 1; -period +select t1.period_ from t1 as t1 limit 1; +period_ 9410 -select t1.period as "Nuvarande period" from t1 as t1 limit 1; -Nuvarande period +select t1.period_ as "Nuvarande period_" from t1 as t1 limit 1; +Nuvarande period_ 9410 -select period as ok_period from t1 limit 1; +select period_ as ok_period from t1 limit 1; ok_period 9410 -select period as ok_period from t1 group by ok_period limit 1; +select period_ as ok_period from t1 group by ok_period limit 1; ok_period 9410 select 1+1 as summa from t1 group by summa limit 1; summa 2 -select period as "Nuvarande period" from t1 group by "Nuvarande period" limit 1; -Nuvarande period +select period_ as "Nuvarande period_" from t1 group by "Nuvarande period_" limit 1; +Nuvarande period_ 9410 show tables; Tables_in_test @@ -5559,6 +5559,71 @@ select (SELECT name FROM t1 WHERE name='tom' AND pw=PASSWORD(@undefined)); NULL drop table t1; End of 10.0 tests +# +# System Versioning Support +# +# +CREATE TABLE t1( x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; +INSERT INTO t1(x, y) VALUES +(0, 100), +(1, 101), +(2, 102), +(3, 103), +(4, 104), +(5, 105), +(6, 106), +(7, 107), +(8, 108), +(9, 109); +DELETE FROM t1 WHERE x = 3; +DELETE FROM t1 WHERE x > 7; +INSERT INTO t1(x, y) VALUES(3, 33); +SELECT @time := Sys_start FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07' WHERE x = 3 AND y = 33; +@time := Sys_start +Sys_start +SELECT x, y FROM t1; +x y +0 100 +1 101 +2 102 +4 104 +5 105 +6 106 +7 107 +3 33 +SET @query=CONCAT('SELECT x, y FROM t1 FOR SYSTEM_TIME FROM TIMESTAMP \'0-0-0 0:0:0\' TO TIMESTAMP \'', @time, '\''); +PREPARE stmt_t1 FROM @query; +EXECUTE stmt_t1; +x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +SET @query=CONCAT('SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP \'0-0-0 0:0:0\' AND TIMESTAMP \'', @time, '\''); +PREPARE stmt_t1 FROM @query; +EXECUTE stmt_t1; +x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +3 33 +SET @time=NULL; +SET @query=NULL; +DEALLOCATE PREPARE stmt_t1; +DROP TABLE t1; set join_cache_level=default; show variables like 'join_cache_level'; Variable_name Value diff --git a/mysql-test/r/select_pkeycache.result b/mysql-test/r/select_pkeycache.result index 5859bd0fae6..c260e2ff333 100644 --- a/mysql-test/r/select_pkeycache.result +++ b/mysql-test/r/select_pkeycache.result @@ -5,18 +5,18 @@ SET @save_optimizer_switch=@@optimizer_switch; SET optimizer_switch=ifnull(@optimizer_switch_for_select_test,'outer_join_with_cache=off'); set join_cache_level=1; CREATE TABLE t1 ( -Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, +Period_ smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL ); INSERT INTO t1 VALUES (9410,9412); -select period from t1; -period +select period_ from t1; +period_ 9410 select * from t1; -Period Varor_period +Period_ Varor_period 9410 9412 select t1.* from t1; -Period Varor_period +Period_ Varor_period 9410 9412 CREATE TABLE t2 ( auto int not null auto_increment, @@ -280,8 +280,8 @@ companynr 34 29 00 -select distinct t2.fld3,period from t2,t1 where companynr=37 and fld3 like "O%"; -fld3 period +select distinct t2.fld3,period_ from t2,t1 where companynr=37 and fld3 like "O%"; +fld3 period_ obliterates 9410 offload 9410 opaquely 9410 @@ -485,12 +485,12 @@ acu Ade adj create table t3 ( -period int not null, +period_ int not null, name char(32) not null, companynr int not null, price double(11,0), price2 double(11,0), -key (period), +key (period_), key (name) ); create temporary table tmp engine = myisam select * from t3; @@ -604,35 +604,35 @@ explain select t3.t2nr,fld3 from t2,t3 where t2.companynr = 34 and t2.fld1=t3.t2 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL fld1 NULL NULL NULL 1199 Using where; Using temporary; Using filesort 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.fld1 1 Using where; Using index -explain select * from t3 as t1,t3 where t1.period=t3.period order by t3.period; +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t3.period_; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL period NULL NULL NULL 41810 Using filesort -1 SIMPLE t3 ref period period 4 test.t1.period 4181 -explain select * from t3 as t1,t3 where t1.period=t3.period order by t3.period limit 10; +1 SIMPLE t1 ALL period_ NULL NULL NULL 41810 Using filesort +1 SIMPLE t3 ref period_ period_ 4 test.t1.period_ 4181 +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t3.period_ limit 10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t3 index period period 4 NULL 1 -1 SIMPLE t1 ref period period 4 test.t3.period 4181 -explain select * from t3 as t1,t3 where t1.period=t3.period order by t1.period limit 10; +1 SIMPLE t3 index period_ period_ 4 NULL 1 +1 SIMPLE t1 ref period_ period_ 4 test.t3.period_ 4181 +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t1.period_ limit 10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index period period 4 NULL 1 -1 SIMPLE t3 ref period period 4 test.t1.period 4181 -select period from t1; -period +1 SIMPLE t1 index period_ period_ 4 NULL 1 +1 SIMPLE t3 ref period_ period_ 4 test.t1.period_ 4181 +select period_ from t1; +period_ 9410 -select period from t1 where period=1900; -period -select fld3,period from t1,t2 where fld1 = 011401 order by period; -fld3 period +select period_ from t1 where period_=1900; +period_ +select fld3,period_ from t1,t2 where fld1 = 011401 order by period_; +fld3 period_ breaking 9410 -select fld3,period from t2,t3 where t2.fld1 = 011401 and t2.fld1=t3.t2nr and t3.period=1001; -fld3 period +select fld3,period_ from t2,t3 where t2.fld1 = 011401 and t2.fld1=t3.t2nr and t3.period_=1001; +fld3 period_ breaking 1001 -explain select fld3,period from t2,t3 where t2.fld1 = 011401 and t3.t2nr=t2.fld1 and 1001 = t3.period; +explain select fld3,period_ from t2,t3 where t2.fld1 = 011401 and t3.t2nr=t2.fld1 and 1001 = t3.period_; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 const fld1 fld1 4 const 1 -1 SIMPLE t3 const PRIMARY,period PRIMARY 4 const 1 -select fld3,period from t2,t1 where companynr*10 = 37*10; -fld3 period +1 SIMPLE t3 const PRIMARY,period_ PRIMARY 4 const 1 +select fld3,period_ from t2,t1 where companynr*10 = 37*10; +fld3 period_ breaking 9410 Romans 9410 intercepted 9410 @@ -1221,8 +1221,8 @@ dusted 9410 encompasses 9410 presentation 9410 Kantian 9410 -select fld3,period,price,price2 from t2,t3 where t2.fld1=t3.t2nr and period >= 1001 and period <= 1002 and t2.companynr = 37 order by fld3,period, price; -fld3 period price price2 +select fld3,period_,price,price2 from t2,t3 where t2.fld1=t3.t2nr and period_ >= 1001 and period_ <= 1002 and t2.companynr = 37 order by fld3,period_, price; +fld3 period_ price price2 admonishing 1002 28357832 8723648 analyzable 1002 28357832 8723648 annihilates 1001 5987435 234724 @@ -1282,8 +1282,8 @@ ventilate 1001 5987435 234724 wallet 1001 5987435 234724 Weissmuller 1002 28357832 8723648 Wotan 1002 28357832 8723648 -select t2.fld1,fld3,period,price,price2 from t2,t3 where t2.fld1>= 18201 and t2.fld1 <= 18811 and t2.fld1=t3.t2nr and period = 1001 and t2.companynr = 37; -fld1 fld3 period price price2 +select t2.fld1,fld3,period_,price,price2 from t2,t3 where t2.fld1>= 18201 and t2.fld1 <= 18811 and t2.fld1=t3.t2nr and period_ = 1001 and t2.companynr = 37; +fld1 fld3 period_ price price2 018201 relaxing 1001 5987435 234724 018601 vacuuming 1001 5987435 234724 018801 inch 1001 5987435 234724 @@ -1323,7 +1323,7 @@ companynr companyname 65 company 9 68 company 10 select * from t1,t1 t12; -Period Varor_period Period Varor_period +Period_ Varor_period Period_ Varor_period 9410 9412 9410 9412 select t2.fld1,t22.fld1 from t2,t2 t22 where t2.fld1 >= 250501 and t2.fld1 <= 250505 and t22.fld1 >= 250501 and t22.fld1 <= 250505; fld1 fld1 @@ -1435,23 +1435,23 @@ explain select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr= id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t4 index NULL PRIMARY 1 NULL 12 Using index; Using temporary 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where; Using join buffer (flat, BNL join) -select t2.fld1,t2.companynr,fld3,period from t3,t2 where t2.fld1 = 38208 and t2.fld1=t3.t2nr and period = 1008 or t2.fld1 = 38008 and t2.fld1 =t3.t2nr and period = 1008; -fld1 companynr fld3 period +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where t2.fld1 = 38208 and t2.fld1=t3.t2nr and period_ = 1008 or t2.fld1 = 38008 and t2.fld1 =t3.t2nr and period_ = 1008; +fld1 companynr fld3 period_ 038008 37 reporters 1008 038208 37 Selfridge 1008 -select t2.fld1,t2.companynr,fld3,period from t3,t2 where (t2.fld1 = 38208 or t2.fld1 = 38008) and t2.fld1=t3.t2nr and period>=1008 and period<=1009; -fld1 companynr fld3 period +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where (t2.fld1 = 38208 or t2.fld1 = 38008) and t2.fld1=t3.t2nr and period_>=1008 and period_<=1009; +fld1 companynr fld3 period_ 038008 37 reporters 1008 038208 37 Selfridge 1008 -select t2.fld1,t2.companynr,fld3,period from t3,t2 where (t3.t2nr = 38208 or t3.t2nr = 38008) and t2.fld1=t3.t2nr and period>=1008 and period<=1009; -fld1 companynr fld3 period +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where (t3.t2nr = 38208 or t3.t2nr = 38008) and t2.fld1=t3.t2nr and period_>=1008 and period_<=1009; +fld1 companynr fld3 period_ 038008 37 reporters 1008 038208 37 Selfridge 1008 -select period from t1 where (((period > 0) or period < 10000 or (period = 1900)) and (period=1900 and period <= 1901) or (period=1903 and (period=1903)) and period>=1902) or ((period=1904 or period=1905) or (period=1906 or period>1907)) or (period=1908 and period = 1909); -period +select period_ from t1 where (((period_ > 0) or period_ < 10000 or (period_ = 1900)) and (period_=1900 and period_ <= 1901) or (period_=1903 and (period_=1903)) and period_>=1902) or ((period_=1904 or period_=1905) or (period_=1906 or period_>1907)) or (period_=1908 and period_ = 1909); +period_ 9410 -select period from t1 where ((period > 0 and period < 1) or (((period > 0 and period < 100) and (period > 10)) or (period > 10)) or (period > 0 and (period > 5 or period > 6))); -period +select period_ from t1 where ((period_ > 0 and period_ < 1) or (((period_ > 0 and period_ < 100) and (period_ > 10)) or (period_ > 10)) or (period_ > 0 and (period_ > 5 or period_ > 6))); +period_ 9410 select a.fld1 from t2 as a,t2 b where ((a.fld1 = 250501 and a.fld1=b.fld1) or a.fld1=250502 or a.fld1=250503 or (a.fld1=250505 and a.fld1<=b.fld1 and b.fld1>=a.fld1)) and a.fld1=b.fld1; fld1 @@ -1708,8 +1708,8 @@ companynr companyname count(*) select t2.fld1,count(*) from t2,t3 where t2.fld1=158402 and t3.name=t2.fld3 group by t3.name; fld1 count(*) 158402 4181 -select sum(Period)/count(*) from t1; -sum(Period)/count(*) +select sum(Period_)/count(*) from t1; +sum(Period_)/count(*) 9410.0000 select companynr,count(price) as "count",sum(price) as "sum" ,abs(sum(price)/count(price)-avg(price)) as "diff",(0+count(price))*companynr as func from t3 group by companynr; companynr count sum diff func @@ -2039,26 +2039,26 @@ t2nr count(*) select max(t2nr) from t3 where price=983543950; max(t2nr) 41807 -select t1.period from t3 = t1 limit 1; -period +select t1.period_ from t3 = t1 limit 1; +period_ 1001 -select t1.period from t1 as t1 limit 1; -period +select t1.period_ from t1 as t1 limit 1; +period_ 9410 -select t1.period as "Nuvarande period" from t1 as t1 limit 1; -Nuvarande period +select t1.period_ as "Nuvarande period_" from t1 as t1 limit 1; +Nuvarande period_ 9410 -select period as ok_period from t1 limit 1; +select period_ as ok_period from t1 limit 1; ok_period 9410 -select period as ok_period from t1 group by ok_period limit 1; +select period_ as ok_period from t1 group by ok_period limit 1; ok_period 9410 select 1+1 as summa from t1 group by summa limit 1; summa 2 -select period as "Nuvarande period" from t1 group by "Nuvarande period" limit 1; -Nuvarande period +select period_ as "Nuvarande period_" from t1 group by "Nuvarande period_" limit 1; +Nuvarande period_ 9410 show tables; Tables_in_test @@ -5548,3 +5548,68 @@ select (SELECT name FROM t1 WHERE name='tom' AND pw=PASSWORD(@undefined)); NULL drop table t1; End of 10.0 tests +# +# System Versioning Support +# +# +CREATE TABLE t1( x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; +INSERT INTO t1(x, y) VALUES +(0, 100), +(1, 101), +(2, 102), +(3, 103), +(4, 104), +(5, 105), +(6, 106), +(7, 107), +(8, 108), +(9, 109); +DELETE FROM t1 WHERE x = 3; +DELETE FROM t1 WHERE x > 7; +INSERT INTO t1(x, y) VALUES(3, 33); +SELECT @time := Sys_start FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07' WHERE x = 3 AND y = 33; +@time := Sys_start +Sys_start +SELECT x, y FROM t1; +x y +0 100 +1 101 +2 102 +4 104 +5 105 +6 106 +7 107 +3 33 +SET @query=CONCAT('SELECT x, y FROM t1 FOR SYSTEM_TIME FROM TIMESTAMP \'0-0-0 0:0:0\' TO TIMESTAMP \'', @time, '\''); +PREPARE stmt_t1 FROM @query; +EXECUTE stmt_t1; +x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +SET @query=CONCAT('SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP \'0-0-0 0:0:0\' AND TIMESTAMP \'', @time, '\''); +PREPARE stmt_t1 FROM @query; +EXECUTE stmt_t1; +x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +3 33 +SET @time=NULL; +SET @query=NULL; +DEALLOCATE PREPARE stmt_t1; +DROP TABLE t1; diff --git a/mysql-test/r/shm.result b/mysql-test/r/shm.result index 65187b6b19b..4a2286a8104 100644 --- a/mysql-test/r/shm.result +++ b/mysql-test/r/shm.result @@ -1,18 +1,18 @@ connect shm_con,localhost,root,,,,$shm_name,SHM; drop table if exists t1,t2,t3,t4; CREATE TABLE t1 ( -Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, +Period_ smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL ); INSERT INTO t1 VALUES (9410,9412); -select period from t1; -period +select period_ from t1; +period_ 9410 select * from t1; -Period Varor_period +Period_ Varor_period 9410 9412 select t1.* from t1; -Period Varor_period +Period_ Varor_period 9410 9412 CREATE TABLE t2 ( auto int not null auto_increment, @@ -276,8 +276,8 @@ companynr 34 29 00 -select distinct t2.fld3,period from t2,t1 where companynr=37 and fld3 like "O%"; -fld3 period +select distinct t2.fld3,period_ from t2,t1 where companynr=37 and fld3 like "O%"; +fld3 period_ obliterates 9410 offload 9410 opaquely 9410 @@ -481,12 +481,12 @@ acu Ade adj create table t3 ( -period int not null, +period_ int not null, name char(32) not null, companynr int not null, price double(11,0), price2 double(11,0), -key (period), +key (period_), key (name) ); create temporary table tmp engine = myisam select * from t3; @@ -600,35 +600,35 @@ explain select t3.t2nr,fld3 from t2,t3 where t2.companynr = 34 and t2.fld1=t3.t2 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL fld1 NULL NULL NULL 1199 Using where; Using temporary; Using filesort 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.fld1 1 Using where; Using index -explain select * from t3 as t1,t3 where t1.period=t3.period order by t3.period; +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t3.period_; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL period NULL NULL NULL 41810 Using filesort -1 SIMPLE t3 ref period period 4 test.t1.period 4181 -explain select * from t3 as t1,t3 where t1.period=t3.period order by t3.period limit 10; +1 SIMPLE t1 ALL period_ NULL NULL NULL 41810 Using temporary; Using filesort +1 SIMPLE t3 ref period_ period_ 4 test.t1.period_ 4181 +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t3.period_ limit 10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t3 index period period 4 NULL 1 -1 SIMPLE t1 ref period period 4 test.t3.period 4181 -explain select * from t3 as t1,t3 where t1.period=t3.period order by t1.period limit 10; +1 SIMPLE t3 index period_ period_ 4 NULL 1 +1 SIMPLE t1 ref period_ period_ 4 test.t3.period_ 4181 +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t1.period_ limit 10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index period period 4 NULL 1 -1 SIMPLE t3 ref period period 4 test.t1.period 4181 -select period from t1; -period +1 SIMPLE t1 index period_ period_ 4 NULL 1 +1 SIMPLE t3 ref period_ period_ 4 test.t1.period_ 4181 +select period_ from t1; +period_ 9410 -select period from t1 where period=1900; -period -select fld3,period from t1,t2 where fld1 = 011401 order by period; -fld3 period +select period_ from t1 where period_=1900; +period_ +select fld3,period_ from t1,t2 where fld1 = 011401 order by period_; +fld3 period_ breaking 9410 -select fld3,period from t2,t3 where t2.fld1 = 011401 and t2.fld1=t3.t2nr and t3.period=1001; -fld3 period +select fld3,period_ from t2,t3 where t2.fld1 = 011401 and t2.fld1=t3.t2nr and t3.period_=1001; +fld3 period_ breaking 1001 -explain select fld3,period from t2,t3 where t2.fld1 = 011401 and t3.t2nr=t2.fld1 and 1001 = t3.period; +explain select fld3,period_ from t2,t3 where t2.fld1 = 011401 and t3.t2nr=t2.fld1 and 1001 = t3.period_; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 const fld1 fld1 4 const 1 -1 SIMPLE t3 const PRIMARY,period PRIMARY 4 const 1 -select fld3,period from t2,t1 where companynr*10 = 37*10; -fld3 period +1 SIMPLE t3 const PRIMARY,period_ PRIMARY 4 const 1 +select fld3,period_ from t2,t1 where companynr*10 = 37*10; +fld3 period_ breaking 9410 Romans 9410 intercepted 9410 @@ -1217,8 +1217,8 @@ dusted 9410 encompasses 9410 presentation 9410 Kantian 9410 -select fld3,period,price,price2 from t2,t3 where t2.fld1=t3.t2nr and period >= 1001 and period <= 1002 and t2.companynr = 37 order by fld3,period, price; -fld3 period price price2 +select fld3,period_,price,price2 from t2,t3 where t2.fld1=t3.t2nr and period_ >= 1001 and period_ <= 1002 and t2.companynr = 37 order by fld3,period_, price; +fld3 period_ price price2 admonishing 1002 28357832 8723648 analyzable 1002 28357832 8723648 annihilates 1001 5987435 234724 @@ -1278,8 +1278,8 @@ ventilate 1001 5987435 234724 wallet 1001 5987435 234724 Weissmuller 1002 28357832 8723648 Wotan 1002 28357832 8723648 -select t2.fld1,fld3,period,price,price2 from t2,t3 where t2.fld1>= 18201 and t2.fld1 <= 18811 and t2.fld1=t3.t2nr and period = 1001 and t2.companynr = 37; -fld1 fld3 period price price2 +select t2.fld1,fld3,period_,price,price2 from t2,t3 where t2.fld1>= 18201 and t2.fld1 <= 18811 and t2.fld1=t3.t2nr and period_ = 1001 and t2.companynr = 37; +fld1 fld3 period_ price price2 018201 relaxing 1001 5987435 234724 018601 vacuuming 1001 5987435 234724 018801 inch 1001 5987435 234724 @@ -1319,7 +1319,7 @@ companynr companyname 65 company 9 68 company 10 select * from t1,t1 t12; -Period Varor_period Period Varor_period +Period_ Varor_period Period_ Varor_period 9410 9412 9410 9412 select t2.fld1,t22.fld1 from t2,t2 t22 where t2.fld1 >= 250501 and t2.fld1 <= 250505 and t22.fld1 >= 250501 and t22.fld1 <= 250505; fld1 fld1 @@ -1434,23 +1434,23 @@ explain select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr= id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t4 index NULL PRIMARY 1 NULL 12 Using index; Using temporary 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where; Using join buffer (flat, BNL join) -select t2.fld1,t2.companynr,fld3,period from t3,t2 where t2.fld1 = 38208 and t2.fld1=t3.t2nr and period = 1008 or t2.fld1 = 38008 and t2.fld1 =t3.t2nr and period = 1008; -fld1 companynr fld3 period +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where t2.fld1 = 38208 and t2.fld1=t3.t2nr and period_ = 1008 or t2.fld1 = 38008 and t2.fld1 =t3.t2nr and period_ = 1008; +fld1 companynr fld3 period_ 038008 37 reporters 1008 038208 37 Selfridge 1008 -select t2.fld1,t2.companynr,fld3,period from t3,t2 where (t2.fld1 = 38208 or t2.fld1 = 38008) and t2.fld1=t3.t2nr and period>=1008 and period<=1009; -fld1 companynr fld3 period +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where (t2.fld1 = 38208 or t2.fld1 = 38008) and t2.fld1=t3.t2nr and period_>=1008 and period_<=1009; +fld1 companynr fld3 period_ 038008 37 reporters 1008 038208 37 Selfridge 1008 -select t2.fld1,t2.companynr,fld3,period from t3,t2 where (t3.t2nr = 38208 or t3.t2nr = 38008) and t2.fld1=t3.t2nr and period>=1008 and period<=1009; -fld1 companynr fld3 period +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where (t3.t2nr = 38208 or t3.t2nr = 38008) and t2.fld1=t3.t2nr and period_>=1008 and period_<=1009; +fld1 companynr fld3 period_ 038008 37 reporters 1008 038208 37 Selfridge 1008 -select period from t1 where (((period > 0) or period < 10000 or (period = 1900)) and (period=1900 and period <= 1901) or (period=1903 and (period=1903)) and period>=1902) or ((period=1904 or period=1905) or (period=1906 or period>1907)) or (period=1908 and period = 1909); -period +select period_ from t1 where (((period_ > 0) or period_ < 10000 or (period_ = 1900)) and (period_=1900 and period_ <= 1901) or (period_=1903 and (period_=1903)) and period_>=1902) or ((period_=1904 or period_=1905) or (period_=1906 or period_>1907)) or (period_=1908 and period_ = 1909); +period_ 9410 -select period from t1 where ((period > 0 and period < 1) or (((period > 0 and period < 100) and (period > 10)) or (period > 10)) or (period > 0 and (period > 5 or period > 6))); -period +select period_ from t1 where ((period_ > 0 and period_ < 1) or (((period_ > 0 and period_ < 100) and (period_ > 10)) or (period_ > 10)) or (period_ > 0 and (period_ > 5 or period_ > 6))); +period_ 9410 select a.fld1 from t2 as a,t2 b where ((a.fld1 = 250501 and a.fld1=b.fld1) or a.fld1=250502 or a.fld1=250503 or (a.fld1=250505 and a.fld1<=b.fld1 and b.fld1>=a.fld1)) and a.fld1=b.fld1; fld1 @@ -1707,8 +1707,8 @@ companynr companyname count(*) select t2.fld1,count(*) from t2,t3 where t2.fld1=158402 and t3.name=t2.fld3 group by t3.name; fld1 count(*) 158402 4181 -select sum(Period)/count(*) from t1; -sum(Period)/count(*) +select sum(Period_)/count(*) from t1; +sum(Period_)/count(*) 9410.0000 select companynr,count(price) as "count",sum(price) as "sum" ,abs(sum(price)/count(price)-avg(price)) as "diff",(0+count(price))*companynr as func from t3 group by companynr; companynr count sum diff func @@ -2038,26 +2038,26 @@ t2nr count(*) select max(t2nr) from t3 where price=983543950; max(t2nr) 41807 -select t1.period from t3 = t1 limit 1; -period +select t1.period_ from t3 = t1 limit 1; +period_ 1001 -select t1.period from t1 as t1 limit 1; -period +select t1.period_ from t1 as t1 limit 1; +period_ 9410 -select t1.period as "Nuvarande period" from t1 as t1 limit 1; -Nuvarande period +select t1.period_ as "Nuvarande period_" from t1 as t1 limit 1; +Nuvarande period_ 9410 -select period as ok_period from t1 limit 1; +select period_ as ok_period from t1 limit 1; ok_period 9410 -select period as ok_period from t1 group by ok_period limit 1; +select period_ as ok_period from t1 group by ok_period limit 1; ok_period 9410 select 1+1 as summa from t1 group by summa limit 1; summa 2 -select period as "Nuvarande period" from t1 group by "Nuvarande period" limit 1; -Nuvarande period +select period_ as "Nuvarande period_" from t1 group by "Nuvarande period_" limit 1; +Nuvarande period_ 9410 show tables; Tables_in_test diff --git a/mysql-test/r/ssl.result b/mysql-test/r/ssl.result index ac18da81b93..6eb68e93be2 100644 --- a/mysql-test/r/ssl.result +++ b/mysql-test/r/ssl.result @@ -10,18 +10,18 @@ Variable_name Value Ssl_server_not_after Apr 20 14:55:05 2035 GMT drop table if exists t1,t2,t3,t4; CREATE TABLE t1 ( -Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, +Period_ smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL ); INSERT INTO t1 VALUES (9410,9412); -select period from t1; -period +select period_ from t1; +period_ 9410 select * from t1; -Period Varor_period +Period_ Varor_period 9410 9412 select t1.* from t1; -Period Varor_period +Period_ Varor_period 9410 9412 CREATE TABLE t2 ( auto int not null auto_increment, @@ -285,8 +285,8 @@ companynr 34 29 00 -select distinct t2.fld3,period from t2,t1 where companynr=37 and fld3 like "O%"; -fld3 period +select distinct t2.fld3,period_ from t2,t1 where companynr=37 and fld3 like "O%"; +fld3 period_ obliterates 9410 offload 9410 opaquely 9410 @@ -490,12 +490,12 @@ acu Ade adj create table t3 ( -period int not null, +period_ int not null, name char(32) not null, companynr int not null, price double(11,0), price2 double(11,0), -key (period), +key (period_), key (name) ); create temporary table tmp engine = myisam select * from t3; @@ -609,35 +609,35 @@ explain select t3.t2nr,fld3 from t2,t3 where t2.companynr = 34 and t2.fld1=t3.t2 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL fld1 NULL NULL NULL 1199 Using where; Using temporary; Using filesort 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.fld1 1 Using where; Using index -explain select * from t3 as t1,t3 where t1.period=t3.period order by t3.period; +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t3.period_; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL period NULL NULL NULL 41810 Using filesort -1 SIMPLE t3 ref period period 4 test.t1.period 4181 -explain select * from t3 as t1,t3 where t1.period=t3.period order by t3.period limit 10; +1 SIMPLE t1 ALL period_ NULL NULL NULL 41810 Using filesort +1 SIMPLE t3 ref period_ period_ 4 test.t1.period_ 4181 +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t3.period_ limit 10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t3 index period period 4 NULL 1 -1 SIMPLE t1 ref period period 4 test.t3.period 4181 -explain select * from t3 as t1,t3 where t1.period=t3.period order by t1.period limit 10; +1 SIMPLE t3 index period_ period_ 4 NULL 1 +1 SIMPLE t1 ref period_ period_ 4 test.t3.period_ 4181 +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t1.period_ limit 10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index period period 4 NULL 1 -1 SIMPLE t3 ref period period 4 test.t1.period 4181 -select period from t1; -period +1 SIMPLE t1 index period_ period_ 4 NULL 1 +1 SIMPLE t3 ref period_ period_ 4 test.t1.period_ 4181 +select period_ from t1; +period_ 9410 -select period from t1 where period=1900; -period -select fld3,period from t1,t2 where fld1 = 011401 order by period; -fld3 period +select period_ from t1 where period_=1900; +period_ +select fld3,period_ from t1,t2 where fld1 = 011401 order by period_; +fld3 period_ breaking 9410 -select fld3,period from t2,t3 where t2.fld1 = 011401 and t2.fld1=t3.t2nr and t3.period=1001; -fld3 period +select fld3,period_ from t2,t3 where t2.fld1 = 011401 and t2.fld1=t3.t2nr and t3.period_=1001; +fld3 period_ breaking 1001 -explain select fld3,period from t2,t3 where t2.fld1 = 011401 and t3.t2nr=t2.fld1 and 1001 = t3.period; +explain select fld3,period_ from t2,t3 where t2.fld1 = 011401 and t3.t2nr=t2.fld1 and 1001 = t3.period_; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 const fld1 fld1 4 const 1 -1 SIMPLE t3 const PRIMARY,period PRIMARY 4 const 1 -select fld3,period from t2,t1 where companynr*10 = 37*10; -fld3 period +1 SIMPLE t3 const PRIMARY,period_ PRIMARY 4 const 1 +select fld3,period_ from t2,t1 where companynr*10 = 37*10; +fld3 period_ breaking 9410 Romans 9410 intercepted 9410 @@ -1226,8 +1226,8 @@ dusted 9410 encompasses 9410 presentation 9410 Kantian 9410 -select fld3,period,price,price2 from t2,t3 where t2.fld1=t3.t2nr and period >= 1001 and period <= 1002 and t2.companynr = 37 order by fld3,period, price; -fld3 period price price2 +select fld3,period_,price,price2 from t2,t3 where t2.fld1=t3.t2nr and period_ >= 1001 and period_ <= 1002 and t2.companynr = 37 order by fld3,period_, price; +fld3 period_ price price2 admonishing 1002 28357832 8723648 analyzable 1002 28357832 8723648 annihilates 1001 5987435 234724 @@ -1287,8 +1287,8 @@ ventilate 1001 5987435 234724 wallet 1001 5987435 234724 Weissmuller 1002 28357832 8723648 Wotan 1002 28357832 8723648 -select t2.fld1,fld3,period,price,price2 from t2,t3 where t2.fld1>= 18201 and t2.fld1 <= 18811 and t2.fld1=t3.t2nr and period = 1001 and t2.companynr = 37; -fld1 fld3 period price price2 +select t2.fld1,fld3,period_,price,price2 from t2,t3 where t2.fld1>= 18201 and t2.fld1 <= 18811 and t2.fld1=t3.t2nr and period_ = 1001 and t2.companynr = 37; +fld1 fld3 period_ price price2 018201 relaxing 1001 5987435 234724 018601 vacuuming 1001 5987435 234724 018801 inch 1001 5987435 234724 @@ -1328,7 +1328,7 @@ companynr companyname 65 company 9 68 company 10 select * from t1,t1 t12; -Period Varor_period Period Varor_period +Period_ Varor_period Period_ Varor_period 9410 9412 9410 9412 select t2.fld1,t22.fld1 from t2,t2 t22 where t2.fld1 >= 250501 and t2.fld1 <= 250505 and t22.fld1 >= 250501 and t22.fld1 <= 250505; fld1 fld1 @@ -1443,23 +1443,23 @@ explain select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr= id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t4 index NULL PRIMARY 1 NULL 12 Using index; Using temporary 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where; Using join buffer (flat, BNL join) -select t2.fld1,t2.companynr,fld3,period from t3,t2 where t2.fld1 = 38208 and t2.fld1=t3.t2nr and period = 1008 or t2.fld1 = 38008 and t2.fld1 =t3.t2nr and period = 1008; -fld1 companynr fld3 period +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where t2.fld1 = 38208 and t2.fld1=t3.t2nr and period_ = 1008 or t2.fld1 = 38008 and t2.fld1 =t3.t2nr and period_ = 1008; +fld1 companynr fld3 period_ 038008 37 reporters 1008 038208 37 Selfridge 1008 -select t2.fld1,t2.companynr,fld3,period from t3,t2 where (t2.fld1 = 38208 or t2.fld1 = 38008) and t2.fld1=t3.t2nr and period>=1008 and period<=1009; -fld1 companynr fld3 period +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where (t2.fld1 = 38208 or t2.fld1 = 38008) and t2.fld1=t3.t2nr and period_>=1008 and period_<=1009; +fld1 companynr fld3 period_ 038008 37 reporters 1008 038208 37 Selfridge 1008 -select t2.fld1,t2.companynr,fld3,period from t3,t2 where (t3.t2nr = 38208 or t3.t2nr = 38008) and t2.fld1=t3.t2nr and period>=1008 and period<=1009; -fld1 companynr fld3 period +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where (t3.t2nr = 38208 or t3.t2nr = 38008) and t2.fld1=t3.t2nr and period_>=1008 and period_<=1009; +fld1 companynr fld3 period_ 038008 37 reporters 1008 038208 37 Selfridge 1008 -select period from t1 where (((period > 0) or period < 10000 or (period = 1900)) and (period=1900 and period <= 1901) or (period=1903 and (period=1903)) and period>=1902) or ((period=1904 or period=1905) or (period=1906 or period>1907)) or (period=1908 and period = 1909); -period +select period_ from t1 where (((period_ > 0) or period_ < 10000 or (period_ = 1900)) and (period_=1900 and period_ <= 1901) or (period_=1903 and (period_=1903)) and period_>=1902) or ((period_=1904 or period_=1905) or (period_=1906 or period_>1907)) or (period_=1908 and period_ = 1909); +period_ 9410 -select period from t1 where ((period > 0 and period < 1) or (((period > 0 and period < 100) and (period > 10)) or (period > 10)) or (period > 0 and (period > 5 or period > 6))); -period +select period_ from t1 where ((period_ > 0 and period_ < 1) or (((period_ > 0 and period_ < 100) and (period_ > 10)) or (period_ > 10)) or (period_ > 0 and (period_ > 5 or period_ > 6))); +period_ 9410 select a.fld1 from t2 as a,t2 b where ((a.fld1 = 250501 and a.fld1=b.fld1) or a.fld1=250502 or a.fld1=250503 or (a.fld1=250505 and a.fld1<=b.fld1 and b.fld1>=a.fld1)) and a.fld1=b.fld1; fld1 @@ -1716,8 +1716,8 @@ companynr companyname count(*) select t2.fld1,count(*) from t2,t3 where t2.fld1=158402 and t3.name=t2.fld3 group by t3.name; fld1 count(*) 158402 4181 -select sum(Period)/count(*) from t1; -sum(Period)/count(*) +select sum(Period_)/count(*) from t1; +sum(Period_)/count(*) 9410.0000 select companynr,count(price) as "count",sum(price) as "sum" ,abs(sum(price)/count(price)-avg(price)) as "diff",(0+count(price))*companynr as func from t3 group by companynr; companynr count sum diff func @@ -2047,26 +2047,26 @@ t2nr count(*) select max(t2nr) from t3 where price=983543950; max(t2nr) 41807 -select t1.period from t3 = t1 limit 1; -period +select t1.period_ from t3 = t1 limit 1; +period_ 1001 -select t1.period from t1 as t1 limit 1; -period +select t1.period_ from t1 as t1 limit 1; +period_ 9410 -select t1.period as "Nuvarande period" from t1 as t1 limit 1; -Nuvarande period +select t1.period_ as "Nuvarande period_" from t1 as t1 limit 1; +Nuvarande period_ 9410 -select period as ok_period from t1 limit 1; +select period_ as ok_period from t1 limit 1; ok_period 9410 -select period as ok_period from t1 group by ok_period limit 1; +select period_ as ok_period from t1 group by ok_period limit 1; ok_period 9410 select 1+1 as summa from t1 group by summa limit 1; summa 2 -select period as "Nuvarande period" from t1 group by "Nuvarande period" limit 1; -Nuvarande period +select period_ as "Nuvarande period_" from t1 group by "Nuvarande period_" limit 1; +Nuvarande period_ 9410 show tables; Tables_in_test diff --git a/mysql-test/r/ssl_compress.result b/mysql-test/r/ssl_compress.result index 4e37cc68a24..d195816caa9 100644 --- a/mysql-test/r/ssl_compress.result +++ b/mysql-test/r/ssl_compress.result @@ -7,18 +7,18 @@ Variable_name Value Compression ON drop table if exists t1,t2,t3,t4; CREATE TABLE t1 ( -Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, +Period_ smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL ); INSERT INTO t1 VALUES (9410,9412); -select period from t1; -period +select period_ from t1; +period_ 9410 select * from t1; -Period Varor_period +Period_ Varor_period 9410 9412 select t1.* from t1; -Period Varor_period +Period_ Varor_period 9410 9412 CREATE TABLE t2 ( auto int not null auto_increment, @@ -282,8 +282,8 @@ companynr 34 29 00 -select distinct t2.fld3,period from t2,t1 where companynr=37 and fld3 like "O%"; -fld3 period +select distinct t2.fld3,period_ from t2,t1 where companynr=37 and fld3 like "O%"; +fld3 period_ obliterates 9410 offload 9410 opaquely 9410 @@ -487,12 +487,12 @@ acu Ade adj create table t3 ( -period int not null, +period_ int not null, name char(32) not null, companynr int not null, price double(11,0), price2 double(11,0), -key (period), +key (period_), key (name) ); create temporary table tmp engine = myisam select * from t3; @@ -606,35 +606,35 @@ explain select t3.t2nr,fld3 from t2,t3 where t2.companynr = 34 and t2.fld1=t3.t2 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL fld1 NULL NULL NULL 1199 Using where; Using temporary; Using filesort 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.fld1 1 Using where; Using index -explain select * from t3 as t1,t3 where t1.period=t3.period order by t3.period; +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t3.period_; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL period NULL NULL NULL 41810 Using filesort -1 SIMPLE t3 ref period period 4 test.t1.period 4181 -explain select * from t3 as t1,t3 where t1.period=t3.period order by t3.period limit 10; +1 SIMPLE t1 ALL period_ NULL NULL NULL 41810 Using filesort +1 SIMPLE t3 ref period_ period_ 4 test.t1.period_ 4181 +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t3.period_ limit 10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t3 index period period 4 NULL 1 -1 SIMPLE t1 ref period period 4 test.t3.period 4181 -explain select * from t3 as t1,t3 where t1.period=t3.period order by t1.period limit 10; +1 SIMPLE t3 index period_ period_ 4 NULL 1 +1 SIMPLE t1 ref period_ period_ 4 test.t3.period_ 4181 +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t1.period_ limit 10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index period period 4 NULL 1 -1 SIMPLE t3 ref period period 4 test.t1.period 4181 -select period from t1; -period +1 SIMPLE t1 index period_ period_ 4 NULL 1 +1 SIMPLE t3 ref period_ period_ 4 test.t1.period_ 4181 +select period_ from t1; +period_ 9410 -select period from t1 where period=1900; -period -select fld3,period from t1,t2 where fld1 = 011401 order by period; -fld3 period +select period_ from t1 where period_=1900; +period_ +select fld3,period_ from t1,t2 where fld1 = 011401 order by period_; +fld3 period_ breaking 9410 -select fld3,period from t2,t3 where t2.fld1 = 011401 and t2.fld1=t3.t2nr and t3.period=1001; -fld3 period +select fld3,period_ from t2,t3 where t2.fld1 = 011401 and t2.fld1=t3.t2nr and t3.period_=1001; +fld3 period_ breaking 1001 -explain select fld3,period from t2,t3 where t2.fld1 = 011401 and t3.t2nr=t2.fld1 and 1001 = t3.period; +explain select fld3,period_ from t2,t3 where t2.fld1 = 011401 and t3.t2nr=t2.fld1 and 1001 = t3.period_; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 const fld1 fld1 4 const 1 -1 SIMPLE t3 const PRIMARY,period PRIMARY 4 const 1 -select fld3,period from t2,t1 where companynr*10 = 37*10; -fld3 period +1 SIMPLE t3 const PRIMARY,period_ PRIMARY 4 const 1 +select fld3,period_ from t2,t1 where companynr*10 = 37*10; +fld3 period_ breaking 9410 Romans 9410 intercepted 9410 @@ -1223,8 +1223,8 @@ dusted 9410 encompasses 9410 presentation 9410 Kantian 9410 -select fld3,period,price,price2 from t2,t3 where t2.fld1=t3.t2nr and period >= 1001 and period <= 1002 and t2.companynr = 37 order by fld3,period, price; -fld3 period price price2 +select fld3,period_,price,price2 from t2,t3 where t2.fld1=t3.t2nr and period_ >= 1001 and period_ <= 1002 and t2.companynr = 37 order by fld3,period_, price; +fld3 period_ price price2 admonishing 1002 28357832 8723648 analyzable 1002 28357832 8723648 annihilates 1001 5987435 234724 @@ -1284,8 +1284,8 @@ ventilate 1001 5987435 234724 wallet 1001 5987435 234724 Weissmuller 1002 28357832 8723648 Wotan 1002 28357832 8723648 -select t2.fld1,fld3,period,price,price2 from t2,t3 where t2.fld1>= 18201 and t2.fld1 <= 18811 and t2.fld1=t3.t2nr and period = 1001 and t2.companynr = 37; -fld1 fld3 period price price2 +select t2.fld1,fld3,period_,price,price2 from t2,t3 where t2.fld1>= 18201 and t2.fld1 <= 18811 and t2.fld1=t3.t2nr and period_ = 1001 and t2.companynr = 37; +fld1 fld3 period_ price price2 018201 relaxing 1001 5987435 234724 018601 vacuuming 1001 5987435 234724 018801 inch 1001 5987435 234724 @@ -1325,7 +1325,7 @@ companynr companyname 65 company 9 68 company 10 select * from t1,t1 t12; -Period Varor_period Period Varor_period +Period_ Varor_period Period_ Varor_period 9410 9412 9410 9412 select t2.fld1,t22.fld1 from t2,t2 t22 where t2.fld1 >= 250501 and t2.fld1 <= 250505 and t22.fld1 >= 250501 and t22.fld1 <= 250505; fld1 fld1 @@ -1440,23 +1440,23 @@ explain select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr= id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t4 index NULL PRIMARY 1 NULL 12 Using index; Using temporary 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where; Using join buffer (flat, BNL join) -select t2.fld1,t2.companynr,fld3,period from t3,t2 where t2.fld1 = 38208 and t2.fld1=t3.t2nr and period = 1008 or t2.fld1 = 38008 and t2.fld1 =t3.t2nr and period = 1008; -fld1 companynr fld3 period +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where t2.fld1 = 38208 and t2.fld1=t3.t2nr and period_ = 1008 or t2.fld1 = 38008 and t2.fld1 =t3.t2nr and period_ = 1008; +fld1 companynr fld3 period_ 038008 37 reporters 1008 038208 37 Selfridge 1008 -select t2.fld1,t2.companynr,fld3,period from t3,t2 where (t2.fld1 = 38208 or t2.fld1 = 38008) and t2.fld1=t3.t2nr and period>=1008 and period<=1009; -fld1 companynr fld3 period +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where (t2.fld1 = 38208 or t2.fld1 = 38008) and t2.fld1=t3.t2nr and period_>=1008 and period_<=1009; +fld1 companynr fld3 period_ 038008 37 reporters 1008 038208 37 Selfridge 1008 -select t2.fld1,t2.companynr,fld3,period from t3,t2 where (t3.t2nr = 38208 or t3.t2nr = 38008) and t2.fld1=t3.t2nr and period>=1008 and period<=1009; -fld1 companynr fld3 period +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where (t3.t2nr = 38208 or t3.t2nr = 38008) and t2.fld1=t3.t2nr and period_>=1008 and period_<=1009; +fld1 companynr fld3 period_ 038008 37 reporters 1008 038208 37 Selfridge 1008 -select period from t1 where (((period > 0) or period < 10000 or (period = 1900)) and (period=1900 and period <= 1901) or (period=1903 and (period=1903)) and period>=1902) or ((period=1904 or period=1905) or (period=1906 or period>1907)) or (period=1908 and period = 1909); -period +select period_ from t1 where (((period_ > 0) or period_ < 10000 or (period_ = 1900)) and (period_=1900 and period_ <= 1901) or (period_=1903 and (period_=1903)) and period_>=1902) or ((period_=1904 or period_=1905) or (period_=1906 or period_>1907)) or (period_=1908 and period_ = 1909); +period_ 9410 -select period from t1 where ((period > 0 and period < 1) or (((period > 0 and period < 100) and (period > 10)) or (period > 10)) or (period > 0 and (period > 5 or period > 6))); -period +select period_ from t1 where ((period_ > 0 and period_ < 1) or (((period_ > 0 and period_ < 100) and (period_ > 10)) or (period_ > 10)) or (period_ > 0 and (period_ > 5 or period_ > 6))); +period_ 9410 select a.fld1 from t2 as a,t2 b where ((a.fld1 = 250501 and a.fld1=b.fld1) or a.fld1=250502 or a.fld1=250503 or (a.fld1=250505 and a.fld1<=b.fld1 and b.fld1>=a.fld1)) and a.fld1=b.fld1; fld1 @@ -1713,8 +1713,8 @@ companynr companyname count(*) select t2.fld1,count(*) from t2,t3 where t2.fld1=158402 and t3.name=t2.fld3 group by t3.name; fld1 count(*) 158402 4181 -select sum(Period)/count(*) from t1; -sum(Period)/count(*) +select sum(Period_)/count(*) from t1; +sum(Period_)/count(*) 9410.0000 select companynr,count(price) as "count",sum(price) as "sum" ,abs(sum(price)/count(price)-avg(price)) as "diff",(0+count(price))*companynr as func from t3 group by companynr; companynr count sum diff func @@ -2044,26 +2044,26 @@ t2nr count(*) select max(t2nr) from t3 where price=983543950; max(t2nr) 41807 -select t1.period from t3 = t1 limit 1; -period +select t1.period_ from t3 = t1 limit 1; +period_ 1001 -select t1.period from t1 as t1 limit 1; -period +select t1.period_ from t1 as t1 limit 1; +period_ 9410 -select t1.period as "Nuvarande period" from t1 as t1 limit 1; -Nuvarande period +select t1.period_ as "Nuvarande period_" from t1 as t1 limit 1; +Nuvarande period_ 9410 -select period as ok_period from t1 limit 1; +select period_ as ok_period from t1 limit 1; ok_period 9410 -select period as ok_period from t1 group by ok_period limit 1; +select period_ as ok_period from t1 group by ok_period limit 1; ok_period 9410 select 1+1 as summa from t1 group by summa limit 1; summa 2 -select period as "Nuvarande period" from t1 group by "Nuvarande period" limit 1; -Nuvarande period +select period_ as "Nuvarande period_" from t1 group by "Nuvarande period_" limit 1; +Nuvarande period_ 9410 show tables; Tables_in_test diff --git a/mysql-test/r/update.result b/mysql-test/r/update.result index 73ebb73e313..cab57d4ef3d 100644 --- a/mysql-test/r/update.result +++ b/mysql-test/r/update.result @@ -719,3 +719,103 @@ Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 drop table t1, t2; # End of MariaDB 10.0 tests +# +# System Versioning Support +# +# +CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; +INSERT INTO t1(x, y) VALUES +(1, 1000), +(2, 2000), +(3, 3000), +(4, 4000), +(5, 5000), +(6, 6000), +(7, 7000), +(8, 8000), +(9, 9000); +SELECT x, y FROM t1; +x y +1 1000 +2 2000 +3 3000 +4 4000 +5 5000 +6 6000 +7 7000 +8 8000 +9 9000 +UPDATE t1 SET y = y + 1 WHERE x > 7; +SELECT x, y FROM t1; +x y +1 1000 +2 2000 +3 3000 +4 4000 +5 5000 +6 6000 +7 7000 +8 8001 +9 9001 +SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; +x y +1 1000 +2 2000 +3 3000 +4 4000 +5 5000 +6 6000 +7 7000 +8 8001 +9 9001 +8 8000 +9 9000 +DROP TABLE t1; +CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; +INSERT INTO t1(x, y) VALUES +(1, 1000), +(2, 2000), +(3, 3000), +(4, 4000), +(5, 5000), +(6, 6000), +(7, 7000), +(8, 8000), +(9, 9000); +SELECT x, y FROM t1; +x y +1 1000 +2 2000 +3 3000 +4 4000 +5 5000 +6 6000 +7 7000 +8 8000 +9 9000 +UPDATE t1 SET y = y + 1 WHERE x > 7; +SELECT x, y FROM t1; +x y +1 1000 +2 2000 +3 3000 +4 4000 +5 5000 +6 6000 +7 7000 +8 8001 +9 9001 +SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; +x y +1 1000 +2 2000 +3 3000 +4 4000 +5 5000 +6 6000 +7 7000 +8 8001 +9 9001 +8 8000 +9 9000 +DROP TABLE t1; diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index 676432690b4..944e8c1392e 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -1577,171 +1577,6 @@ t1 CREATE TABLE `t1` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; End of 5.1 tests - -# -# Bug#34828: OF is taken as OFF and a value of 0 is set for variable SQL_notes. -# - -# Checking sql_notes... -SET @sql_notes_saved = @@sql_notes; - -SET @@sql_notes = ON; -SELECT @@sql_notes; -@@sql_notes -1 - -SET @@sql_notes = OF; -ERROR 42000: Variable 'sql_notes' can't be set to the value of 'OF' -SELECT @@sql_notes; -@@sql_notes -1 - -SET @@sql_notes = OFF; -SELECT @@sql_notes; -@@sql_notes -0 - -SET @@sql_notes = @sql_notes_saved; - -# Checking delay_key_write... -SET @delay_key_write_saved = @@delay_key_write; - -SET GLOBAL delay_key_write = ON; -SELECT @@delay_key_write; -@@delay_key_write -ON - -SET GLOBAL delay_key_write = OF; -ERROR 42000: Variable 'delay_key_write' can't be set to the value of 'OF' -SELECT @@delay_key_write; -@@delay_key_write -ON - -SET GLOBAL delay_key_write = AL; -ERROR 42000: Variable 'delay_key_write' can't be set to the value of 'AL' -SELECT @@delay_key_write; -@@delay_key_write -ON - -SET GLOBAL delay_key_write = OFF; -SELECT @@delay_key_write; -@@delay_key_write -OFF - -SET GLOBAL delay_key_write = ALL; -SELECT @@delay_key_write; -@@delay_key_write -ALL - -SET GLOBAL delay_key_write = @delay_key_write_saved; - -# Checking sql_safe_updates... -SET @sql_safe_updates_saved = @@sql_safe_updates; - -SET @@sql_safe_updates = ON; -SELECT @@sql_safe_updates; -@@sql_safe_updates -1 - -SET @@sql_safe_updates = OF; -ERROR 42000: Variable 'sql_safe_updates' can't be set to the value of 'OF' -SELECT @@sql_safe_updates; -@@sql_safe_updates -1 - -SET @@sql_safe_updates = OFF; -SELECT @@sql_safe_updates; -@@sql_safe_updates -0 - -SET @@sql_safe_updates = @sql_safe_updates_saved; - -# Checking foreign_key_checks... -SET @foreign_key_checks_saved = @@foreign_key_checks; - -SET @@foreign_key_checks = ON; -SELECT @@foreign_key_checks; -@@foreign_key_checks -1 - -SET @@foreign_key_checks = OF; -ERROR 42000: Variable 'foreign_key_checks' can't be set to the value of 'OF' -SELECT @@foreign_key_checks; -@@foreign_key_checks -1 - -SET @@foreign_key_checks = OFF; -SELECT @@foreign_key_checks; -@@foreign_key_checks -0 - -SET @@foreign_key_checks = @foreign_key_checks_saved; - -# Checking unique_checks... -SET @unique_checks_saved = @@unique_checks; - -SET @@unique_checks = ON; -SELECT @@unique_checks; -@@unique_checks -1 - -SET @@unique_checks = OF; -ERROR 42000: Variable 'unique_checks' can't be set to the value of 'OF' -SELECT @@unique_checks; -@@unique_checks -1 - -SET @@unique_checks = OFF; -SELECT @@unique_checks; -@@unique_checks -0 - -SET @@unique_checks = @unique_checks_saved; - -# Checking sql_buffer_result... -SET @sql_buffer_result_saved = @@sql_buffer_result; - -SET @@sql_buffer_result = ON; -SELECT @@sql_buffer_result; -@@sql_buffer_result -1 - -SET @@sql_buffer_result = OF; -ERROR 42000: Variable 'sql_buffer_result' can't be set to the value of 'OF' -SELECT @@sql_buffer_result; -@@sql_buffer_result -1 - -SET @@sql_buffer_result = OFF; -SELECT @@sql_buffer_result; -@@sql_buffer_result -0 - -SET @@sql_buffer_result = @sql_buffer_result_saved; - -# Checking sql_quote_show_create... -SET @sql_quote_show_create_saved = @@sql_quote_show_create; - -SET @@sql_quote_show_create = ON; -SELECT @@sql_quote_show_create; -@@sql_quote_show_create -1 - -SET @@sql_quote_show_create = OF; -ERROR 42000: Variable 'sql_quote_show_create' can't be set to the value of 'OF' -SELECT @@sql_quote_show_create; -@@sql_quote_show_create -1 - -SET @@sql_quote_show_create = OFF; -SELECT @@sql_quote_show_create; -@@sql_quote_show_create -0 - -SET @@sql_quote_show_create = @sql_quote_show_create_saved; - -# End of Bug#34828. - # Make sure we can manipulate with autocommit in the # along with other variables. drop table if exists t1; diff --git a/mysql-test/suite/archive/archive.result b/mysql-test/suite/archive/archive.result index d294d3dfe58..f0ef14495fa 100644 --- a/mysql-test/suite/archive/archive.result +++ b/mysql-test/suite/archive/archive.result @@ -3,18 +3,18 @@ call mtr.add_suppression("Table 't1' is marked as crashed and should be repaired DROP TABLE if exists t1,t2,t3,t4,t5,t6; SET storage_engine=ARCHIVE; CREATE TABLE t1 ( -Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, +Period_ smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL ) ENGINE=archive; INSERT INTO t1 VALUES (9410,9412); -select period FROM t1; -period +select period_ FROM t1; +period_ 9410 select * FROM t1; -Period Varor_period +Period_ Varor_period 9410 9412 select t1.* FROM t1; -Period Varor_period +Period_ Varor_period 9410 9412 CREATE TABLE t2 ( auto int, diff --git a/mysql-test/suite/archive/archive.test b/mysql-test/suite/archive/archive.test index 30f2766507e..19b46195682 100644 --- a/mysql-test/suite/archive/archive.test +++ b/mysql-test/suite/archive/archive.test @@ -15,13 +15,13 @@ SET storage_engine=ARCHIVE; let $MYSQLD_DATADIR= `SELECT @@datadir`; CREATE TABLE t1 ( - Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, + Period_ smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL ) ENGINE=archive; INSERT INTO t1 VALUES (9410,9412); -select period FROM t1; +select period_ FROM t1; select * FROM t1; select t1.* FROM t1; diff --git a/mysql-test/suite/binlog/r/binlog_stm_blackhole.result b/mysql-test/suite/binlog/r/binlog_stm_blackhole.result index feed949a71a..ac2b2003f30 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_blackhole.result +++ b/mysql-test/suite/binlog/r/binlog_stm_blackhole.result @@ -1,16 +1,16 @@ CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); drop table if exists t1,t2; CREATE TABLE t1 ( -Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, +Period_ smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL ) ENGINE=blackhole; INSERT INTO t1 VALUES (9410,9412); -select period from t1; -period +select period_ from t1; +period_ select * from t1; -Period Varor_period +Period_ Varor_period select t1.* from t1; -Period Varor_period +Period_ Varor_period CREATE TABLE t2 ( auto int NOT NULL auto_increment, fld1 int(6) unsigned zerofill DEFAULT '000000' NOT NULL, diff --git a/mysql-test/suite/csv/csv.result b/mysql-test/suite/csv/csv.result index 220b84b222e..c9f7c617b40 100644 --- a/mysql-test/suite/csv/csv.result +++ b/mysql-test/suite/csv/csv.result @@ -3,18 +3,18 @@ call mtr.add_suppression("Table 'test_repair_table4' is marked as crashed and sh call mtr.add_suppression("Table 't1' is marked as crashed and should be repaired"); drop table if exists t1,t2,t3,t4; CREATE TABLE t1 ( -Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, +Period_ smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL ) ENGINE = CSV; INSERT INTO t1 VALUES (9410,9412); -select period from t1; -period +select period_ from t1; +period_ 9410 select * from t1; -Period Varor_period +Period_ Varor_period 9410 9412 select t1.* from t1; -Period Varor_period +Period_ Varor_period 9410 9412 CREATE TABLE t2 ( auto int not null, @@ -4919,12 +4919,12 @@ DROP TABLE t1; ALTER TABLE t2 RENAME t1; DROP TABLE t1; CREATE TABLE t1 ( -Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, +Period_ smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL ) ENGINE = CSV; INSERT INTO t1 VALUES (9410,9412); -select period from t1; -period +select period_ from t1; +period_ 9410 drop table if exists t1,t2,t3,t4; Warnings: diff --git a/mysql-test/suite/csv/csv.test b/mysql-test/suite/csv/csv.test index 3da9aca7b16..711351a32ae 100644 --- a/mysql-test/suite/csv/csv.test +++ b/mysql-test/suite/csv/csv.test @@ -17,13 +17,13 @@ drop table if exists t1,t2,t3,t4; --enable_warnings CREATE TABLE t1 ( - Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, + Period_ smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL ) ENGINE = CSV; INSERT INTO t1 VALUES (9410,9412); -select period from t1; +select period_ from t1; select * from t1; select t1.* from t1; @@ -1308,13 +1308,13 @@ ALTER TABLE t2 RENAME t1; DROP TABLE t1; CREATE TABLE t1 ( - Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, + Period_ smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL ) ENGINE = CSV; INSERT INTO t1 VALUES (9410,9412); -select period from t1; +select period_ from t1; drop table if exists t1,t2,t3,t4; diff --git a/mysql-test/suite/funcs_1/r/innodb_views.result b/mysql-test/suite/funcs_1/r/innodb_views.result index 294e0695226..759ab6fd327 100644 --- a/mysql-test/suite/funcs_1/r/innodb_views.result +++ b/mysql-test/suite/funcs_1/r/innodb_views.result @@ -3551,11 +3551,11 @@ CREATE VIEW v1 or REPLACE AS Select * from tb2 my_table; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'or REPLACE AS Select * from tb2 my_table' at line 1 CREATE VIEW v1 WITH CASCADED CHECK OPTION AS Select * from tb2 my_table limit 50; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CASCADED CHECK OPTION AS Select * +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WITH CASCADED CHECK OPTION AS Select * from tb2 my_table limit 50' at line 1 CREATE VIEW v1 WITH LOCAL CHECK OPTION AS Select * from tb2 my_table limit 50; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'LOCAL CHECK OPTION AS Select * +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WITH LOCAL CHECK OPTION AS Select * from tb2 my_table limit 50' at line 1 SELECT * FROM tb2 my_table CREATE VIEW As v1; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CREATE VIEW As v1' at line 1 @@ -3585,7 +3585,7 @@ FROM test.tb2 my_table CHECK OPTION WITH CASCADED; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CHECK OPTION WITH CASCADED' at line 2 CREATE OR REPLACE VIEW v1 WITH CASCADED CHECK OPTION AS SELECT F59, F60 FROM test.tb2 my_table; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CASCADED CHECK OPTION +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WITH CASCADED CHECK OPTION AS SELECT F59, F60 FROM test.tb2 my_table' at line 1 CREATE OR REPLACE AS SELECT F59, F60 FROM test.tb2 my_table VIEW v1 WITH CASCADED CHECK OPTION; @@ -3614,7 +3614,7 @@ FROM test.tb2 my_table CHECK OPTION WITH LOCAL; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CHECK OPTION WITH LOCAL' at line 2 CREATE OR REPLACE VIEW v1 WITH CASCADED CHECK OPTION AS SELECT F59, F60 FROM test.tb2 my_table; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CASCADED CHECK OPTION +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WITH CASCADED CHECK OPTION AS SELECT F59, F60 FROM test.tb2 my_table' at line 1 CREATE OR REPLACE AS SELECT F59, F60 FROM test.tb2 my_table VIEW v1 WITH LOCAL CHECK OPTION; diff --git a/mysql-test/suite/funcs_1/r/memory_views.result b/mysql-test/suite/funcs_1/r/memory_views.result index 87465035980..60a9d2a3f2e 100644 --- a/mysql-test/suite/funcs_1/r/memory_views.result +++ b/mysql-test/suite/funcs_1/r/memory_views.result @@ -3552,11 +3552,11 @@ CREATE VIEW v1 or REPLACE AS Select * from tb2 my_table; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'or REPLACE AS Select * from tb2 my_table' at line 1 CREATE VIEW v1 WITH CASCADED CHECK OPTION AS Select * from tb2 my_table limit 50; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CASCADED CHECK OPTION AS Select * +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WITH CASCADED CHECK OPTION AS Select * from tb2 my_table limit 50' at line 1 CREATE VIEW v1 WITH LOCAL CHECK OPTION AS Select * from tb2 my_table limit 50; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'LOCAL CHECK OPTION AS Select * +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WITH LOCAL CHECK OPTION AS Select * from tb2 my_table limit 50' at line 1 SELECT * FROM tb2 my_table CREATE VIEW As v1; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CREATE VIEW As v1' at line 1 @@ -3586,7 +3586,7 @@ FROM test.tb2 my_table CHECK OPTION WITH CASCADED; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CHECK OPTION WITH CASCADED' at line 2 CREATE OR REPLACE VIEW v1 WITH CASCADED CHECK OPTION AS SELECT F59, F60 FROM test.tb2 my_table; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CASCADED CHECK OPTION +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WITH CASCADED CHECK OPTION AS SELECT F59, F60 FROM test.tb2 my_table' at line 1 CREATE OR REPLACE AS SELECT F59, F60 FROM test.tb2 my_table VIEW v1 WITH CASCADED CHECK OPTION; @@ -3615,7 +3615,7 @@ FROM test.tb2 my_table CHECK OPTION WITH LOCAL; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CHECK OPTION WITH LOCAL' at line 2 CREATE OR REPLACE VIEW v1 WITH CASCADED CHECK OPTION AS SELECT F59, F60 FROM test.tb2 my_table; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CASCADED CHECK OPTION +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WITH CASCADED CHECK OPTION AS SELECT F59, F60 FROM test.tb2 my_table' at line 1 CREATE OR REPLACE AS SELECT F59, F60 FROM test.tb2 my_table VIEW v1 WITH LOCAL CHECK OPTION; diff --git a/mysql-test/suite/funcs_1/r/myisam_views-big.result b/mysql-test/suite/funcs_1/r/myisam_views-big.result index 9296b9d98a2..420a400905b 100644 --- a/mysql-test/suite/funcs_1/r/myisam_views-big.result +++ b/mysql-test/suite/funcs_1/r/myisam_views-big.result @@ -4054,11 +4054,11 @@ CREATE VIEW v1 or REPLACE AS Select * from tb2 my_table; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'or REPLACE AS Select * from tb2 my_table' at line 1 CREATE VIEW v1 WITH CASCADED CHECK OPTION AS Select * from tb2 my_table limit 50; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CASCADED CHECK OPTION AS Select * +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WITH CASCADED CHECK OPTION AS Select * from tb2 my_table limit 50' at line 1 CREATE VIEW v1 WITH LOCAL CHECK OPTION AS Select * from tb2 my_table limit 50; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'LOCAL CHECK OPTION AS Select * +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WITH LOCAL CHECK OPTION AS Select * from tb2 my_table limit 50' at line 1 SELECT * FROM tb2 my_table CREATE VIEW As v1; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CREATE VIEW As v1' at line 1 @@ -4088,7 +4088,7 @@ FROM test.tb2 my_table CHECK OPTION WITH CASCADED; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CHECK OPTION WITH CASCADED' at line 2 CREATE OR REPLACE VIEW v1 WITH CASCADED CHECK OPTION AS SELECT F59, F60 FROM test.tb2 my_table; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CASCADED CHECK OPTION +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WITH CASCADED CHECK OPTION AS SELECT F59, F60 FROM test.tb2 my_table' at line 1 CREATE OR REPLACE AS SELECT F59, F60 FROM test.tb2 my_table VIEW v1 WITH CASCADED CHECK OPTION; @@ -4117,7 +4117,7 @@ FROM test.tb2 my_table CHECK OPTION WITH LOCAL; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CHECK OPTION WITH LOCAL' at line 2 CREATE OR REPLACE VIEW v1 WITH CASCADED CHECK OPTION AS SELECT F59, F60 FROM test.tb2 my_table; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CASCADED CHECK OPTION +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WITH CASCADED CHECK OPTION AS SELECT F59, F60 FROM test.tb2 my_table' at line 1 CREATE OR REPLACE AS SELECT F59, F60 FROM test.tb2 my_table VIEW v1 WITH LOCAL CHECK OPTION; diff --git a/mysql-test/suite/funcs_1/r/storedproc.result b/mysql-test/suite/funcs_1/r/storedproc.result index 2c86e6c3e73..29d3b23211b 100644 --- a/mysql-test/suite/funcs_1/r/storedproc.result +++ b/mysql-test/suite/funcs_1/r/storedproc.result @@ -2807,7 +2807,7 @@ ERROR 42000: You have an error in your SQL syntax; check the manual that corresp SELECT * from t1 where f2=f1' at line 1 CREATE PROCEDURE with() SELECT * from t1 where f2=f1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '() +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'with() SELECT * from t1 where f2=f1' at line 1 CREATE PROCEDURE write() SELECT * from t1 where f2=f1; @@ -9222,7 +9222,7 @@ CREATE PROCEDURE sp1() BEGIN declare with char; END// -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'char; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'with char; END' at line 3 DROP PROCEDURE IF EXISTS sp1; Warnings: @@ -11574,9 +11574,8 @@ BEGIN declare with condition for sqlstate '02000'; declare exit handler for with set @var2 = 1; END// -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'condition for sqlstate '02000'; -declare exit handler for with set @var2 = 1; -END' at line 3 +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'with condition for sqlstate '02000'; +declare exit handler for with set @var2 = 1' at line 3 DROP PROCEDURE IF EXISTS sp1; Warnings: Note 1305 PROCEDURE db_storedproc.sp1 does not exist @@ -13680,7 +13679,7 @@ CREATE PROCEDURE sp1( ) BEGIN declare with handler for sqlstate '02000' set @var2 = 1; END// -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'handler for sqlstate '02000' set @var2 = 1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'with handler for sqlstate '02000' set @var2 = 1; END' at line 3 DROP PROCEDURE IF EXISTS sp1; Warnings: diff --git a/mysql-test/suite/innodb_fts/r/fulltext.result b/mysql-test/suite/innodb_fts/r/fulltext.result index f096f1c7dd5..84822109e2e 100644 --- a/mysql-test/suite/innodb_fts/r/fulltext.result +++ b/mysql-test/suite/innodb_fts/r/fulltext.result @@ -57,7 +57,7 @@ Only MyISAM tables support collections MySQL has now support for full-text search Full-text search in MySQL implements vector space model select * from t1 where MATCH(a,b) AGAINST ("indexes" IN BOOLEAN MODE WITH QUERY EXPANSION); -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'QUERY EXPANSION)' at line 1 +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WITH QUERY EXPANSION)' at line 1 explain select * from t1 where MATCH(a,b) AGAINST ("collections"); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 fulltext a a 0 1 Using where diff --git a/mysql-test/suite/sys_vars/r/delay_key_write_basic.result b/mysql-test/suite/sys_vars/r/delay_key_write_basic.result index 2258d7af078..7299737f63b 100644 --- a/mysql-test/suite/sys_vars/r/delay_key_write_basic.result +++ b/mysql-test/suite/sys_vars/r/delay_key_write_basic.result @@ -37,8 +37,8 @@ SET @@global.delay_key_write = FALSE0; ERROR 42000: Variable 'delay_key_write' can't be set to the value of 'FALSE0' SET @@global.delay_key_write = ONN; ERROR 42000: Variable 'delay_key_write' can't be set to the value of 'ONN' -SET @@global.delay_key_write = OF; -ERROR 42000: Variable 'delay_key_write' can't be set to the value of 'OF' +SET @@global.delay_key_write = OFFF; +ERROR 42000: Variable 'delay_key_write' can't be set to the value of 'OFFF' SET @@global.delay_key_write = ' '; ERROR 42000: Variable 'delay_key_write' can't be set to the value of ' ' SET @@global.delay_key_write = ""; diff --git a/mysql-test/suite/sys_vars/r/foreign_key_checks_basic.result b/mysql-test/suite/sys_vars/r/foreign_key_checks_basic.result index 834d693edb8..f33ef34a62a 100644 --- a/mysql-test/suite/sys_vars/r/foreign_key_checks_basic.result +++ b/mysql-test/suite/sys_vars/r/foreign_key_checks_basic.result @@ -43,8 +43,8 @@ SET @@session.foreign_key_checks = TR ERROR 42000: Variable 'foreign_key_checks' can't be set to the value of 'TRÜE' SET @@session.foreign_key_checks = ÕN; ERROR 42000: Variable 'foreign_key_checks' can't be set to the value of 'ÕN' -SET @@session.foreign_key_checks = OF; -ERROR 42000: Variable 'foreign_key_checks' can't be set to the value of 'OF' +SET @@session.foreign_key_checks = OFFF; +ERROR 42000: Variable 'foreign_key_checks' can't be set to the value of 'OFFF' SET @@session.foreign_key_checks = ÓFF; ERROR 42000: Variable 'foreign_key_checks' can't be set to the value of 'ÓFF' SET @@session.foreign_key_checks = '¹'; diff --git a/mysql-test/suite/sys_vars/r/innodb_support_xa_basic.result b/mysql-test/suite/sys_vars/r/innodb_support_xa_basic.result new file mode 100644 index 00000000000..5c66ff41355 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/innodb_support_xa_basic.result @@ -0,0 +1,227 @@ +SET @session_start_value = @@session.innodb_support_xa; +SELECT @session_start_value; +@session_start_value +1 +SET @global_start_value = @@global.innodb_support_xa; +SELECT @global_start_value; +@global_start_value +1 +'#--------------------FN_DYNVARS_046_01------------------------#' +SET @@session.innodb_support_xa = 0; +Warnings: +Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed. +SET @@session.innodb_support_xa = DEFAULT; +Warnings: +Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. +SELECT @@session.innodb_support_xa; +@@session.innodb_support_xa +1 +SET @@global.innodb_support_xa = 0; +Warnings: +Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed. +SET @@global.innodb_support_xa = DEFAULT; +Warnings: +Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. +SELECT @@global.innodb_support_xa; +@@global.innodb_support_xa +1 +'#---------------------FN_DYNVARS_046_02-------------------------#' +SET innodb_support_xa = 1; +Warnings: +Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. +SELECT @@innodb_support_xa; +@@innodb_support_xa +1 +SELECT session.innodb_support_xa; +ERROR 42S02: Unknown table 'session' in field list +SELECT local.innodb_support_xa; +ERROR 42S02: Unknown table 'local' in field list +SELECT global.innodb_support_xa; +ERROR 42S02: Unknown table 'global' in field list +SET session innodb_support_xa = 0; +Warnings: +Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed. +SELECT @@session.innodb_support_xa; +@@session.innodb_support_xa +1 +SET global innodb_support_xa = 0; +Warnings: +Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed. +SELECT @@global.innodb_support_xa; +@@global.innodb_support_xa +1 +'#--------------------FN_DYNVARS_046_03------------------------#' +SET @@session.innodb_support_xa = 0; +Warnings: +Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed. +SELECT @@session.innodb_support_xa; +@@session.innodb_support_xa +1 +SET @@session.innodb_support_xa = 1; +Warnings: +Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. +SELECT @@session.innodb_support_xa; +@@session.innodb_support_xa +1 +SET @@global.innodb_support_xa = 0; +Warnings: +Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed. +SELECT @@global.innodb_support_xa; +@@global.innodb_support_xa +1 +SET @@global.innodb_support_xa = 1; +Warnings: +Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. +SELECT @@global.innodb_support_xa; +@@global.innodb_support_xa +1 +'#--------------------FN_DYNVARS_046_04-------------------------#' +SET @@session.innodb_support_xa = -0.6; +ERROR 42000: Incorrect argument type to variable 'innodb_support_xa' +SET @@session.innodb_support_xa = 1.6; +ERROR 42000: Incorrect argument type to variable 'innodb_support_xa' +SET @@session.innodb_support_xa = "T"; +ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'T' +SET @@session.innodb_support_xa = "Y"; +ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'Y' +SET @@session.innodb_support_xa = TRÜE; +ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'TRÜE' +SET @@session.innodb_support_xa = ÕN; +ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'ÕN' +SET @@session.innodb_support_xa = OFF; +Warnings: +Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed. +SELECT @@session.innodb_support_xa; +@@session.innodb_support_xa +1 +SET @@session.innodb_support_xa = ÓFF; +ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'ÓFF' +SET @@global.innodb_support_xa = -1; +ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of '-1' +SELECT @@global.innodb_support_xa; +@@global.innodb_support_xa +1 +SET @@global.innodb_support_xa = 2; +ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of '2' +SET @@global.innodb_support_xa = "T"; +ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'T' +SET @@global.innodb_support_xa = "Y"; +ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'Y' +SET @@global.innodb_support_xa = TRÜE; +ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'TRÜE' +SET @@global.innodb_support_xa = ÕN; +ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'ÕN' +SET @@global.innodb_support_xa = OFF; +Warnings: +Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed. +SELECT @@global.innodb_support_xa; +@@global.innodb_support_xa +1 +SET @@global.innodb_support_xa = ÓFF; +ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'ÓFF' +'#-------------------FN_DYNVARS_046_05----------------------------#' +SET @@global.innodb_support_xa = 0; +Warnings: +Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed. +SET @@session.innodb_support_xa = 1; +Warnings: +Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. +SELECT @@global.innodb_support_xa AS res_is_0; +res_is_0 +1 +SET @@global.innodb_support_xa = 0; +Warnings: +Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed. +SELECT @@session.innodb_support_xa AS res_is_1; +res_is_1 +1 +'#----------------------FN_DYNVARS_046_06------------------------#' +SELECT IF(@@global.innodb_support_xa, "ON", "OFF") = +VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_support_xa'; +IF(@@global.innodb_support_xa, "ON", "OFF") = +VARIABLE_VALUE +1 +SELECT @@global.innodb_support_xa; +@@global.innodb_support_xa +1 +SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_support_xa'; +VARIABLE_VALUE +ON +'#----------------------FN_DYNVARS_046_07------------------------#' +SELECT IF(@@session.innodb_support_xa, "ON", "OFF") = +VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_VARIABLES +WHERE VARIABLE_NAME='innodb_support_xa'; +IF(@@session.innodb_support_xa, "ON", "OFF") = +VARIABLE_VALUE +1 +SELECT @@session.innodb_support_xa; +@@session.innodb_support_xa +1 +SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_VARIABLES +WHERE VARIABLE_NAME='innodb_support_xa'; +VARIABLE_VALUE +ON +'#---------------------FN_DYNVARS_046_08-------------------------#' +SET @@session.innodb_support_xa = OFF; +Warnings: +Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed. +SELECT @@session.innodb_support_xa; +@@session.innodb_support_xa +1 +SET @@session.innodb_support_xa = ON; +Warnings: +Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. +SELECT @@session.innodb_support_xa; +@@session.innodb_support_xa +1 +SET @@global.innodb_support_xa = OFF; +Warnings: +Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed. +SELECT @@global.innodb_support_xa; +@@global.innodb_support_xa +1 +SET @@global.innodb_support_xa = ON; +Warnings: +Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. +SELECT @@global.innodb_support_xa; +@@global.innodb_support_xa +1 +'#---------------------FN_DYNVARS_046_09----------------------#' +SET @@session.innodb_support_xa = TRUE; +Warnings: +Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. +SELECT @@session.innodb_support_xa; +@@session.innodb_support_xa +1 +SET @@session.innodb_support_xa = FALSE; +Warnings: +Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed. +SELECT @@session.innodb_support_xa; +@@session.innodb_support_xa +1 +SET @@global.innodb_support_xa = TRUE; +Warnings: +Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. +SELECT @@global.innodb_support_xa; +@@global.innodb_support_xa +1 +SET @@global.innodb_support_xa = FALSE; +Warnings: +Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed. +SELECT @@global.innodb_support_xa; +@@global.innodb_support_xa +1 +SET @@session.innodb_support_xa = @session_start_value; +Warnings: +Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. +SELECT @@session.innodb_support_xa; +@@session.innodb_support_xa +1 +SET @@global.innodb_support_xa = @global_start_value; +Warnings: +Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. +SELECT @@global.innodb_support_xa; +@@global.innodb_support_xa +1 diff --git a/mysql-test/suite/sys_vars/r/innodb_table_locks_basic.result b/mysql-test/suite/sys_vars/r/innodb_table_locks_basic.result index 08dc5d7aaca..aec529aece2 100644 --- a/mysql-test/suite/sys_vars/r/innodb_table_locks_basic.result +++ b/mysql-test/suite/sys_vars/r/innodb_table_locks_basic.result @@ -66,7 +66,7 @@ SET @@session.innodb_table_locks = TR ERROR 42000: Variable 'innodb_table_locks' can't be set to the value of 'TRÜE' SET @@session.innodb_table_locks = ÕN; ERROR 42000: Variable 'innodb_table_locks' can't be set to the value of 'ÕN' -SET @@session.innodb_table_locks = OF; +SET @@session.innodb_table_locks = OFF; SELECT @@session.innodb_table_locks; @@session.innodb_table_locks 0 @@ -84,7 +84,7 @@ SET @@global.innodb_table_locks = TR ERROR 42000: Variable 'innodb_table_locks' can't be set to the value of 'TRÜE' SET @@global.innodb_table_locks = QN; ERROR 42000: Variable 'innodb_table_locks' can't be set to the value of 'QN' -SET @@global.innodb_table_locks = OF; +SET @@global.innodb_table_locks = OFF; SELECT @@global.innodb_table_locks; @@global.innodb_table_locks 0 diff --git a/mysql-test/suite/sys_vars/r/keep_files_on_create_basic.result b/mysql-test/suite/sys_vars/r/keep_files_on_create_basic.result index b7deea88a9c..8e9f7308b73 100644 --- a/mysql-test/suite/sys_vars/r/keep_files_on_create_basic.result +++ b/mysql-test/suite/sys_vars/r/keep_files_on_create_basic.result @@ -101,8 +101,8 @@ SET @@session.keep_files_on_create = ONN; ERROR 42000: Variable 'keep_files_on_create' can't be set to the value of 'ONN' SET @@session.keep_files_on_create = ONF; ERROR 42000: Variable 'keep_files_on_create' can't be set to the value of 'ONF' -SET @@session.keep_files_on_create = OF; -ERROR 42000: Variable 'keep_files_on_create' can't be set to the value of 'OF' +SET @@session.keep_files_on_create = OFFF; +ERROR 42000: Variable 'keep_files_on_create' can't be set to the value of 'OFFF' SET @@session.keep_files_on_create = 'OFN'; ERROR 42000: Variable 'keep_files_on_create' can't be set to the value of 'OFN' SET @@session.keep_files_on_create = -2; diff --git a/mysql-test/suite/sys_vars/r/log_bin_trust_function_creators_basic.result b/mysql-test/suite/sys_vars/r/log_bin_trust_function_creators_basic.result index 7ed1b689f5a..d3d2e97d249 100644 --- a/mysql-test/suite/sys_vars/r/log_bin_trust_function_creators_basic.result +++ b/mysql-test/suite/sys_vars/r/log_bin_trust_function_creators_basic.result @@ -50,8 +50,8 @@ SET @@global.log_bin_trust_function_creators = 'ONN'; ERROR 42000: Variable 'log_bin_trust_function_creators' can't be set to the value of 'ONN' SET @@global.log_bin_trust_function_creators = "OFFF"; ERROR 42000: Variable 'log_bin_trust_function_creators' can't be set to the value of 'OFFF' -SET @@global.log_bin_trust_function_creators = OF; -ERROR 42000: Variable 'log_bin_trust_function_creators' can't be set to the value of 'OF' +SET @@global.log_bin_trust_function_creators = OFFF; +ERROR 42000: Variable 'log_bin_trust_function_creators' can't be set to the value of 'OFFF' SET @@global.log_bin_trust_function_creators = TTRUE; ERROR 42000: Variable 'log_bin_trust_function_creators' can't be set to the value of 'TTRUE' SET @@global.log_bin_trust_function_creators = FELSE; diff --git a/mysql-test/suite/sys_vars/r/low_priority_updates_basic.result b/mysql-test/suite/sys_vars/r/low_priority_updates_basic.result index 633dc274dec..9e514c8cb35 100644 --- a/mysql-test/suite/sys_vars/r/low_priority_updates_basic.result +++ b/mysql-test/suite/sys_vars/r/low_priority_updates_basic.result @@ -101,8 +101,8 @@ SET @@session.low_priority_updates = ONN; ERROR 42000: Variable 'low_priority_updates' can't be set to the value of 'ONN' SET @@session.low_priority_updates = ONF; ERROR 42000: Variable 'low_priority_updates' can't be set to the value of 'ONF' -SET @@session.low_priority_updates = OF; -ERROR 42000: Variable 'low_priority_updates' can't be set to the value of 'OF' +SET @@session.low_priority_updates = OFFF; +ERROR 42000: Variable 'low_priority_updates' can't be set to the value of 'OFFF' SET @@session.low_priority_updates = 'OFN'; ERROR 42000: Variable 'low_priority_updates' can't be set to the value of 'OFN' SET @@session.low_priority_updates = -2; diff --git a/mysql-test/suite/sys_vars/r/old_passwords_basic.result b/mysql-test/suite/sys_vars/r/old_passwords_basic.result index 26d0e79071b..dba84b18b11 100644 --- a/mysql-test/suite/sys_vars/r/old_passwords_basic.result +++ b/mysql-test/suite/sys_vars/r/old_passwords_basic.result @@ -97,8 +97,8 @@ SET @@session.old_passwords = ONN; ERROR 42000: Variable 'old_passwords' can't be set to the value of 'ONN' SET @@session.old_passwords = ONF; ERROR 42000: Variable 'old_passwords' can't be set to the value of 'ONF' -SET @@session.old_passwords = OF; -ERROR 42000: Variable 'old_passwords' can't be set to the value of 'OF' +SET @@session.old_passwords = OFFF; +ERROR 42000: Variable 'old_passwords' can't be set to the value of 'OFFF' SET @@session.old_passwords = 'OFN'; ERROR 42000: Variable 'old_passwords' can't be set to the value of 'OFN' SET @@session.old_passwords = -2; diff --git a/mysql-test/suite/sys_vars/r/optimizer_prune_level_basic.result b/mysql-test/suite/sys_vars/r/optimizer_prune_level_basic.result index 99843f0b93f..c22107292cd 100644 --- a/mysql-test/suite/sys_vars/r/optimizer_prune_level_basic.result +++ b/mysql-test/suite/sys_vars/r/optimizer_prune_level_basic.result @@ -104,7 +104,7 @@ SET @@session.optimizer_prune_level = ONF; ERROR 42000: Incorrect argument type to variable 'optimizer_prune_level' SET @@session.optimizer_prune_level = ON; ERROR 42000: Incorrect argument type to variable 'optimizer_prune_level' -SET @@session.optimizer_prune_level = OF; +SET @@session.optimizer_prune_level = OFFF; ERROR 42000: Incorrect argument type to variable 'optimizer_prune_level' SET @@session.optimizer_prune_level = 'OFN'; ERROR 42000: Incorrect argument type to variable 'optimizer_prune_level' diff --git a/mysql-test/suite/sys_vars/r/pseudo_slave_mode_basic.result b/mysql-test/suite/sys_vars/r/pseudo_slave_mode_basic.result index c98dd338909..cec880bf1d5 100644 --- a/mysql-test/suite/sys_vars/r/pseudo_slave_mode_basic.result +++ b/mysql-test/suite/sys_vars/r/pseudo_slave_mode_basic.result @@ -58,8 +58,8 @@ SET @@session.pseudo_slave_mode = TR ERROR 42000: Variable 'pseudo_slave_mode' can't be set to the value of 'TRÜE' SET @@session.pseudo_slave_mode = ÕN; ERROR 42000: Variable 'pseudo_slave_mode' can't be set to the value of 'ÕN' -SET @@session.pseudo_slave_mode = OF; -ERROR 42000: Variable 'pseudo_slave_mode' can't be set to the value of 'OF' +SET @@session.pseudo_slave_mode = OFFF; +ERROR 42000: Variable 'pseudo_slave_mode' can't be set to the value of 'OFFF' SET @@session.pseudo_slave_mode = ÓFF; ERROR 42000: Variable 'pseudo_slave_mode' can't be set to the value of 'ÓFF' SET @@session.pseudo_slave_mode = '¹'; diff --git a/mysql-test/suite/sys_vars/r/query_cache_wlock_invalidate_basic.result b/mysql-test/suite/sys_vars/r/query_cache_wlock_invalidate_basic.result index 96f42bbbda3..26169b4b979 100644 --- a/mysql-test/suite/sys_vars/r/query_cache_wlock_invalidate_basic.result +++ b/mysql-test/suite/sys_vars/r/query_cache_wlock_invalidate_basic.result @@ -66,8 +66,8 @@ SET @@session.query_cache_wlock_invalidate = TR ERROR 42000: Variable 'query_cache_wlock_invalidate' can't be set to the value of 'TRÜE' SET @@session.query_cache_wlock_invalidate = ÕN; ERROR 42000: Variable 'query_cache_wlock_invalidate' can't be set to the value of 'ÕN' -SET @@session.query_cache_wlock_invalidate = OF; -ERROR 42000: Variable 'query_cache_wlock_invalidate' can't be set to the value of 'OF' +SET @@session.query_cache_wlock_invalidate = OFFF; +ERROR 42000: Variable 'query_cache_wlock_invalidate' can't be set to the value of 'OFFF' SET @@session.query_cache_wlock_invalidate = ÓFF; ERROR 42000: Variable 'query_cache_wlock_invalidate' can't be set to the value of 'ÓFF' SET @@global.query_cache_wlock_invalidate = -1; @@ -82,8 +82,8 @@ SET @@global.query_cache_wlock_invalidate = TR ERROR 42000: Variable 'query_cache_wlock_invalidate' can't be set to the value of 'TRÜE' SET @@global.query_cache_wlock_invalidate = ÕN; ERROR 42000: Variable 'query_cache_wlock_invalidate' can't be set to the value of 'ÕN' -SET @@global.query_cache_wlock_invalidate = OF; -ERROR 42000: Variable 'query_cache_wlock_invalidate' can't be set to the value of 'OF' +SET @@global.query_cache_wlock_invalidate = OFFF; +ERROR 42000: Variable 'query_cache_wlock_invalidate' can't be set to the value of 'OFFF' SET @@global.query_cache_wlock_invalidate = ÓFF; ERROR 42000: Variable 'query_cache_wlock_invalidate' can't be set to the value of 'ÓFF' '#-------------------FN_DYNVARS_135_05----------------------------#' diff --git a/mysql-test/suite/sys_vars/r/sql_big_selects_basic.result b/mysql-test/suite/sys_vars/r/sql_big_selects_basic.result index 98f05bda488..fc16ecc06f2 100644 --- a/mysql-test/suite/sys_vars/r/sql_big_selects_basic.result +++ b/mysql-test/suite/sys_vars/r/sql_big_selects_basic.result @@ -43,8 +43,8 @@ SET @@session.sql_big_selects = TR ERROR 42000: Variable 'sql_big_selects' can't be set to the value of 'TRÜE' SET @@session.sql_big_selects = ÕN; ERROR 42000: Variable 'sql_big_selects' can't be set to the value of 'ÕN' -SET @@session.sql_big_selects = OF; -ERROR 42000: Variable 'sql_big_selects' can't be set to the value of 'OF' +SET @@session.sql_big_selects = OFFF; +ERROR 42000: Variable 'sql_big_selects' can't be set to the value of 'OFFF' SET @@session.sql_big_selects = ÓFF; ERROR 42000: Variable 'sql_big_selects' can't be set to the value of 'ÓFF' SET @@session.sql_big_selects = '¹'; diff --git a/mysql-test/suite/sys_vars/r/sql_big_tables_basic.result b/mysql-test/suite/sys_vars/r/sql_big_tables_basic.result index 09553ae7d57..91081a78328 100644 --- a/mysql-test/suite/sys_vars/r/sql_big_tables_basic.result +++ b/mysql-test/suite/sys_vars/r/sql_big_tables_basic.result @@ -48,7 +48,7 @@ SET @@session.sql_big_tables = TR ERROR 42000: Variable 'sql_big_tables' can't be set to the value of 'TRÜE' SET @@session.sql_big_tables = ÕN; ERROR 42000: Variable 'sql_big_tables' can't be set to the value of 'ÕN' -SET @@session.sql_big_tables = OF; +SET @@session.sql_big_tables = OFFF; ERROR 42000: Variable 'sql_big_tables' can't be set to the value of 'OF' SET @@session.sql_big_tables = ÓFF; ERROR 42000: Variable 'sql_big_tables' can't be set to the value of 'ÓFF' diff --git a/mysql-test/suite/sys_vars/r/sql_buffer_result_basic.result b/mysql-test/suite/sys_vars/r/sql_buffer_result_basic.result index 2dfdcb26898..83597ef47cb 100644 --- a/mysql-test/suite/sys_vars/r/sql_buffer_result_basic.result +++ b/mysql-test/suite/sys_vars/r/sql_buffer_result_basic.result @@ -48,8 +48,8 @@ SET @@session.sql_buffer_result = TR ERROR 42000: Variable 'sql_buffer_result' can't be set to the value of 'TRÜE' SET @@session.sql_buffer_result = ÕN; ERROR 42000: Variable 'sql_buffer_result' can't be set to the value of 'ÕN' -SET @@session.sql_buffer_result = OF; -ERROR 42000: Variable 'sql_buffer_result' can't be set to the value of 'OF' +SET @@session.sql_buffer_result = OFFF; +ERROR 42000: Variable 'sql_buffer_result' can't be set to the value of 'OFFF' SET @@session.sql_buffer_result = ÓFF; ERROR 42000: Variable 'sql_buffer_result' can't be set to the value of 'ÓFF' SET @@session.sql_buffer_result = '¹'; diff --git a/mysql-test/suite/sys_vars/r/sql_log_bin_basic.result b/mysql-test/suite/sys_vars/r/sql_log_bin_basic.result index 909c434340c..a909019fc50 100644 --- a/mysql-test/suite/sys_vars/r/sql_log_bin_basic.result +++ b/mysql-test/suite/sys_vars/r/sql_log_bin_basic.result @@ -48,8 +48,8 @@ SET @@session.sql_log_bin = TR ERROR 42000: Variable 'sql_log_bin' can't be set to the value of 'TRÜE' SET @@session.sql_log_bin = ÕN; ERROR 42000: Variable 'sql_log_bin' can't be set to the value of 'ÕN' -SET @@session.sql_log_bin = OF; -ERROR 42000: Variable 'sql_log_bin' can't be set to the value of 'OF' +SET @@session.sql_log_bin = OFFF; +ERROR 42000: Variable 'sql_log_bin' can't be set to the value of 'OFFF' SET @@session.sql_log_bin = ÓFF; ERROR 42000: Variable 'sql_log_bin' can't be set to the value of 'ÓFF' SET @@session.sql_log_bin = '¹'; diff --git a/mysql-test/suite/sys_vars/r/sql_log_off_basic.result b/mysql-test/suite/sys_vars/r/sql_log_off_basic.result index c2ffa17c5fe..0cb5b576127 100644 --- a/mysql-test/suite/sys_vars/r/sql_log_off_basic.result +++ b/mysql-test/suite/sys_vars/r/sql_log_off_basic.result @@ -48,8 +48,8 @@ SET @@session.sql_log_off = TR ERROR 42000: Variable 'sql_log_off' can't be set to the value of 'TRÜE' SET @@session.sql_log_off = ÕN; ERROR 42000: Variable 'sql_log_off' can't be set to the value of 'ÕN' -SET @@session.sql_log_off = OF; -ERROR 42000: Variable 'sql_log_off' can't be set to the value of 'OF' +SET @@session.sql_log_off = OFFF; +ERROR 42000: Variable 'sql_log_off' can't be set to the value of 'OFFF' SET @@session.sql_log_off = ÓFF; ERROR 42000: Variable 'sql_log_off' can't be set to the value of 'ÓFF' SET @@session.sql_log_off = '¹'; diff --git a/mysql-test/suite/sys_vars/r/sql_low_priority_updates_basic.result b/mysql-test/suite/sys_vars/r/sql_low_priority_updates_basic.result index 28bc53e5718..ed493e038ca 100644 --- a/mysql-test/suite/sys_vars/r/sql_low_priority_updates_basic.result +++ b/mysql-test/suite/sys_vars/r/sql_low_priority_updates_basic.result @@ -63,7 +63,7 @@ SET @@session.sql_low_priority_updates = TR ERROR 42000: Variable 'sql_low_priority_updates' can't be set to the value of 'TRÜE' SET @@session.sql_low_priority_updates = ÕN; ERROR 42000: Variable 'sql_low_priority_updates' can't be set to the value of 'ÕN' -SET @@session.sql_low_priority_updates = OF; +SET @@session.sql_low_priority_updates = OFFF; ERROR 42000: Variable 'sql_low_priority_updates' can't be set to the value of 'OF' SET @@session.sql_low_priority_updates = ÓFF; ERROR 42000: Variable 'sql_low_priority_updates' can't be set to the value of 'ÓFF' @@ -79,7 +79,7 @@ SET @@global.sql_low_priority_updates = TR ERROR 42000: Variable 'sql_low_priority_updates' can't be set to the value of 'TRÜE' SET @@global.sql_low_priority_updates = ÕN; ERROR 42000: Variable 'sql_low_priority_updates' can't be set to the value of 'ÕN' -SET @@global.sql_low_priority_updates = OF; +SET @@global.sql_low_priority_updates = OFFF; ERROR 42000: Variable 'sql_low_priority_updates' can't be set to the value of 'OF' SET @@global.sql_low_priority_updates = ÓFF; ERROR 42000: Variable 'sql_low_priority_updates' can't be set to the value of 'ÓFF' diff --git a/mysql-test/suite/sys_vars/r/sql_notes_basic.result b/mysql-test/suite/sys_vars/r/sql_notes_basic.result index 7a54f90f8b7..18a846874ab 100644 --- a/mysql-test/suite/sys_vars/r/sql_notes_basic.result +++ b/mysql-test/suite/sys_vars/r/sql_notes_basic.result @@ -48,8 +48,8 @@ SET @@session.sql_notes = TR ERROR 42000: Variable 'sql_notes' can't be set to the value of 'TRÜE' SET @@session.sql_notes = ÕN; ERROR 42000: Variable 'sql_notes' can't be set to the value of 'ÕN' -SET @@session.sql_notes = OF; -ERROR 42000: Variable 'sql_notes' can't be set to the value of 'OF' +SET @@session.sql_notes = OFFF; +ERROR 42000: Variable 'sql_notes' can't be set to the value of 'OFFF' SET @@session.sql_notes = ÓFF; ERROR 42000: Variable 'sql_notes' can't be set to the value of 'ÓFF' SET @@session.sql_notes = '¹'; diff --git a/mysql-test/suite/sys_vars/r/sql_quote_show_create_basic.result b/mysql-test/suite/sys_vars/r/sql_quote_show_create_basic.result index 8cf99233ef9..97715ae2089 100644 --- a/mysql-test/suite/sys_vars/r/sql_quote_show_create_basic.result +++ b/mysql-test/suite/sys_vars/r/sql_quote_show_create_basic.result @@ -48,8 +48,8 @@ SET @@session.sql_quote_show_create = TR ERROR 42000: Variable 'sql_quote_show_create' can't be set to the value of 'TRÜE' SET @@session.sql_quote_show_create = ÕN; ERROR 42000: Variable 'sql_quote_show_create' can't be set to the value of 'ÕN' -SET @@session.sql_quote_show_create = OF; -ERROR 42000: Variable 'sql_quote_show_create' can't be set to the value of 'OF' +SET @@session.sql_quote_show_create = OFFF; +ERROR 42000: Variable 'sql_quote_show_create' can't be set to the value of 'OFFF' SET @@session.sql_quote_show_create = ÓFF; ERROR 42000: Variable 'sql_quote_show_create' can't be set to the value of 'ÓFF' SET @@session.sql_quote_show_create = '¹'; diff --git a/mysql-test/suite/sys_vars/r/sql_safe_updates_basic.result b/mysql-test/suite/sys_vars/r/sql_safe_updates_basic.result index 91bfcb2377e..4bdcc8f6b47 100644 --- a/mysql-test/suite/sys_vars/r/sql_safe_updates_basic.result +++ b/mysql-test/suite/sys_vars/r/sql_safe_updates_basic.result @@ -48,8 +48,8 @@ SET @@session.sql_safe_updates = TR ERROR 42000: Variable 'sql_safe_updates' can't be set to the value of 'TRÜE' SET @@session.sql_safe_updates = ÕN; ERROR 42000: Variable 'sql_safe_updates' can't be set to the value of 'ÕN' -SET @@session.sql_safe_updates = OF; -ERROR 42000: Variable 'sql_safe_updates' can't be set to the value of 'OF' +SET @@session.sql_safe_updates = OFFF; +ERROR 42000: Variable 'sql_safe_updates' can't be set to the value of 'OFFF' SET @@session.sql_safe_updates = ÓFF; ERROR 42000: Variable 'sql_safe_updates' can't be set to the value of 'ÓFF' SET @@session.sql_safe_updates = '¹'; diff --git a/mysql-test/suite/sys_vars/r/sql_warnings_basic.result b/mysql-test/suite/sys_vars/r/sql_warnings_basic.result index 762182336c3..f9cae0c7f7a 100644 --- a/mysql-test/suite/sys_vars/r/sql_warnings_basic.result +++ b/mysql-test/suite/sys_vars/r/sql_warnings_basic.result @@ -46,8 +46,8 @@ SET @@session.sql_warnings = TR ERROR 42000: Variable 'sql_warnings' can't be set to the value of 'TRÜE' SET @@session.sql_warnings = ÕN; ERROR 42000: Variable 'sql_warnings' can't be set to the value of 'ÕN' -SET @@session.sql_warnings = OF; -ERROR 42000: Variable 'sql_warnings' can't be set to the value of 'OF' +SET @@session.sql_warnings = OFFF; +ERROR 42000: Variable 'sql_warnings' can't be set to the value of 'OFFF' SET @@session.sql_warnings = ÓFF; ERROR 42000: Variable 'sql_warnings' can't be set to the value of 'ÓFF' SET @@session.sql_warnings = '¹'; diff --git a/mysql-test/suite/sys_vars/r/tx_read_only_basic.result b/mysql-test/suite/sys_vars/r/tx_read_only_basic.result index 3750145083f..e8f5da31c5a 100644 --- a/mysql-test/suite/sys_vars/r/tx_read_only_basic.result +++ b/mysql-test/suite/sys_vars/r/tx_read_only_basic.result @@ -102,8 +102,8 @@ SET @@session.tx_read_only = ONN; ERROR 42000: Variable 'tx_read_only' can't be set to the value of 'ONN' SET @@session.tx_read_only = ONF; ERROR 42000: Variable 'tx_read_only' can't be set to the value of 'ONF' -SET @@session.tx_read_only = OF; -ERROR 42000: Variable 'tx_read_only' can't be set to the value of 'OF' +SET @@session.tx_read_only = OFFF; +ERROR 42000: Variable 'tx_read_only' can't be set to the value of 'OFFF' SET @@session.tx_read_only = 'OFN'; ERROR 42000: Variable 'tx_read_only' can't be set to the value of 'OFN' SET @@session.tx_read_only = -2; diff --git a/mysql-test/suite/sys_vars/t/delay_key_write_basic.test b/mysql-test/suite/sys_vars/t/delay_key_write_basic.test index 25176879eb1..2856993cb6c 100644 --- a/mysql-test/suite/sys_vars/t/delay_key_write_basic.test +++ b/mysql-test/suite/sys_vars/t/delay_key_write_basic.test @@ -90,7 +90,7 @@ SET @@global.delay_key_write = FALSE0; --Error ER_WRONG_VALUE_FOR_VAR SET @@global.delay_key_write = ONN; --Error ER_WRONG_VALUE_FOR_VAR -SET @@global.delay_key_write = OF; +SET @@global.delay_key_write = OFFF; --Error ER_WRONG_VALUE_FOR_VAR SET @@global.delay_key_write = ' '; diff --git a/mysql-test/suite/sys_vars/t/foreign_key_checks_basic.test b/mysql-test/suite/sys_vars/t/foreign_key_checks_basic.test index 8a327ab699b..b1fc9997cfa 100644 --- a/mysql-test/suite/sys_vars/t/foreign_key_checks_basic.test +++ b/mysql-test/suite/sys_vars/t/foreign_key_checks_basic.test @@ -94,7 +94,7 @@ SET @@session.foreign_key_checks = TR --Error ER_WRONG_VALUE_FOR_VAR SET @@session.foreign_key_checks = ÕN; --Error ER_WRONG_VALUE_FOR_VAR -SET @@session.foreign_key_checks = OF; +SET @@session.foreign_key_checks = OFFF; --Error ER_WRONG_VALUE_FOR_VAR SET @@session.foreign_key_checks = ÓFF; --Error ER_WRONG_VALUE_FOR_VAR diff --git a/mysql-test/suite/sys_vars/t/innodb_support_xa_basic.test b/mysql-test/suite/sys_vars/t/innodb_support_xa_basic.test new file mode 100644 index 00000000000..f8ce5852769 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/innodb_support_xa_basic.test @@ -0,0 +1,240 @@ +################# mysql-test\t\innodb_support_xa_basic.test ################### +# # +# Variable Name: innodb_support_xa # +# Scope: GLOBAL | SESSION # +# Access Type: Dynamic # +# Data Type: boolean # +# Default Value: 1 # +# Range: 0,1 # +# # +# # +# Creation Date: 2008-02-20 # +# Author: Rizwan # +# # +# Description: Test Cases of Dynamic System Variable innodb_support_xa # +# 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/have_innodb.inc +--source include/load_sysvars.inc + +######################################################################## +# START OF innodb_support_xa TESTS # +######################################################################## + + +################################################################################ +# Saving initial value of innodb_support_xa in a temporary variable # +################################################################################ + + +SET @session_start_value = @@session.innodb_support_xa; +SELECT @session_start_value; + + +SET @global_start_value = @@global.innodb_support_xa; +SELECT @global_start_value; + + + +--echo '#--------------------FN_DYNVARS_046_01------------------------#' +######################################################################## +# Display the DEFAULT value of innodb_support_xa # +######################################################################## + +SET @@session.innodb_support_xa = 0; +SET @@session.innodb_support_xa = DEFAULT; +SELECT @@session.innodb_support_xa; + +SET @@global.innodb_support_xa = 0; +SET @@global.innodb_support_xa = DEFAULT; +SELECT @@global.innodb_support_xa; + +--echo '#---------------------FN_DYNVARS_046_02-------------------------#' +########################################################################## +# Check if innodb_support_xa can be accessed with and without @@ sign # +########################################################################## + +SET innodb_support_xa = 1; +SELECT @@innodb_support_xa; + +--Error ER_UNKNOWN_TABLE +SELECT session.innodb_support_xa; + +--Error ER_UNKNOWN_TABLE +SELECT local.innodb_support_xa; + +--Error ER_UNKNOWN_TABLE +SELECT global.innodb_support_xa; +#using another syntax for accessing system variables +SET session innodb_support_xa = 0; +SELECT @@session.innodb_support_xa; + +SET global innodb_support_xa = 0; +SELECT @@global.innodb_support_xa; + + +--echo '#--------------------FN_DYNVARS_046_03------------------------#' +########################################################################## +# change the value of innodb_support_xa to a valid value # +########################################################################## +# for session +SET @@session.innodb_support_xa = 0; +SELECT @@session.innodb_support_xa; +SET @@session.innodb_support_xa = 1; +SELECT @@session.innodb_support_xa; + +# for global +SET @@global.innodb_support_xa = 0; +SELECT @@global.innodb_support_xa; +SET @@global.innodb_support_xa = 1; +SELECT @@global.innodb_support_xa; + + +--echo '#--------------------FN_DYNVARS_046_04-------------------------#' +########################################################################### +# Change the value of innodb_support_xa to invalid value # +########################################################################### + +# for session +--Error ER_WRONG_TYPE_FOR_VAR +SET @@session.innodb_support_xa = -0.6; +--Error ER_WRONG_TYPE_FOR_VAR +SET @@session.innodb_support_xa = 1.6; +--Error ER_WRONG_VALUE_FOR_VAR +SET @@session.innodb_support_xa = "T"; +--Error ER_WRONG_VALUE_FOR_VAR +SET @@session.innodb_support_xa = "Y"; +--Error ER_WRONG_VALUE_FOR_VAR +SET @@session.innodb_support_xa = TRÜE; +--Error ER_WRONG_VALUE_FOR_VAR +SET @@session.innodb_support_xa = ÕN; + +SET @@session.innodb_support_xa = OFF; +SELECT @@session.innodb_support_xa; + +--Error ER_WRONG_VALUE_FOR_VAR +SET @@session.innodb_support_xa = ÓFF; + +# for global + + +--Error ER_WRONG_VALUE_FOR_VAR +SET @@global.innodb_support_xa = -1; +SELECT @@global.innodb_support_xa; + +--Error ER_WRONG_VALUE_FOR_VAR +SET @@global.innodb_support_xa = 2; +--Error ER_WRONG_VALUE_FOR_VAR +SET @@global.innodb_support_xa = "T"; +--Error ER_WRONG_VALUE_FOR_VAR +SET @@global.innodb_support_xa = "Y"; +--Error ER_WRONG_VALUE_FOR_VAR +SET @@global.innodb_support_xa = TRÜE; +--Error ER_WRONG_VALUE_FOR_VAR +SET @@global.innodb_support_xa = ÕN; + +SET @@global.innodb_support_xa = OFF; +SELECT @@global.innodb_support_xa; + +--Error ER_WRONG_VALUE_FOR_VAR +SET @@global.innodb_support_xa = ÓFF; + + +--echo '#-------------------FN_DYNVARS_046_05----------------------------#' +########################################################################### +# Test if changing global variable effects session and vice versa # +########################################################################### + +SET @@global.innodb_support_xa = 0; +SET @@session.innodb_support_xa = 1; +SELECT @@global.innodb_support_xa AS res_is_0; + +SET @@global.innodb_support_xa = 0; +SELECT @@session.innodb_support_xa AS res_is_1; + +--echo '#----------------------FN_DYNVARS_046_06------------------------#' +######################################################################### +# Check if the value in GLOBAL Table matches value in variable # +######################################################################### + +--disable_warnings +SELECT IF(@@global.innodb_support_xa, "ON", "OFF") = + VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES + WHERE VARIABLE_NAME='innodb_support_xa'; +--enable_warnings +SELECT @@global.innodb_support_xa; +--disable_warnings +SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES + WHERE VARIABLE_NAME='innodb_support_xa'; +--enable_warnings + + +--echo '#----------------------FN_DYNVARS_046_07------------------------#' +######################################################################### +# Check if the value in SESSION Table matches value in variable # +######################################################################### + +--disable_warnings +SELECT IF(@@session.innodb_support_xa, "ON", "OFF") = + VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_VARIABLES + WHERE VARIABLE_NAME='innodb_support_xa'; +--enable_warnings +SELECT @@session.innodb_support_xa; +--disable_warnings +SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_VARIABLES + WHERE VARIABLE_NAME='innodb_support_xa'; +--enable_warnings + + +--echo '#---------------------FN_DYNVARS_046_08-------------------------#' +################################################################### +# Check if ON and OFF values can be used on variable # +################################################################### + +SET @@session.innodb_support_xa = OFF; +SELECT @@session.innodb_support_xa; +SET @@session.innodb_support_xa = ON; +SELECT @@session.innodb_support_xa; + +SET @@global.innodb_support_xa = OFF; +SELECT @@global.innodb_support_xa; +SET @@global.innodb_support_xa = ON; +SELECT @@global.innodb_support_xa; + +--echo '#---------------------FN_DYNVARS_046_09----------------------#' +################################################################### +# Check if TRUE and FALSE values can be used on variable # +################################################################### + +SET @@session.innodb_support_xa = TRUE; +SELECT @@session.innodb_support_xa; +SET @@session.innodb_support_xa = FALSE; +SELECT @@session.innodb_support_xa; + +SET @@global.innodb_support_xa = TRUE; +SELECT @@global.innodb_support_xa; +SET @@global.innodb_support_xa = FALSE; +SELECT @@global.innodb_support_xa; + +############################## +# Restore initial value # +############################## + +SET @@session.innodb_support_xa = @session_start_value; +SELECT @@session.innodb_support_xa; + +SET @@global.innodb_support_xa = @global_start_value; +SELECT @@global.innodb_support_xa; + +############################################################### +# END OF innodb_support_xa TESTS # +############################################################### diff --git a/mysql-test/suite/sys_vars/t/innodb_table_locks_basic.test b/mysql-test/suite/sys_vars/t/innodb_table_locks_basic.test index e3e4bda345e..25be5daa552 100644 --- a/mysql-test/suite/sys_vars/t/innodb_table_locks_basic.test +++ b/mysql-test/suite/sys_vars/t/innodb_table_locks_basic.test @@ -119,7 +119,7 @@ SET @@session.innodb_table_locks = TR --Error ER_WRONG_VALUE_FOR_VAR SET @@session.innodb_table_locks = ÕN; -SET @@session.innodb_table_locks = OF; +SET @@session.innodb_table_locks = OFF; SELECT @@session.innodb_table_locks; --Error ER_WRONG_VALUE_FOR_VAR @@ -141,7 +141,7 @@ SET @@global.innodb_table_locks = TR --Error ER_WRONG_VALUE_FOR_VAR SET @@global.innodb_table_locks = QN; -SET @@global.innodb_table_locks = OF; +SET @@global.innodb_table_locks = OFF; SELECT @@global.innodb_table_locks; --Error ER_WRONG_TYPE_FOR_VAR diff --git a/mysql-test/suite/sys_vars/t/keep_files_on_create_basic.test b/mysql-test/suite/sys_vars/t/keep_files_on_create_basic.test index e6141af4bbe..cfa50e72146 100644 --- a/mysql-test/suite/sys_vars/t/keep_files_on_create_basic.test +++ b/mysql-test/suite/sys_vars/t/keep_files_on_create_basic.test @@ -132,7 +132,7 @@ SET @@session.keep_files_on_create = ONN; --Error ER_WRONG_VALUE_FOR_VAR SET @@session.keep_files_on_create = ONF; --Error ER_WRONG_VALUE_FOR_VAR -SET @@session.keep_files_on_create = OF; +SET @@session.keep_files_on_create = OFFF; --Error ER_WRONG_VALUE_FOR_VAR SET @@session.keep_files_on_create = 'OFN'; --Error ER_WRONG_VALUE_FOR_VAR diff --git a/mysql-test/suite/sys_vars/t/log_bin_trust_function_creators_basic.test b/mysql-test/suite/sys_vars/t/log_bin_trust_function_creators_basic.test index 15ffad2742a..1db6bf41e6f 100644 --- a/mysql-test/suite/sys_vars/t/log_bin_trust_function_creators_basic.test +++ b/mysql-test/suite/sys_vars/t/log_bin_trust_function_creators_basic.test @@ -96,7 +96,7 @@ SET @@global.log_bin_trust_function_creators = 'ONN'; --Error ER_WRONG_VALUE_FOR_VAR SET @@global.log_bin_trust_function_creators = "OFFF"; --Error ER_WRONG_VALUE_FOR_VAR -SET @@global.log_bin_trust_function_creators = OF; +SET @@global.log_bin_trust_function_creators = OFFF; --Error ER_WRONG_VALUE_FOR_VAR SET @@global.log_bin_trust_function_creators = TTRUE; --Error ER_WRONG_VALUE_FOR_VAR diff --git a/mysql-test/suite/sys_vars/t/low_priority_updates_basic.test b/mysql-test/suite/sys_vars/t/low_priority_updates_basic.test index e00688ef974..703036b8e36 100644 --- a/mysql-test/suite/sys_vars/t/low_priority_updates_basic.test +++ b/mysql-test/suite/sys_vars/t/low_priority_updates_basic.test @@ -132,7 +132,7 @@ SET @@session.low_priority_updates = ONN; --Error ER_WRONG_VALUE_FOR_VAR SET @@session.low_priority_updates = ONF; --Error ER_WRONG_VALUE_FOR_VAR -SET @@session.low_priority_updates = OF; +SET @@session.low_priority_updates = OFFF; --Error ER_WRONG_VALUE_FOR_VAR SET @@session.low_priority_updates = 'OFN'; --Error ER_WRONG_VALUE_FOR_VAR diff --git a/mysql-test/suite/sys_vars/t/old_passwords_basic.test b/mysql-test/suite/sys_vars/t/old_passwords_basic.test index f4965ad7528..038a77edf8f 100644 --- a/mysql-test/suite/sys_vars/t/old_passwords_basic.test +++ b/mysql-test/suite/sys_vars/t/old_passwords_basic.test @@ -131,7 +131,7 @@ SET @@session.old_passwords = ONN; --Error ER_WRONG_VALUE_FOR_VAR SET @@session.old_passwords = ONF; --Error ER_WRONG_VALUE_FOR_VAR -SET @@session.old_passwords = OF; +SET @@session.old_passwords = OFFF; --Error ER_WRONG_VALUE_FOR_VAR SET @@session.old_passwords = 'OFN'; --Error ER_WRONG_VALUE_FOR_VAR diff --git a/mysql-test/suite/sys_vars/t/optimizer_prune_level_basic.test b/mysql-test/suite/sys_vars/t/optimizer_prune_level_basic.test index 1e3a8bc3d7f..374be2db6ae 100644 --- a/mysql-test/suite/sys_vars/t/optimizer_prune_level_basic.test +++ b/mysql-test/suite/sys_vars/t/optimizer_prune_level_basic.test @@ -140,7 +140,7 @@ SET @@session.optimizer_prune_level = ONF; --Error ER_WRONG_TYPE_FOR_VAR SET @@session.optimizer_prune_level = ON; --Error ER_WRONG_TYPE_FOR_VAR -SET @@session.optimizer_prune_level = OF; +SET @@session.optimizer_prune_level = OFFF; --Error ER_WRONG_TYPE_FOR_VAR SET @@session.optimizer_prune_level = 'OFN'; diff --git a/mysql-test/suite/sys_vars/t/pseudo_slave_mode_basic.test b/mysql-test/suite/sys_vars/t/pseudo_slave_mode_basic.test index 3ef39bb8667..6d1dca299c6 100644 --- a/mysql-test/suite/sys_vars/t/pseudo_slave_mode_basic.test +++ b/mysql-test/suite/sys_vars/t/pseudo_slave_mode_basic.test @@ -97,7 +97,7 @@ SET @@session.pseudo_slave_mode = TR --Error ER_WRONG_VALUE_FOR_VAR SET @@session.pseudo_slave_mode = ÕN; --Error ER_WRONG_VALUE_FOR_VAR -SET @@session.pseudo_slave_mode = OF; +SET @@session.pseudo_slave_mode = OFFF; --Error ER_WRONG_VALUE_FOR_VAR SET @@session.pseudo_slave_mode = ÓFF; --Error ER_WRONG_VALUE_FOR_VAR diff --git a/mysql-test/suite/sys_vars/t/query_cache_wlock_invalidate_basic.test b/mysql-test/suite/sys_vars/t/query_cache_wlock_invalidate_basic.test index 055c3629d15..c883d9b789a 100644 --- a/mysql-test/suite/sys_vars/t/query_cache_wlock_invalidate_basic.test +++ b/mysql-test/suite/sys_vars/t/query_cache_wlock_invalidate_basic.test @@ -116,7 +116,7 @@ SET @@session.query_cache_wlock_invalidate = TR --Error ER_WRONG_VALUE_FOR_VAR SET @@session.query_cache_wlock_invalidate = ÕN; --Error ER_WRONG_VALUE_FOR_VAR -SET @@session.query_cache_wlock_invalidate = OF; +SET @@session.query_cache_wlock_invalidate = OFFF; --Error ER_WRONG_VALUE_FOR_VAR SET @@session.query_cache_wlock_invalidate = ÓFF; @@ -135,7 +135,7 @@ SET @@global.query_cache_wlock_invalidate = TR --Error ER_WRONG_VALUE_FOR_VAR SET @@global.query_cache_wlock_invalidate = ÕN; --Error ER_WRONG_VALUE_FOR_VAR -SET @@global.query_cache_wlock_invalidate = OF; +SET @@global.query_cache_wlock_invalidate = OFFF; --Error ER_WRONG_VALUE_FOR_VAR SET @@global.query_cache_wlock_invalidate = ÓFF; diff --git a/mysql-test/suite/sys_vars/t/sql_big_selects_basic.test b/mysql-test/suite/sys_vars/t/sql_big_selects_basic.test index 42331d766be..52345b71144 100644 --- a/mysql-test/suite/sys_vars/t/sql_big_selects_basic.test +++ b/mysql-test/suite/sys_vars/t/sql_big_selects_basic.test @@ -94,7 +94,7 @@ SET @@session.sql_big_selects = TR --Error ER_WRONG_VALUE_FOR_VAR SET @@session.sql_big_selects = ÕN; --Error ER_WRONG_VALUE_FOR_VAR -SET @@session.sql_big_selects = OF; +SET @@session.sql_big_selects = OFFF; --Error ER_WRONG_VALUE_FOR_VAR SET @@session.sql_big_selects = ÓFF; --Error ER_WRONG_VALUE_FOR_VAR diff --git a/mysql-test/suite/sys_vars/t/sql_buffer_result_basic.test b/mysql-test/suite/sys_vars/t/sql_buffer_result_basic.test index f5f99efeb0a..2475bd9cd8a 100644 --- a/mysql-test/suite/sys_vars/t/sql_buffer_result_basic.test +++ b/mysql-test/suite/sys_vars/t/sql_buffer_result_basic.test @@ -100,7 +100,7 @@ SET @@session.sql_buffer_result = TR --Error ER_WRONG_VALUE_FOR_VAR SET @@session.sql_buffer_result = ÕN; --Error ER_WRONG_VALUE_FOR_VAR -SET @@session.sql_buffer_result = OF; +SET @@session.sql_buffer_result = OFFF; --Error ER_WRONG_VALUE_FOR_VAR SET @@session.sql_buffer_result = ÓFF; --Error ER_WRONG_VALUE_FOR_VAR diff --git a/mysql-test/suite/sys_vars/t/sql_log_bin_basic.test b/mysql-test/suite/sys_vars/t/sql_log_bin_basic.test index 5f5e3920862..7e133200d5f 100644 --- a/mysql-test/suite/sys_vars/t/sql_log_bin_basic.test +++ b/mysql-test/suite/sys_vars/t/sql_log_bin_basic.test @@ -98,7 +98,7 @@ SET @@session.sql_log_bin = TR --Error ER_WRONG_VALUE_FOR_VAR SET @@session.sql_log_bin = ÕN; --Error ER_WRONG_VALUE_FOR_VAR -SET @@session.sql_log_bin = OF; +SET @@session.sql_log_bin = OFFF; --Error ER_WRONG_VALUE_FOR_VAR SET @@session.sql_log_bin = ÓFF; --Error ER_WRONG_VALUE_FOR_VAR diff --git a/mysql-test/suite/sys_vars/t/sql_log_off_basic.test b/mysql-test/suite/sys_vars/t/sql_log_off_basic.test index 38549ac35d2..a48d3bbfda6 100644 --- a/mysql-test/suite/sys_vars/t/sql_log_off_basic.test +++ b/mysql-test/suite/sys_vars/t/sql_log_off_basic.test @@ -97,7 +97,7 @@ SET @@session.sql_log_off = TR --Error ER_WRONG_VALUE_FOR_VAR SET @@session.sql_log_off = ÕN; --Error ER_WRONG_VALUE_FOR_VAR -SET @@session.sql_log_off = OF; +SET @@session.sql_log_off = OFFF; --Error ER_WRONG_VALUE_FOR_VAR SET @@session.sql_log_off = ÓFF; --Error ER_WRONG_VALUE_FOR_VAR diff --git a/mysql-test/suite/sys_vars/t/sql_notes_basic.test b/mysql-test/suite/sys_vars/t/sql_notes_basic.test index 9af5fa35ea2..204ebe3fe84 100644 --- a/mysql-test/suite/sys_vars/t/sql_notes_basic.test +++ b/mysql-test/suite/sys_vars/t/sql_notes_basic.test @@ -99,7 +99,7 @@ SET @@session.sql_notes = TR --Error ER_WRONG_VALUE_FOR_VAR SET @@session.sql_notes = ÕN; --Error ER_WRONG_VALUE_FOR_VAR -SET @@session.sql_notes = OF; +SET @@session.sql_notes = OFFF; --Error ER_WRONG_VALUE_FOR_VAR SET @@session.sql_notes = ÓFF; --Error ER_WRONG_VALUE_FOR_VAR diff --git a/mysql-test/suite/sys_vars/t/sql_quote_show_create_basic.test b/mysql-test/suite/sys_vars/t/sql_quote_show_create_basic.test index 020b5f51e9f..8e8118b998b 100644 --- a/mysql-test/suite/sys_vars/t/sql_quote_show_create_basic.test +++ b/mysql-test/suite/sys_vars/t/sql_quote_show_create_basic.test @@ -98,7 +98,7 @@ SET @@session.sql_quote_show_create = TR --Error ER_WRONG_VALUE_FOR_VAR SET @@session.sql_quote_show_create = ÕN; --Error ER_WRONG_VALUE_FOR_VAR -SET @@session.sql_quote_show_create = OF; +SET @@session.sql_quote_show_create = OFFF; --Error ER_WRONG_VALUE_FOR_VAR SET @@session.sql_quote_show_create = ÓFF; --Error ER_WRONG_VALUE_FOR_VAR diff --git a/mysql-test/suite/sys_vars/t/sql_safe_updates_basic.test b/mysql-test/suite/sys_vars/t/sql_safe_updates_basic.test index 66148b65aaf..89208cae0ef 100644 --- a/mysql-test/suite/sys_vars/t/sql_safe_updates_basic.test +++ b/mysql-test/suite/sys_vars/t/sql_safe_updates_basic.test @@ -97,7 +97,7 @@ SET @@session.sql_safe_updates = TR --Error ER_WRONG_VALUE_FOR_VAR SET @@session.sql_safe_updates = ÕN; --Error ER_WRONG_VALUE_FOR_VAR -SET @@session.sql_safe_updates = OF; +SET @@session.sql_safe_updates = OFFF; --Error ER_WRONG_VALUE_FOR_VAR SET @@session.sql_safe_updates = ÓFF; --Error ER_WRONG_VALUE_FOR_VAR diff --git a/mysql-test/suite/sys_vars/t/sql_warnings_basic.test b/mysql-test/suite/sys_vars/t/sql_warnings_basic.test index ced58f96e15..f32b6f33f89 100644 --- a/mysql-test/suite/sys_vars/t/sql_warnings_basic.test +++ b/mysql-test/suite/sys_vars/t/sql_warnings_basic.test @@ -98,7 +98,7 @@ SET @@session.sql_warnings = TR --Error ER_WRONG_VALUE_FOR_VAR SET @@session.sql_warnings = ÕN; --Error ER_WRONG_VALUE_FOR_VAR -SET @@session.sql_warnings = OF; +SET @@session.sql_warnings = OFFF; --Error ER_WRONG_VALUE_FOR_VAR SET @@session.sql_warnings = ÓFF; --Error ER_WRONG_VALUE_FOR_VAR diff --git a/mysql-test/suite/sys_vars/t/tx_read_only_basic.test b/mysql-test/suite/sys_vars/t/tx_read_only_basic.test index 0ebfcc31a89..8c6ab0e3d59 100644 --- a/mysql-test/suite/sys_vars/t/tx_read_only_basic.test +++ b/mysql-test/suite/sys_vars/t/tx_read_only_basic.test @@ -116,7 +116,7 @@ SET @@session.tx_read_only = ONN; --Error ER_WRONG_VALUE_FOR_VAR SET @@session.tx_read_only = ONF; --Error ER_WRONG_VALUE_FOR_VAR -SET @@session.tx_read_only = OF; +SET @@session.tx_read_only = OFFF; --Error ER_WRONG_VALUE_FOR_VAR SET @@session.tx_read_only = 'OFN'; --Error ER_WRONG_VALUE_FOR_VAR diff --git a/mysql-test/t/auto_increment.test b/mysql-test/t/auto_increment.test index 7f0ab5dc169..dca4b026c80 100644 --- a/mysql-test/t/auto_increment.test +++ b/mysql-test/t/auto_increment.test @@ -397,3 +397,37 @@ insert into t1 values(null); select last_insert_id(); select * from t1; drop table t1; + +--echo # +--echo # System Versioning Support +--echo # +--echo # +CREATE TABLE t1(id INT UNSIGNED AUTO_INCREMENT, x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end), PRIMARY KEY (id)) WITH SYSTEM VERSIONING; +CREATE TABLE T1(id INT UNSIGNED AUTO_INCREMENT, x INT UNSIGNED, y INT UNSIGNED, PRIMARY KEY (id)); +INSERT INTO t1(x, y) VALUES(1, 11); +INSERT INTO T1(x, y) VALUES(1, 11); +INSERT INTO t1(x, y) VALUES(2, 12); +INSERT INTO T1(x, y) VALUES(2, 12); +INSERT INTO t1(x, y) VALUES(3, 13); +INSERT INTO T1(x, y) VALUES(3, 13); +INSERT INTO t1(x, y) VALUES(4, 14); +INSERT INTO T1(x, y) VALUES(4, 14); +INSERT INTO t1(x, y) VALUES(5, 15); +INSERT INTO T1(x, y) VALUES(5, 15); +INSERT INTO t1(x, y) VALUES(6, 16); +INSERT INTO T1(x, y) VALUES(6, 16); +INSERT INTO t1(x, y) VALUES(7, 17); +INSERT INTO T1(x, y) VALUES(7, 17); +INSERT INTO t1(x, y) VALUES(8, 18); +INSERT INTO T1(x, y) VALUES(8, 18); +INSERT INTO t1(x, y) VALUES(9, 19); +INSERT INTO T1(x, y) VALUES(9, 19); +SELECT t1.x = T1.x AND t1.y = T1.y, t1.x, t1.y, T1.x, T1.y FROM t1 INNER JOIN T1 ON(t1.id = T1.id); +DELETE FROM t1 WHERE x=2; +DELETE FROM T1 WHERE x=2; +SELECT t1.x = T1.x AND t1.y = T1.y, t1.x, t1.y, T1.x, T1.y FROM t1 INNER JOIN T1 ON(t1.id = T1.id); +DELETE FROM t1 WHERE x>7; +DELETE FROM T1 WHERE x>7; +SELECT t1.x = T1.x AND t1.y = T1.y, t1.x, t1.y, T1.x, T1.y FROM t1 INNER JOIN T1 ON(t1.id = T1.id); +DROP TABLE t1; +DROP TABLE T1; diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 6461204f06e..5e5c5008d8e 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -1781,3 +1781,101 @@ create table t1; # create table t1 (i int, j int, key(i), key(i)) as select 1 as i, 2 as j; drop table t1; + +# +# Create table SYSTEM VERSIONING +# +--echo # +--echo # Test for SYSTEM VERSIONING CREATE +--echo # + +create table t1 ( + XNo INT UNSIGNED, + Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, + Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) +) WITH SYSTEM VERSIONING; +SHOW CREATE TABLE t1; + +drop table if exists t1; + +--error ER_SYS_START_MORE_THAN_ONCE +create table t1 ( + XNo INT UNSIGNED, + Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, + Sys_start2 TIMESTAMP(6) GENERATED ALWAYS AS ROW START, + Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) +) WITH SYSTEM VERSIONING; + +--error ER_PERIOD_FOR_SYSTEM_TIME_CONTAINS_WRONG_END_COLUMN +create table t1 ( + XNo INT UNSIGNED, + Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, + Sys_end2 TIMESTAMP(6) GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) +) WITH SYSTEM VERSIONING; + +--error ER_SYS_END_MORE_THAN_ONCE +create table t1 ( + XNo INT UNSIGNED, + Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, + Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, + Sys_end2 TIMESTAMP(6) GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) +) WITH SYSTEM VERSIONING; + +--error ER_SYS_START_NOT_SPECIFIED +create table t1 ( + XNo INT UNSIGNED, + PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) +) WITH SYSTEM VERSIONING; + +--error ER_SYS_END_MORE_THAN_ONCE +create table t1 ( + XNo INT UNSIGNED, + Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, + Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, + Sys_end2 TIMESTAMP(6) GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) +); + +--error ER_PERIOD_FOR_SYSTEM_TIME_CONTAINS_WRONG_START_COLUMN +create table t1 ( + XNo INT UNSIGNED, + Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, + Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (Sys_insert, Sys_remove) +) WITH SYSTEM VERSIONING; + +--error ER_MISSING_WITH_SYSTEM_VERSIONING +create table t1 ( + XNo INT UNSIGNED, + Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, + Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) +); + +--error ER_SYS_START_AND_SYS_END_SAME +create table t1 ( + XNo INT UNSIGNED, + Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, + Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (Sys_start, Sys_start) +); + +--error ER_SYS_START_FIELD_MUST_BE_TIMESTAMP +create table t1 ( + XNo INT UNSIGNED, + Sys_start INT GENERATED ALWAYS AS ROW START, + Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) +) WITH SYSTEM VERSIONING; + +--error ER_SYS_END_FIELD_MUST_BE_TIMESTAMP +create table t1 ( + XNo INT UNSIGNED, + Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, + Sys_end INT GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) +) WITH SYSTEM VERSIONING; diff --git a/mysql-test/t/delete.test b/mysql-test/t/delete.test index c82420640c2..a91e6ddf82e 100644 --- a/mysql-test/t/delete.test +++ b/mysql-test/t/delete.test @@ -582,3 +582,47 @@ DELETE v2 FROM v2; DROP VIEW v2, v1; DROP TABLE t1, t2; + +# +# SQL DELETE for SYSTEM VERSIONING +# +--echo # +--echo # Test for SYSTEM VERSIONING +--echo # + +SET @@session.time_zone='+00:00'; + +create table t1 ( + XNo INT UNSIGNED, + Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, + Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) +) WITH SYSTEM VERSIONING; + +INSERT INTO t1(XNo) VALUES(0); +INSERT INTO t1(XNo) VALUES(1); +INSERT INTO t1(XNo) VALUES(2); +INSERT INTO t1(XNo) VALUES(3); +INSERT INTO t1(XNo) VALUES(4); +INSERT INTO t1(XNo) VALUES(5); +INSERT INTO t1(XNo) VALUES(6); +INSERT INTO t1(XNo) VALUES(7); +INSERT INTO t1(XNo) VALUES(8); +INSERT INTO t1(XNo) VALUES(9); + +SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; +DELETE FROM t1 WHERE XNo = 0; +SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; +DELETE FROM t1 WHERE XNo = 1; +SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; +DELETE FROM t1 WHERE XNo > 5; + +CREATE VIEW vt1 AS SELECT XNo FROM t1; + +SELECT XNo FROM vt1; +DELETE FROM vt1 WHERE XNo = 3; +SELECT XNo FROM vt1; +SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; + +DROP VIEW vt1; +DROP TABLE t1; diff --git a/mysql-test/t/insert.test b/mysql-test/t/insert.test index 206c5553100..7a4523a3f49 100644 --- a/mysql-test/t/insert.test +++ b/mysql-test/t/insert.test @@ -573,3 +573,76 @@ insert ignore into t1 values (1,12) on duplicate key update f2=13; set @@old_mode=""; insert ignore into t1 values (1,12); DROP TABLE t1; + +--echo # +--echo # System Versioning Support +--echo # +--echo # + +-- source include/have_innodb.inc + +SET @@session.time_zone='+00:00'; + +CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; +INSERT INTO t1(x, y) VALUES(3, 4); +INSERT INTO t1(x, y) VALUES(2, 3); +INSERT INTO t1 VALUES(40, 33); +SELECT x, y, Sys_end FROM t1; +DROP TABLE t1; + +CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; +INSERT INTO t1(x, y) VALUES(3, 4); +INSERT INTO t1(x, y) VALUES(2, 3); +INSERT INTO t1 VALUES(40, 33); +SELECT x, y, Sys_end FROM t1; +DROP TABLE t1; + +CREATE TABLE t1(id INT UNSIGNED NOT NULL AUTO_INCREMENT, x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end), PRIMARY KEY(id)) WITH SYSTEM VERSIONING; +INSERT INTO t1(x, y) VALUES(33, 44); +INSERT INTO t1(id, x, y) VALUES(20, 33, 44); +INSERT INTO t1 VALUES(40, 33, 44); +SELECT id, x, y, Sys_end FROM t1; +DROP TABLE t1; + +CREATE TABLE t1(id INT UNSIGNED NOT NULL AUTO_INCREMENT, x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end), PRIMARY KEY(id)) WITH SYSTEM VERSIONING ENGINE=InnoDB; +INSERT INTO t1(x, y) VALUES(33, 44); +INSERT INTO t1(id, x, y) VALUES(20, 33, 44); +INSERT INTO t1 VALUES(40, 33, 44); +SELECT id, x, y, Sys_end FROM t1; +DROP TABLE t1; + +CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; +CREATE VIEW vt1_1 AS SELECT x, y FROM t1; +CREATE VIEW vt1_2 AS SELECT x, y, Sys_end FROM t1; +INSERT INTO t1(x, y) VALUES(8001, 9001); +--error ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER +INSERT INTO t1(x, y, Sys_end) VALUES(8001, 9001, '2015-1-1 0:0:0'); +INSERT INTO vt1_1(x, y) VALUES(1001, 2001); +INSERT INTO vt1_1 VALUES(1002, 2002); +INSERT INTO vt1_2(x, y) VALUES(3001, 4001); +--error ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER +INSERT INTO vt1_2 VALUES(3002, 4002, '2015-1-1 0:0:0'); +SELECT x, y, Sys_end FROM t1; +SELECT x, y FROM vt1_1; +SELECT x, y, Sys_end FROM vt1_2; +DROP TABLE t1; +DROP VIEW vt1_1; +DROP VIEW vt1_2; + +CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; +CREATE VIEW vt1_1 AS SELECT x, y FROM t1; +CREATE VIEW vt1_2 AS SELECT x, y, Sys_end FROM t1; +INSERT INTO t1(x, y) VALUES(8001, 9001); +--error ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER +INSERT INTO t1(x, y, Sys_end) VALUES(8001, 9001, '2015-1-1 0:0:0'); +INSERT INTO vt1_1(x, y) VALUES(1001, 2001); +INSERT INTO vt1_1 VALUES(1002, 2002); +INSERT INTO vt1_2(x, y) VALUES(3001, 4001); +--error ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER +INSERT INTO vt1_2 VALUES(3002, 4002, '2015-1-1 0:0:0'); +SELECT x, y, Sys_end FROM t1; +SELECT x, y FROM vt1_1; +SELECT x, y, Sys_end FROM vt1_2; +DROP TABLE t1; +DROP VIEW vt1_1; +DROP VIEW vt1_2; diff --git a/mysql-test/t/insert_select.test b/mysql-test/t/insert_select.test index fda89f18d99..11dca894117 100644 --- a/mysql-test/t/insert_select.test +++ b/mysql-test/t/insert_select.test @@ -425,3 +425,68 @@ SET GLOBAL myisam_data_pointer_size = @old_myisam_data_pointer_size; DROP TABLE t1; --echo End of 5.1 tests + +--echo # +--echo # System Versioning Support +--echo # +--echo # + +-- source include/have_innodb.inc + +CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=MyISAM; +CREATE TABLE t2(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=MyISAM; +INSERT INTO t1(x, y) VALUES + (1, 1000), + (2, 2000), + (3, 3000), + (4, 4000), + (5, 5000), + (6, 6000), + (7, 7000), + (8, 8000), + (9, 9000); +DELETE FROM t1 WHERE x >= 1; +INSERT INTO t1(x, y) VALUES + (1, 1001), + (2, 2001), + (3, 3001), + (4, 4001), + (5, 5001), + (6, 6001), + (7, 7001), + (8, 8001), + (9, 9001); +INSERT INTO t2 SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; +SELECT x, y FROM t1; +SELECT x, y FROM t2; +DROP TABLE t1; +DROP TABLE t2; + +CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; +CREATE TABLE t2(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; +INSERT INTO t1(x, y) VALUES + (1, 1000), + (2, 2000), + (3, 3000), + (4, 4000), + (5, 5000), + (6, 6000), + (7, 7000), + (8, 8000), + (9, 9000); +DELETE FROM t1 WHERE x >= 1; +INSERT INTO t1(x, y) VALUES + (1, 1001), + (2, 2001), + (3, 3001), + (4, 4001), + (5, 5001), + (6, 6001), + (7, 7001), + (8, 8001), + (9, 9001); +INSERT INTO t2 SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; +SELECT x, y FROM t1; +SELECT x, y FROM t2; +DROP TABLE t1; +DROP TABLE t2; diff --git a/mysql-test/t/insert_update.test b/mysql-test/t/insert_update.test index 7234973eeb8..518fea8d2a1 100644 --- a/mysql-test/t/insert_update.test +++ b/mysql-test/t/insert_update.test @@ -311,3 +311,48 @@ insert into t1(f1) values(1) on duplicate key update f1=1; select @stamp2:=f2 from t1; select if( @stamp1 = @stamp2, "correct", "wrong"); drop table t1; + +--echo # +--echo # System Versioning Support +--echo # +--echo # + +-- source include/have_innodb.inc + +CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end), PRIMARY KEY(x, y)) WITH SYSTEM VERSIONING; +INSERT INTO t1(x, y) VALUES + (1, 1000), + (2, 2000), + (3, 3000), + (4, 4000), + (5, 5000), + (6, 6000), + (7, 7000), + (8, 8000), + (9, 9000); +INSERT INTO t1(x, y) VALUES(3, 3000) ON DUPLICATE KEY UPDATE y = y+1; +INSERT INTO t1(x, y) VALUES(4, 4000) ON DUPLICATE KEY UPDATE y = y+1; +INSERT INTO t1(x, y) VALUES(4, 4001) ON DUPLICATE KEY UPDATE y = y+1; +INSERT INTO t1(x, y) VALUES(4, 4444) ON DUPLICATE KEY UPDATE y = y+1; +SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; +SELECT x, y FROM t1; +DROP TABLE t1; + +CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end), PRIMARY KEY(x, y)) WITH SYSTEM VERSIONING ENGINE=InnoDB; +INSERT INTO t1(x, y) VALUES + (1, 1000), + (2, 2000), + (3, 3000), + (4, 4000), + (5, 5000), + (6, 6000), + (7, 7000), + (8, 8000), + (9, 9000); +INSERT INTO t1(x, y) VALUES(3, 3000) ON DUPLICATE KEY UPDATE y = y+1; +INSERT INTO t1(x, y) VALUES(4, 4000) ON DUPLICATE KEY UPDATE y = y+1; +INSERT INTO t1(x, y) VALUES(4, 4001) ON DUPLICATE KEY UPDATE y = y+1; +INSERT INTO t1(x, y) VALUES(4, 4444) ON DUPLICATE KEY UPDATE y = y+1; +SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; +SELECT x, y FROM t1; +DROP TABLE t1; diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test index 64e61f7c0b5..a5a9ca4943e 100644 --- a/mysql-test/t/multi_update.test +++ b/mysql-test/t/multi_update.test @@ -984,3 +984,119 @@ deallocate prepare stmt1; drop view v3,v2,v1; drop table t1,t2,t3; --echo end of 5.5 tests + + +--source include/have_xtradb.inc + +--echo +--echo # Bug mdev-5970 +--echo # Bug#13256831 - ERROR 1032 (HY000): CAN'T FIND RECORD +--echo + +CREATE TABLE t1 (f1 INT PRIMARY KEY, f2 INT) ENGINE=InnoDB; +CREATE TABLE t2 (f1 INT PRIMARY KEY, f2 INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (5, 7); +INSERT INTO t2 VALUES (6, 97); + +CREATE ALGORITHM = MERGE VIEW v1 AS +SELECT a2.f1 AS f1, a2.f2 AS f2 +FROM t1 AS a1 JOIN t2 AS a2 ON a1.f2 > a2.f1 +WITH LOCAL CHECK OPTION; + +SELECT * FROM v1; +UPDATE v1 SET f1 = 1; +SELECT * FROM v1; + +DROP TABLE t1, t2; +DROP VIEW v1; + +--echo # +--echo # MDEV-5973: MySQL Bug#11757486:49539: NON-DESCRIPTIVE ERR (ERROR 0 +--echo # FROM STORAGE ENGINE) WITH MULTI-TABLE UPDATE +--echo # + +CREATE TABLE table_11757486 (field1 tinyint) ENGINE=INNODB; +INSERT INTO table_11757486 VALUES (0),(0); +SET SESSION SQL_MODE='STRICT_ALL_TABLES'; +UPDATE IGNORE (SELECT 128 as col1) x, table_11757486 SET field1=x.col1; +UPDATE IGNORE table_11757486 SET field1=128; + +--error ER_WARN_DATA_OUT_OF_RANGE +UPDATE (SELECT 128 as col1) x, table_11757486 SET field1=x.col1; +--error ER_WARN_DATA_OUT_OF_RANGE +UPDATE table_11757486 SET field1=128; + +SET SESSION SQL_MODE=''; +UPDATE IGNORE (SELECT 128 as col1) x, table_11757486 SET field1=x.col1; +UPDATE IGNORE table_11757486 SET field1=128; + +DROP TABLE table_11757486; + +SET SESSION SQL_MODE=default; + +--echo end of 10.0 tests + +--echo # +--echo # System Versioning Support +--echo # +--echo # + +CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; +CREATE TABLE t2(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; +INSERT INTO t1(x, y) VALUES + (1, 1000), + (2, 2000), + (3, 3000), + (4, 4000), + (5, 5000), + (6, 6000), + (7, 7000), + (8, 8000), + (9, 9000); +INSERT INTO t2(x, y) VALUES + (1, 1010), + (2, 2010), + (3, 3010), + (4, 4010), + (5, 5010), + (6, 6010), + (7, 7010), + (8, 8010), + (9, 9010); +UPDATE t1, t2 SET t1.y = t1.x + t1.y, t2.y = t2.x + t2.y WHERE t1.x > 7 AND t2.x < 7; +SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; +SELECT x, y FROM t1; +SELECT x, y FROM t2 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; +SELECT x, y FROM t2; +DROP TABLE t1; +DROP TABLE t2; + +CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; +CREATE TABLE t2(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; +INSERT INTO t1(x, y) VALUES + (1, 1000), + (2, 2000), + (3, 3000), + (4, 4000), + (5, 5000), + (6, 6000), + (7, 7000), + (8, 8000), + (9, 9000); +INSERT INTO t2(x, y) VALUES + (1, 1010), + (2, 2010), + (3, 3010), + (4, 4010), + (5, 5010), + (6, 6010), + (7, 7010), + (8, 8010), + (9, 9010); +UPDATE t1, t2 SET t1.y = t1.x + t1.y, t2.y = t2.x + t2.y WHERE t1.x > 7 AND t2.x < 7; +SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; +SELECT x, y FROM t1; +SELECT x, y FROM t2 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; +SELECT x, y FROM t2; +DROP TABLE t1; +DROP TABLE t2; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index e8d5f9fa445..3d2c689591e 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -25,13 +25,13 @@ if (`select @join_cache_level_for_select_test is not null`) } CREATE TABLE t1 ( - Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, + Period_ smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL ); INSERT INTO t1 VALUES (9410,9412); -select period from t1; +select period_ from t1; select * from t1; select t1.* from t1; @@ -1361,7 +1361,7 @@ select fld1,fld3 from t2 where fld1 like "25050_"; select distinct companynr from t2; select distinct companynr from t2 order by companynr; select distinct companynr from t2 order by companynr desc; -select distinct t2.fld3,period from t2,t1 where companynr=37 and fld3 like "O%"; +select distinct t2.fld3,period_ from t2,t1 where companynr=37 and fld3 like "O%"; select distinct fld3 from t2 where companynr = 34 order by fld3; select distinct fld3 from t2 limit 10; @@ -1374,26 +1374,26 @@ select distinct substring(fld3,1,3) as a from t2 having a like "A%" limit 10; # make a big table. create table t3 ( - period int not null, + period_ int not null, name char(32) not null, companynr int not null, price double(11,0), price2 double(11,0), - key (period), + key (period_), key (name) ); --disable_query_log -INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1001,"Iranizes",37,5987435,234724); -INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1002,"violinist",37,28357832,8723648); -INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1003,"extramarital",37,39654943,235872); -INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1004,"spates",78,726498,72987523); -INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1005,"cloakroom",78,98439034,823742); -INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1006,"gazer",101,834598,27348324); -INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1007,"hand",154,983543950,29837423); -INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1008,"tucked",311,234298,3275892); -INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1009,"gems",447,2374834,9872392); -INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1010,"clinker",512,786542,76234234); +INSERT INTO t3 (period_,name,companynr,price,price2) VALUES (1001,"Iranizes",37,5987435,234724); +INSERT INTO t3 (period_,name,companynr,price,price2) VALUES (1002,"violinist",37,28357832,8723648); +INSERT INTO t3 (period_,name,companynr,price,price2) VALUES (1003,"extramarital",37,39654943,235872); +INSERT INTO t3 (period_,name,companynr,price,price2) VALUES (1004,"spates",78,726498,72987523); +INSERT INTO t3 (period_,name,companynr,price,price2) VALUES (1005,"cloakroom",78,98439034,823742); +INSERT INTO t3 (period_,name,companynr,price,price2) VALUES (1006,"gazer",101,834598,27348324); +INSERT INTO t3 (period_,name,companynr,price,price2) VALUES (1007,"hand",154,983543950,29837423); +INSERT INTO t3 (period_,name,companynr,price,price2) VALUES (1008,"tucked",311,234298,3275892); +INSERT INTO t3 (period_,name,companynr,price,price2) VALUES (1009,"gems",447,2374834,9872392); +INSERT INTO t3 (period_,name,companynr,price,price2) VALUES (1010,"clinker",512,786542,76234234); --enable_query_log create temporary table tmp engine = myisam select * from t3; @@ -1462,39 +1462,39 @@ explain select t3.t2nr,fld3 from t2,t3 where t2.companynr = 34 and t2.fld1=t3.t2 # Some test with ORDER BY and limit # -explain select * from t3 as t1,t3 where t1.period=t3.period order by t3.period; -explain select * from t3 as t1,t3 where t1.period=t3.period order by t3.period limit 10; -explain select * from t3 as t1,t3 where t1.period=t3.period order by t1.period limit 10; +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t3.period_; +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t3.period_ limit 10; +explain select * from t3 as t1,t3 where t1.period_=t3.period_ order by t1.period_ limit 10; # # Search with a constant table. # -select period from t1; -select period from t1 where period=1900; -select fld3,period from t1,t2 where fld1 = 011401 order by period; +select period_ from t1; +select period_ from t1 where period_=1900; +select fld3,period_ from t1,t2 where fld1 = 011401 order by period_; # # Search with a constant table and several keyparts. (Rows are read only once # in the beginning of the search) # -select fld3,period from t2,t3 where t2.fld1 = 011401 and t2.fld1=t3.t2nr and t3.period=1001; +select fld3,period_ from t2,t3 where t2.fld1 = 011401 and t2.fld1=t3.t2nr and t3.period_=1001; -explain select fld3,period from t2,t3 where t2.fld1 = 011401 and t3.t2nr=t2.fld1 and 1001 = t3.period; +explain select fld3,period_ from t2,t3 where t2.fld1 = 011401 and t3.t2nr=t2.fld1 and 1001 = t3.period_; # # Search with a constant table and several rows from another table # -select fld3,period from t2,t1 where companynr*10 = 37*10; +select fld3,period_ from t2,t1 where companynr*10 = 37*10; # # Search with a table reference and without a key. # t3 will be the main table. # -select fld3,period,price,price2 from t2,t3 where t2.fld1=t3.t2nr and period >= 1001 and period <= 1002 and t2.companynr = 37 order by fld3,period, price; +select fld3,period_,price,price2 from t2,t3 where t2.fld1=t3.t2nr and period_ >= 1001 and period_ <= 1002 and t2.companynr = 37 order by fld3,period_, price; # # Search with an interval on a table with full key on reference table. @@ -1502,7 +1502,7 @@ select fld3,period,price,price2 from t2,t3 where t2.fld1=t3.t2nr and period >= 1 # t2nr will be checked. # -select t2.fld1,fld3,period,price,price2 from t2,t3 where t2.fld1>= 18201 and t2.fld1 <= 18811 and t2.fld1=t3.t2nr and period = 1001 and t2.companynr = 37; +select t2.fld1,fld3,period_,price,price2 from t2,t3 where t2.fld1>= 18201 and t2.fld1 <= 18811 and t2.fld1=t3.t2nr and period_ = 1001 and t2.companynr = 37; # # We need another table for join stuff.. @@ -1594,18 +1594,18 @@ explain select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr= # each record # -select t2.fld1,t2.companynr,fld3,period from t3,t2 where t2.fld1 = 38208 and t2.fld1=t3.t2nr and period = 1008 or t2.fld1 = 38008 and t2.fld1 =t3.t2nr and period = 1008; +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where t2.fld1 = 38208 and t2.fld1=t3.t2nr and period_ = 1008 or t2.fld1 = 38008 and t2.fld1 =t3.t2nr and period_ = 1008; -select t2.fld1,t2.companynr,fld3,period from t3,t2 where (t2.fld1 = 38208 or t2.fld1 = 38008) and t2.fld1=t3.t2nr and period>=1008 and period<=1009; +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where (t2.fld1 = 38208 or t2.fld1 = 38008) and t2.fld1=t3.t2nr and period_>=1008 and period_<=1009; -select t2.fld1,t2.companynr,fld3,period from t3,t2 where (t3.t2nr = 38208 or t3.t2nr = 38008) and t2.fld1=t3.t2nr and period>=1008 and period<=1009; +select t2.fld1,t2.companynr,fld3,period_ from t3,t2 where (t3.t2nr = 38208 or t3.t2nr = 38008) and t2.fld1=t3.t2nr and period_>=1008 and period_<=1009; # # Test of many parenthesis levels # -select period from t1 where (((period > 0) or period < 10000 or (period = 1900)) and (period=1900 and period <= 1901) or (period=1903 and (period=1903)) and period>=1902) or ((period=1904 or period=1905) or (period=1906 or period>1907)) or (period=1908 and period = 1909); -select period from t1 where ((period > 0 and period < 1) or (((period > 0 and period < 100) and (period > 10)) or (period > 10)) or (period > 0 and (period > 5 or period > 6))); +select period_ from t1 where (((period_ > 0) or period_ < 10000 or (period_ = 1900)) and (period_=1900 and period_ <= 1901) or (period_=1903 and (period_=1903)) and period_>=1902) or ((period_=1904 or period_=1905) or (period_=1906 or period_>1907)) or (period_=1908 and period_ = 1909); +select period_ from t1 where ((period_ > 0 and period_ < 1) or (((period_ > 0 and period_ < 100) and (period_ > 10)) or (period_ > 10)) or (period_ > 0 and (period_ > 5 or period_ > 6))); select a.fld1 from t2 as a,t2 b where ((a.fld1 = 250501 and a.fld1=b.fld1) or a.fld1=250502 or a.fld1=250503 or (a.fld1=250505 and a.fld1<=b.fld1 and b.fld1>=a.fld1)) and a.fld1=b.fld1; @@ -1663,7 +1663,7 @@ select t2.fld1,count(*) from t2,t3 where t2.fld1=158402 and t3.name=t2.fld3 grou # Calculation with group functions # -select sum(Period)/count(*) from t1; +select sum(Period_)/count(*) from t1; select companynr,count(price) as "count",sum(price) as "sum" ,abs(sum(price)/count(price)-avg(price)) as "diff",(0+count(price))*companynr as func from t3 group by companynr; select companynr,sum(price)/count(price) as avg from t3 group by companynr having avg > 70000000 order by avg; @@ -1753,13 +1753,13 @@ select max(t2nr) from t3 where price=983543950; # Test of alias # -select t1.period from t3 = t1 limit 1; -select t1.period from t1 as t1 limit 1; -select t1.period as "Nuvarande period" from t1 as t1 limit 1; -select period as ok_period from t1 limit 1; -select period as ok_period from t1 group by ok_period limit 1; +select t1.period_ from t3 = t1 limit 1; +select t1.period_ from t1 as t1 limit 1; +select t1.period_ as "Nuvarande period_" from t1 as t1 limit 1; +select period_ as ok_period from t1 limit 1; +select period_ as ok_period from t1 group by ok_period limit 1; select 1+1 as summa from t1 group by summa limit 1; -select period as "Nuvarande period" from t1 group by "Nuvarande period" limit 1; +select period_ as "Nuvarande period_" from t1 group by "Nuvarande period_" limit 1; # # Some simple show commands @@ -4671,3 +4671,37 @@ select (SELECT name FROM t1 WHERE name='tom' AND pw=PASSWORD(@undefined)); drop table t1; --echo End of 10.0 tests + +--echo # +--echo # System Versioning Support +--echo # +--echo # +CREATE TABLE t1( x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; +INSERT INTO t1(x, y) VALUES + (0, 100), + (1, 101), + (2, 102), + (3, 103), + (4, 104), + (5, 105), + (6, 106), + (7, 107), + (8, 108), + (9, 109); +DELETE FROM t1 WHERE x = 3; +DELETE FROM t1 WHERE x > 7; +--real_sleep 1 +INSERT INTO t1(x, y) VALUES(3, 33); +--replace_column 1 Sys_start +SELECT @time := Sys_start FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07' WHERE x = 3 AND y = 33; +SELECT x, y FROM t1; +SET @query=CONCAT('SELECT x, y FROM t1 FOR SYSTEM_TIME FROM TIMESTAMP \'0-0-0 0:0:0\' TO TIMESTAMP \'', @time, '\''); +PREPARE stmt_t1 FROM @query; +EXECUTE stmt_t1; +SET @query=CONCAT('SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP \'0-0-0 0:0:0\' AND TIMESTAMP \'', @time, '\''); +PREPARE stmt_t1 FROM @query; +EXECUTE stmt_t1; +SET @time=NULL; +SET @query=NULL; +DEALLOCATE PREPARE stmt_t1; +DROP TABLE t1; diff --git a/mysql-test/t/update.test b/mysql-test/t/update.test index e5ef0b11127..5dfc623acc8 100644 --- a/mysql-test/t/update.test +++ b/mysql-test/t/update.test @@ -654,3 +654,42 @@ show status like 'Handler_read%'; drop table t1, t2; --echo # End of MariaDB 10.0 tests + +--echo # +--echo # System Versioning Support +--echo # +--echo # + +CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; +INSERT INTO t1(x, y) VALUES + (1, 1000), + (2, 2000), + (3, 3000), + (4, 4000), + (5, 5000), + (6, 6000), + (7, 7000), + (8, 8000), + (9, 9000); +SELECT x, y FROM t1; +UPDATE t1 SET y = y + 1 WHERE x > 7; +SELECT x, y FROM t1; +SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; +DROP TABLE t1; + +CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; +INSERT INTO t1(x, y) VALUES + (1, 1000), + (2, 2000), + (3, 3000), + (4, 4000), + (5, 5000), + (6, 6000), + (7, 7000), + (8, 8000), + (9, 9000); +SELECT x, y FROM t1; +UPDATE t1 SET y = y + 1 WHERE x > 7; +SELECT x, y FROM t1; +SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; +DROP TABLE t1; diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index 1ba20f0ac9e..1f65956f8ad 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -1295,166 +1295,6 @@ DROP TABLE t1; --echo End of 5.1 tests -########################################################################### - ---echo ---echo # ---echo # Bug#34828: OF is taken as OFF and a value of 0 is set for variable SQL_notes. ---echo # ---echo - ---echo # Checking sql_notes... -SET @sql_notes_saved = @@sql_notes; - ---echo -SET @@sql_notes = ON; -SELECT @@sql_notes; - ---echo ---error ER_WRONG_VALUE_FOR_VAR -SET @@sql_notes = OF; -SELECT @@sql_notes; - ---echo -SET @@sql_notes = OFF; -SELECT @@sql_notes; - ---echo -SET @@sql_notes = @sql_notes_saved; - ---echo ---echo # Checking delay_key_write... -SET @delay_key_write_saved = @@delay_key_write; - ---echo -SET GLOBAL delay_key_write = ON; -SELECT @@delay_key_write; - ---echo ---error ER_WRONG_VALUE_FOR_VAR -SET GLOBAL delay_key_write = OF; -SELECT @@delay_key_write; - ---echo ---error ER_WRONG_VALUE_FOR_VAR -SET GLOBAL delay_key_write = AL; -SELECT @@delay_key_write; - ---echo -SET GLOBAL delay_key_write = OFF; -SELECT @@delay_key_write; - ---echo -SET GLOBAL delay_key_write = ALL; -SELECT @@delay_key_write; - ---echo -SET GLOBAL delay_key_write = @delay_key_write_saved; - ---echo ---echo # Checking sql_safe_updates... -SET @sql_safe_updates_saved = @@sql_safe_updates; - ---echo -SET @@sql_safe_updates = ON; -SELECT @@sql_safe_updates; - ---echo ---error ER_WRONG_VALUE_FOR_VAR -SET @@sql_safe_updates = OF; -SELECT @@sql_safe_updates; - ---echo -SET @@sql_safe_updates = OFF; -SELECT @@sql_safe_updates; - ---echo -SET @@sql_safe_updates = @sql_safe_updates_saved; - ---echo ---echo # Checking foreign_key_checks... -SET @foreign_key_checks_saved = @@foreign_key_checks; - ---echo -SET @@foreign_key_checks = ON; -SELECT @@foreign_key_checks; - ---echo ---error ER_WRONG_VALUE_FOR_VAR -SET @@foreign_key_checks = OF; -SELECT @@foreign_key_checks; - ---echo -SET @@foreign_key_checks = OFF; -SELECT @@foreign_key_checks; - ---echo -SET @@foreign_key_checks = @foreign_key_checks_saved; - ---echo ---echo # Checking unique_checks... -SET @unique_checks_saved = @@unique_checks; - ---echo -SET @@unique_checks = ON; -SELECT @@unique_checks; - ---echo ---error ER_WRONG_VALUE_FOR_VAR -SET @@unique_checks = OF; -SELECT @@unique_checks; - ---echo -SET @@unique_checks = OFF; -SELECT @@unique_checks; - ---echo -SET @@unique_checks = @unique_checks_saved; - ---echo ---echo # Checking sql_buffer_result... -SET @sql_buffer_result_saved = @@sql_buffer_result; - ---echo -SET @@sql_buffer_result = ON; -SELECT @@sql_buffer_result; - ---echo ---error ER_WRONG_VALUE_FOR_VAR -SET @@sql_buffer_result = OF; -SELECT @@sql_buffer_result; - ---echo -SET @@sql_buffer_result = OFF; -SELECT @@sql_buffer_result; - ---echo -SET @@sql_buffer_result = @sql_buffer_result_saved; - ---echo ---echo # Checking sql_quote_show_create... -SET @sql_quote_show_create_saved = @@sql_quote_show_create; - ---echo -SET @@sql_quote_show_create = ON; -SELECT @@sql_quote_show_create; - ---echo ---error ER_WRONG_VALUE_FOR_VAR -SET @@sql_quote_show_create = OF; -SELECT @@sql_quote_show_create; - ---echo -SET @@sql_quote_show_create = OFF; -SELECT @@sql_quote_show_create; - ---echo -SET @@sql_quote_show_create = @sql_quote_show_create_saved; - ---echo ---echo # End of Bug#34828. ---echo - --echo # Make sure we can manipulate with autocommit in the --echo # along with other variables. diff --git a/sql/field.cc b/sql/field.cc index 812c4dbb639..cb91e93ec5e 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5423,6 +5423,22 @@ void Field_timestampf::store_TIME(my_time_t timestamp, ulong sec_part) my_timestamp_to_binary(&tm, ptr, dec); } +bool Field_timestampf::set_max_timestamp() +{ + DBUG_ENTER("Field_timestampf::set_max_timestamp"); + + mi_int4store(ptr, 0x7fffffff); + memset(ptr + 4, 0x0, value_length() - 4); + + DBUG_RETURN(FALSE); +} + +bool Field_timestampf::is_max_timestamp() +{ + DBUG_ENTER("Field_timestampf::is_max_timestamp"); + + DBUG_RETURN(mi_sint4korr(ptr) == 0x7fffffff); +} my_time_t Field_timestampf::get_timestamp(const uchar *pos, ulong *sec_part) const diff --git a/sql/field.h b/sql/field.h index 9559ba789b1..3513a773ef4 100644 --- a/sql/field.h +++ b/sql/field.h @@ -33,6 +33,8 @@ #include "compat56.h" #include "sql_type.h" /* Type_std_attributes */ +#include + class Send_field; class Copy_field; class Protocol; @@ -674,6 +676,19 @@ public: static void operator delete(void *ptr, MEM_ROOT *mem_root) { DBUG_ASSERT(0); } + /** + Is used by System Versioning. + */ + virtual bool set_max_timestamp() { + return true; + } + /** + Is used by System Versioning. + */ + virtual bool is_max_timestamp() { + return false; + } + uchar *ptr; // Position to field in record /** Byte where the @c NULL bit is stored inside a record. If this Field is a @@ -1391,6 +1406,56 @@ public: FIELD_FLAGS_COLUMN_FORMAT; } + /* + System versioning support. + */ + + bool is_generated() + { + return flags & (GENERATED_ROW_START_FLAG | GENERATED_ROW_END_FLAG); + } + + bool is_generated_row_start() + { + return flags & GENERATED_ROW_START_FLAG; + } + + bool is_generated_row_end() + { + return flags & GENERATED_ROW_END_FLAG; + } + + bool is_versioning_disabled() + { + return flags & WITHOUT_SYSTEM_VERSIONING_FLAG; + } + + /* Mark a field as auto-generated row start column. */ + void set_generated_row_start() + { + //DBUG_ASSERT((flags & GENERATED_ROW_END_FLAG) == 0); + flags |= GENERATED_ROW_START_FLAG; + } + + /* Mark a field as auto-generated row start column. */ + void set_generated_row_end() + { + //DBUG_ASSERT((flags & GENERATED_ROW_START_FLAG) == 0); + flags |= GENERATED_ROW_END_FLAG; + } + + /* Disable a field versioning for a versioned table. */ + void disable_versioning() + { + flags |= WITHOUT_SYSTEM_VERSIONING_FLAG; + } + + /* Inherit a field versioning status from the table. */ + void inherit_versioning() + { + flags &= ~WITHOUT_SYSTEM_VERSIONING_FLAG; + } + /* Validate a non-null field value stored in the given record according to the current thread settings, e.g. sql_mode. @@ -2517,6 +2582,8 @@ public: { return memcmp(a_ptr, b_ptr, pack_length()); } + virtual bool set_max_timestamp(); + virtual bool is_max_timestamp(); void store_TIME(my_time_t timestamp, ulong sec_part); my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const; uint size_of() const { return sizeof(*this); } diff --git a/sql/handler.h b/sql/handler.h index e6615695ce7..2b911cd94c5 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1660,6 +1660,36 @@ struct Schema_specification_st }; +struct System_versioning_info +{ + struct + { + String *start, *end; + } period_for_system_time; + + struct + { + String *start; + String *end; + } generated_as_row; + + void set_period_for_system_time(String *start, String *end) + { + period_for_system_time.start = start; + period_for_system_time.end = end; + } + void set_period_for_system_time() + { + set_period_for_system_time(NULL, NULL); + } + + /** User has added 'WITH SYSTEM VERSIONING' to table definition */ + bool declared_system_versioning; + + /** Table described by this structure have enabled system versioning */ + bool versioned; +}; + /** A helper struct for table DDL statements, e.g.: CREATE [OR REPLACE] [TEMPORARY] @@ -1734,6 +1764,8 @@ struct Table_scope_and_contents_source_st bool table_was_deleted; sequence_definition *seq_create_info; + System_versioning_info system_versioning_info; + void init() { bzero(this, sizeof(*this)); @@ -1744,6 +1776,17 @@ struct Table_scope_and_contents_source_st db_type= tmp_table() ? ha_default_tmp_handlerton(thd) : ha_default_handlerton(thd); } + + bool versioned() + { + return system_versioning_info.versioned; + } + const System_versioning_info *get_system_versioning_info() + { + if (!versioned()) + return NULL; + return &system_versioning_info; + } }; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 174f8ffb9fa..a1a9ca5c8ae 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1702,6 +1702,15 @@ void Item_func_curtime_utc::store_now_in_TIME(THD *thd, MYSQL_TIME *now_time) */ } + +Item_func_now::Item_func_now(THD *thd, uint dec) : + Item_datetimefunc(thd, new (thd->mem_root) Item_decimal(thd, dec, TRUE)), + last_query_id(0) +{ + decimals = dec; +} + + bool Item_func_now::fix_fields(THD *thd, Item **items) { if (decimals > TIME_SECOND_PART_DIGITS) diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 6ee565236c3..f1a719fb775 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -718,8 +718,7 @@ class Item_func_now :public Item_datetimefunc MYSQL_TIME ltime; query_id_t last_query_id; public: - Item_func_now(THD *thd, uint dec): Item_datetimefunc(thd), last_query_id(0) - { decimals= dec; } + Item_func_now(THD *thd, uint dec); bool fix_fields(THD *, Item **); bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); virtual void store_now_in_TIME(THD *thd, MYSQL_TIME *now_time)=0; diff --git a/sql/lex.h b/sql/lex.h index bb6ab1ca34d..da5a288be99 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -458,6 +458,7 @@ static SYMBOL symbols[] = { { "PAGE_CHECKSUM", SYM(PAGE_CHECKSUM_SYM)}, { "PARSER", SYM(PARSER_SYM)}, { "PARSE_VCOL_EXPR", SYM(PARSE_VCOL_EXPR_SYM)}, + { "PERIOD", SYM(PERIOD_SYM)}, { "PARTIAL", SYM(PARTIAL)}, { "PARTITION", SYM(PARTITION_SYM)}, { "PARTITIONING", SYM(PARTITIONING_SYM)}, @@ -625,6 +626,8 @@ static SYMBOL symbols[] = { { "SUSPEND", SYM(SUSPEND_SYM)}, { "SWAPS", SYM(SWAPS_SYM)}, { "SWITCHES", SYM(SWITCHES_SYM)}, + { "SYSTEM", SYM(SYSTEM)}, + { "SYSTEM_TIME", SYM(SYSTEM_TIME_SYM)}, { "TABLE", SYM(TABLE_SYM)}, { "TABLE_NAME", SYM(TABLE_NAME_SYM)}, { "TABLES", SYM(TABLES)}, @@ -690,6 +693,7 @@ static SYMBOL symbols[] = { { "VIA", SYM(VIA_SYM)}, { "VIEW", SYM(VIEW_SYM)}, { "VIRTUAL", SYM(VIRTUAL_SYM)}, + { "VERSIONING", SYM(VERSIONING)}, { "WAIT", SYM(WAIT_SYM)}, { "WARNINGS", SYM(WARNINGS)}, { "WEEK", SYM(WEEK_SYM)}, diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 562d0acdd19..380d992a89b 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7484,3 +7484,50 @@ ER_UNKNOWN_SEQUENCES 42S02 eng "Unknown SEQUENCE: '%-.300s'" ER_UNKNOWN_VIEW 42S02 eng "Unknown VIEW: '%-.300s'" + +# MariaDB error numbers related to System Versioning + +ER_SYS_START_NOT_SPECIFIED + eng "'Generated as row start' not specified" + +ER_SYS_END_NOT_SPECIFIED + eng "'Generated as row end' not specified" + +ER_SYS_START_MORE_THAN_ONCE + eng "'Generated as row start' specified more than once" + +ER_SYS_END_MORE_THAN_ONCE + eng "Generated as row end specified more than once" + +ER_MISSING_PERIOD_FOR_SYSTEM_TIME + eng "'Period for system time' is missing" + +ER_TABLE_DOESNT_SUPPORT_SYSTEM_VERSIONING + eng "Table '%s' doesn't support system versioning" + +ER_MISSING_WITH_SYSTEM_VERSIONING + eng "'With system versioning' is missing" + +ER_PERIOD_FOR_SYSTEM_TIME_CONTAINS_WRONG_START_COLUMN + eng "First column in 'period for system time' must be equal to 'generated as row start' column" + +ER_PERIOD_FOR_SYSTEM_TIME_CONTAINS_WRONG_END_COLUMN + eng "Second column in 'period for system time' must be equal to 'generated as row end' column" + +ER_SYS_START_AND_SYS_END_SAME + eng "'Period for system_time' must contain two different columns" + +ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER + eng "Generated field for System Versioning cannot be set by user" + +ER_FOREIGN_KEY_ON_SYSTEM_VERSIONED + eng "Foreign key clause is not yet supported in conjunction with system versioning" + +ER_UPDATE_INFO_WITH_SYSTEM_VERSIONING + eng "Rows matched: %ld Changed: %ld Inserted: %ld Warnings: %ld" + +ER_SYS_START_FIELD_MUST_BE_TIMESTAMP + eng "System start field must be of type TIMESTAMP" + +ER_SYS_END_FIELD_MUST_BE_TIMESTAMP + eng "System end field must be of type TIMESTAMP" diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 5f9c6ceabc7..1af45c12331 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7071,7 +7071,7 @@ bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array, thd->lex->current_select->is_item_list_lookup= 0; /* - To prevent fail on forward lookup we fill it with zerows, + To prevent fail on forward lookup we fill it with zeroes, then if we got pointer on zero after find_item_in_list we will know that it is forward lookup. @@ -7962,6 +7962,13 @@ fill_record(THD *thd, TABLE *table_arg, List &fields, List &values, ER_THD(thd, ER_WARNING_NON_DEFAULT_VALUE_FOR_VIRTUAL_COLUMN), rfield->field_name, table->s->table_name.str); } + if (table->versioned() && rfield->is_generated() && + !ignore_errors) + { + my_error(ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER, MYF(0)); + goto err; + } + if (rfield->stored_in_db() && (value->save_in_field(rfield, 0)) < 0 && !ignore_errors) { @@ -8002,7 +8009,7 @@ void switch_to_nullable_trigger_fields(List &items, TABLE *table) Field** field= table->field_to_fill(); /* True if we have NOT NULL fields and BEFORE triggers */ - if (field != table->field) + if (field != table->field && field != table->non_generated_field) { List_iterator_fast it(items); Item *item; @@ -8209,6 +8216,13 @@ fill_record(THD *thd, TABLE *table, Field **ptr, List &values, } } + if (table->versioned() && field->is_generated() && + !ignore_errors) + { + my_error(ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER, MYF(0)); + goto err; + } + if (use_value) value->save_val(field); else @@ -8460,7 +8474,6 @@ int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order) { List_iterator li(*(select_lex->ftfunc_list)); Item_func_match *ifm; - DBUG_PRINT("info",("Performing FULLTEXT search")); while ((ifm=li++)) ifm->init_search(thd, no_order); diff --git a/sql/sql_class.h b/sql/sql_class.h index 62974bb021e..82d538b07fd 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3906,7 +3906,12 @@ public: Lex_input_stream *lip= &m_parser_state->m_lip; if (!yytext) { - if (!(yytext= lip->get_tok_start())) + if (lip->lookahead_token >= 0) + yytext= lip->get_tok_start_prev(); + else + yytext= lip->get_tok_start(); + + if (!yytext) yytext= ""; } /* Push an error into the error stack */ @@ -5516,6 +5521,10 @@ class multi_update :public select_result_interceptor /* Need this to protect against multiple prepare() calls */ bool prepared; + + // For System Versioning (may need to insert new fields to a table). + ha_rows updated_sys_ver; + public: multi_update(THD *thd_arg, TABLE_LIST *ut, List *leaves_list, List *fields, List *values, diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index eb5f0d7a477..4983aafe9e9 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -343,7 +343,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, */ if (!with_select && !using_limit && const_cond_result && (!thd->is_current_stmt_binlog_format_row() && - !(table->triggers && table->triggers->has_delete_triggers()))) + !(table->triggers && table->triggers->has_delete_triggers())) + && !table->versioned()) { /* Update the table->file->stats.records number */ table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); @@ -559,6 +560,12 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, while (!(error=info.read_record(&info)) && !thd->killed && ! thd->is_error()) { + if (table->versioned() && + !table->vers_end_field()->is_max_timestamp()) + { + continue; + } + explain->tracker.on_record_read(); thd->inc_examined_row_count(1); if (table->vfield) @@ -580,7 +587,16 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, break; } - if (!(error= table->file->ha_delete_row(table->record[0]))) + if (!table->versioned()) + error= table->file->ha_delete_row(table->record[0]); + else + { + store_record(table,record[1]); + table->vers_end_field()->set_time(); + error= table->file->ha_update_row(table->record[1], + table->record[0]); + } + if (!error) { deleted++; if (table->triggers && @@ -1052,6 +1068,12 @@ int multi_delete::send_data(List &values) if (table->status & (STATUS_NULL_ROW | STATUS_DELETED)) continue; + if (table->versioned() && + !table->vers_end_field()->is_max_timestamp()) + { + continue; + } + table->file->position(table->record[0]); found++; @@ -1064,7 +1086,16 @@ int multi_delete::send_data(List &values) TRG_ACTION_BEFORE, FALSE)) DBUG_RETURN(1); table->status|= STATUS_DELETED; - if (!(error=table->file->ha_delete_row(table->record[0]))) + if (!table->versioned()) + error= table->file->ha_delete_row(table->record[0]); + else + { + store_record(table,record[1]); + table->vers_end_field()->set_time(); + error= table->file->ha_update_row(table->record[1], + table->record[0]); + } + if (!error) { deleted++; if (!table->file->has_transactions()) @@ -1243,8 +1274,16 @@ int multi_delete::do_table_deletes(TABLE *table, SORT_INFO *sort_info, local_error= 1; break; } - - local_error= table->file->ha_delete_row(table->record[0]); + + if (!table->versioned()) + local_error= table->file->ha_delete_row(table->record[0]); + else + { + store_record(table,record[1]); + table->vers_end_field()->set_time(); + local_error= table->file->ha_update_row(table->record[1], + table->record[0]); + } if (local_error && !ignore) { table->file->print_error(local_error, MYF(0)); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index f97732860ad..4787356c8b6 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -222,7 +222,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, table_list->view_db.str, table_list->view_name.str); DBUG_RETURN(-1); } - if (values.elements != table->s->fields) + if (values.elements != table->user_fields()) { my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), 1L); DBUG_RETURN(-1); @@ -1029,6 +1029,13 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, } } + if (table->versioned() && + table->vers_update_fields()) + { + error= 1; + break; + } + if ((res= table_list->view_check_option(thd, (values_list.elements == 1 ? 0 : @@ -1555,6 +1562,13 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, if (!table) table= table_list->table; + if (table->versioned() && duplic == DUP_REPLACE) + { + // Additional memory may be required to create historical items. + if (table_list->set_insert_values(thd->mem_root)) + DBUG_RETURN(TRUE); + } + if (!select_insert) { Item *fake_conds= 0; @@ -1605,6 +1619,31 @@ static int last_uniq_key(TABLE *table,uint keynr) } +/* + Inserts one historical row to a table. + + Copies content of the row from table->record[1] to table->record[0], + sets Sys_end to now() and calls ha_write_row() . +*/ + +int vers_insert_history_row(TABLE *table, ha_rows *inserted) +{ + DBUG_ASSERT(table->versioned()); + restore_record(table,record[1]); + + // Set Sys_end to now() + if (table->vers_end_field()->set_time()) + { + return 1; + } + + const int error= table->file->ha_write_row(table->record[0]); + if (!error) + ++*inserted; + + return error; +} + /* Write a record to table with optional deleting of conflicting records, invoke proper triggers if needed. @@ -1809,7 +1848,12 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) } if (error != HA_ERR_RECORD_IS_THE_SAME) + { info->updated++; + if (table->versioned() && + (error=vers_insert_history_row(table, &info->copied))) + goto err; + } else error= 0; /* @@ -1861,13 +1905,16 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) tables which have ON UPDATE but have no ON DELETE triggers, we just should not expose this fact to users by invoking ON UPDATE triggers. - */ - if (last_uniq_key(table,key_nr) && - !table->file->referenced_by_foreign_key() && - (!table->triggers || !table->triggers->has_delete_triggers())) + For system versioning wa also use path through delete since we would + save nothing through this cheating. + */ + if (last_uniq_key(table,key_nr) && + !table->file->referenced_by_foreign_key() && + (!table->triggers || !table->triggers->has_delete_triggers()) && + !table->versioned()) { if ((error=table->file->ha_update_row(table->record[1], - table->record[0])) && + table->record[0])) && error != HA_ERR_RECORD_IS_THE_SAME) goto err; if (error != HA_ERR_RECORD_IS_THE_SAME) @@ -1887,9 +1934,29 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) table->triggers->process_triggers(thd, TRG_EVENT_DELETE, TRG_ACTION_BEFORE, TRUE)) goto before_trg_err; - if ((error=table->file->ha_delete_row(table->record[1]))) + + if (!table->versioned()) + error= table->file->ha_delete_row(table->record[1]); + else + { + DBUG_ASSERT(table->insert_values); + store_record(table,insert_values); + restore_record(table,record[1]); + if (table->vers_end_field()->set_time()) + { + error= 1; + goto err; + } + error= table->file->ha_update_row(table->record[1], + table->record[0]); + restore_record(table,insert_values); + } + if (error) goto err; - info->deleted++; + if (!table->versioned()) + info->deleted++; + else + info->updated++; if (!table->file->has_transactions()) thd->transaction.stmt.modified_non_trans_table= TRUE; if (table->triggers && @@ -3732,6 +3799,9 @@ int select_insert::send_data(List &values) DBUG_RETURN(0); thd->count_cuted_fields= CHECK_FIELD_WARN; // Calculate cuted fields + if (table->versioned() && + table->vers_update_fields()) + DBUG_RETURN(1); store_values(values); if (table->default_field && table->update_default_fields(0, info.ignore)) DBUG_RETURN(1); @@ -3793,12 +3863,16 @@ int select_insert::send_data(List &values) void select_insert::store_values(List &values) { + DBUG_ENTER("select_insert::store_values"); + if (fields->elements) fill_record_n_invoke_before_triggers(thd, table, *fields, values, 1, TRG_EVENT_INSERT); else fill_record_n_invoke_before_triggers(thd, table, table->field_to_fill(), values, 1, TRG_EVENT_INSERT); + + DBUG_VOID_RETURN; } bool select_insert::prepare_eof() diff --git a/sql/sql_insert.h b/sql/sql_insert.h index aea0dac6b0d..a8794e7414b 100644 --- a/sql/sql_insert.h +++ b/sql/sql_insert.h @@ -37,6 +37,7 @@ void upgrade_lock_type_for_insert(THD *thd, thr_lock_type *lock_type, bool is_multi_insert); int check_that_all_fields_are_given_values(THD *thd, TABLE *entry, TABLE_LIST *table_list); +int vers_insert_history_row(TABLE *table, ha_rows *inserted); int write_record(THD *thd, TABLE *table, COPY_INFO *info); void kill_delayed_threads(void); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index a6796dcb901..c1281a2e022 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1343,6 +1343,27 @@ int MYSQLlex(YYSTYPE *yylval, THD *thd) return WITH; } break; + case FOR_SYM: + /* + * Additional look-ahead to resolve doubtful cases like: + * SELECT ... FOR UPDATE + * SELECT ... FOR SYSTEM_TIME ... . + */ + token= lex_one_token(yylval, thd); + lip->add_digest_token(token, yylval); + switch(token) { + case SYSTEM_TIME_SYM: + return FOR_SYSTEM_TIME_SYM; + default: + /* + Save the token following 'FOR_SYM' + */ + lip->lookahead_yylval= lip->yylval; + lip->yylval= NULL; + lip->lookahead_token= token; + return FOR_SYM; + } + break; default: break; } @@ -2998,8 +3019,7 @@ void Query_tables_list::destroy_query_tables_list() */ LEX::LEX() - : explain(NULL), - result(0), arena_for_set_stmt(0), mem_root_for_set_stmt(0), + : explain(NULL), result(0), arena_for_set_stmt(0), mem_root_for_set_stmt(0), option_type(OPT_DEFAULT), context_analysis_only(0), sphead(0), is_lex_started(0), limit_rows_examined_cnt(ULONGLONG_MAX) { diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 4257e77e2e8..a7fe77ca5a7 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3560,6 +3560,12 @@ public: SELECT_LEX *exclude_last_select(); bool add_unit_in_brackets(SELECT_LEX *nselect); void check_automatic_up(enum sub_select_type type); + + System_versioning_info *vers_get_info() + { + create_info.system_versioning_info.versioned = true; + return &create_info.system_versioning_info; + } }; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 077c57a953e..5484467509a 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -138,6 +138,7 @@ static void sql_kill_user(THD *thd, LEX_USER *user, killed_state state); static bool lock_tables_precheck(THD *thd, TABLE_LIST *tables); static bool execute_show_status(THD *, TABLE_LIST *); static bool check_rename_table(THD *, TABLE_LIST *, TABLE_LIST *); +static bool check_system_versioning(Table_scope_and_contents_source_st *); const char *any_db="*any*"; // Special symbol for check_access @@ -3849,6 +3850,9 @@ mysql_execute_command(THD *thd) */ Alter_info alter_info(lex->alter_info, thd->mem_root); + if (check_system_versioning(&create_info)) + goto end_with_restore_list; + if (thd->is_fatal_error) { /* If out of memory when creating a copy of alter_info. */ @@ -7319,6 +7323,66 @@ bool check_fk_parent_table_access(THD *thd, } + +/**************************************************************************** + Checks related to system versioning +****************************************************************************/ + +static bool check_system_versioning(Table_scope_and_contents_source_st *create_info) +{ + const System_versioning_info *versioning_info = &create_info->system_versioning_info; + + if (!versioning_info->versioned) + return false; + + bool r = false; + + if (!versioning_info->declared_system_versioning) + { + r = true; + my_error(ER_MISSING_WITH_SYSTEM_VERSIONING, MYF(0)); + } + + if (!versioning_info->generated_as_row.start) + { + r = true; + my_error(ER_SYS_START_NOT_SPECIFIED, MYF(0)); + } + + if (!versioning_info->generated_as_row.end) + { + r = true; + my_error(ER_SYS_END_NOT_SPECIFIED, MYF(0)); + } + + if (!versioning_info->period_for_system_time.start || !versioning_info->period_for_system_time.end) + { + r = true; + my_error(ER_MISSING_PERIOD_FOR_SYSTEM_TIME, MYF(0)); + } + + if (!r) + { + if (my_strcasecmp(system_charset_info, + versioning_info->generated_as_row.start->c_ptr(), + versioning_info->period_for_system_time.start->c_ptr())) + { + r = true; + my_error(ER_PERIOD_FOR_SYSTEM_TIME_CONTAINS_WRONG_START_COLUMN, MYF(0)); + } + + if (my_strcasecmp(system_charset_info, + versioning_info->generated_as_row.end->c_ptr(), + versioning_info->period_for_system_time.end->c_ptr())) + { + r = true; + my_error(ER_PERIOD_FOR_SYSTEM_TIME_CONTAINS_WRONG_END_COLUMN, MYF(0)); + } + } + + return r; // false means no error +} + /**************************************************************************** Check stack size; Send error if there isn't enough stack to continue ****************************************************************************/ diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a2e3d68e5dd..17e36390146 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -588,7 +588,7 @@ void remove_redundant_subquery_clauses(st_select_lex *subq_select_lex) subq_select_lex->group_list.empty(); DBUG_PRINT("info", ("GROUP BY removed")); } - + /* TODO: This would prevent processing quries with ORDER BY ... LIMIT therefore we disable this optimization for now. @@ -666,6 +666,77 @@ setup_without_group(THD *thd, Ref_ptr_array ref_pointer_array, DBUG_RETURN(res); } +static int +setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **conds, SELECT_LEX *select_lex) +{ + DBUG_ENTER("setup_for_system_time"); + + TABLE_LIST *table; + int versioned_tables= 0; + + for (table= tables; table; table= table->next_local) + { + if (table->table && table->table->versioned()) + versioned_tables++; + else if (table->system_versioning.type != FOR_SYSTEM_TIME_UNSPECIFIED) + { + my_error(ER_TABLE_DOESNT_SUPPORT_SYSTEM_VERSIONING, MYF(0), table->table_name); + DBUG_RETURN(-1); + } + } + + if (versioned_tables == 0) + DBUG_RETURN(0); + + for (table= tables; table; table= table->next_local) + { + if (table->table && table->table->versioned()) + { + Field *fstart= table->table->vers_start_field(); + Field *fend= table->table->vers_end_field(); + Item *istart= new (thd->mem_root) Item_field(thd, fstart); + Item *iend= new (thd->mem_root) Item_field(thd, fend); + Item *cond1= 0, *cond2= 0, *curr = 0; + switch (table->system_versioning.type) + { + case FOR_SYSTEM_TIME_UNSPECIFIED: + curr= new (thd->mem_root) Item_func_now_local(thd, 6); + cond1= new (thd->mem_root) Item_func_le(thd, istart, curr); + cond2= new (thd->mem_root) Item_func_gt(thd, iend, curr); + break; + case FOR_SYSTEM_TIME_AS_OF: + cond1= new (thd->mem_root) Item_func_le(thd, istart, + table->system_versioning.start); + cond2= new (thd->mem_root) Item_func_gt(thd, iend, + table->system_versioning.start); + break; + case FOR_SYSTEM_TIME_FROM_TO: + cond1= new (thd->mem_root) Item_func_lt(thd, istart, + table->system_versioning.end); + cond2= new (thd->mem_root) Item_func_ge(thd, iend, + table->system_versioning.start); + break; + case FOR_SYSTEM_TIME_BETWEEN: + cond1= new (thd->mem_root) Item_func_le(thd, istart, + table->system_versioning.end); + cond2= new (thd->mem_root) Item_func_ge(thd, iend, + table->system_versioning.start); + break; + default: + DBUG_ASSERT(0); + } + if (cond1 && cond2) + { + COND *system_time_cond= new (thd->mem_root) Item_cond_and(thd, cond1, cond2); + thd->change_item_tree(conds, and_items(thd, *conds, system_time_cond)); + table->system_versioning.is_moved_to_where= true; + } + } + } + + DBUG_RETURN(0); +} + /***************************************************************************** Check fields, find best join, do the select and output fields. mysql_select assumes that all tables are already opened @@ -740,7 +811,11 @@ JOIN::prepare(TABLE_LIST *tables_init, { remove_redundant_subquery_clauses(select_lex); } - + + /* Handle FOR SYSTEM_TIME clause. */ + if (setup_for_system_time(thd, tables_list, &conds, select_lex) < 0) + DBUG_RETURN(-1); + /* TRUE if the SELECT list mixes elements with and without grouping, and there is no GROUP BY clause. Mixing non-aggregated fields with @@ -24784,6 +24859,38 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result) DBUG_RETURN(res || thd->is_error()); } +void TABLE_LIST::print_system_versioning(THD *thd, table_map eliminated_tables, + String *str, enum_query_type query_type) +{ + if (system_versioning.is_moved_to_where) + return; + + // system versioning + if (system_versioning.type != FOR_SYSTEM_TIME_UNSPECIFIED) + { + switch (system_versioning.type) + { + case FOR_SYSTEM_TIME_AS_OF: + str->append(STRING_WITH_LEN(" for system_time as of ")); + system_versioning.start->print(str, query_type); + break; + case FOR_SYSTEM_TIME_FROM_TO: + str->append(STRING_WITH_LEN(" for system_time from timestamp ")); + system_versioning.start->print(str, query_type); + str->append(STRING_WITH_LEN(" to ")); + system_versioning.end->print(str, query_type); + break; + case FOR_SYSTEM_TIME_BETWEEN: + str->append(STRING_WITH_LEN(" for system_time between timestamp ")); + system_versioning.start->print(str, query_type); + str->append(STRING_WITH_LEN(" and ")); + system_versioning.end->print(str, query_type); + break; + default: + DBUG_ASSERT(0); + } + } +} static void print_table_array(THD *thd, table_map eliminated_tables, @@ -25119,6 +25226,8 @@ void TABLE_LIST::print(THD *thd, table_map eliminated_tables, String *str, append_identifier(thd, str, t_alias, strlen(t_alias)); } + print_system_versioning(thd, eliminated_tables, str, query_type); + if (index_hints) { List_iterator it(*index_hints); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 01f474a73fb..e3613c1e0e7 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1666,6 +1666,7 @@ static bool get_field_default_value(THD *thd, Field *field, String *def_value, has_default= (field->default_value || (!(field->flags & NO_DEFAULT_VALUE_FLAG) && + !field->is_generated() && field->unireg_check != Field::NEXT_NUMBER)); def_value->length(0); @@ -2123,6 +2124,14 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, packet->append(STRING_WITH_LEN(" DEFAULT ")); packet->append(def_value.ptr(), def_value.length(), system_charset_info); } + else if (field->is_generated_row_start()) + { + packet->append(STRING_WITH_LEN(" GENERATED AS ROW START")); + } + else if (field->is_generated_row_end()) + { + packet->append(STRING_WITH_LEN(" GENERATED AS ROW END")); + } if (!limited_mysql_mode && print_on_update_clause(field, &def_value, false)) @@ -2215,6 +2224,17 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, hton->index_options); } + if (table->versioned()) + { + const Field *fs = table->vers_start_field(); + const Field *fe = table->vers_end_field(); + packet->append(STRING_WITH_LEN(",\n PERIOD FOR SYSTEM_TIME (")); + append_identifier(thd,packet,fs->field_name, strlen(fs->field_name)); + packet->append(STRING_WITH_LEN(", ")); + append_identifier(thd,packet,fe->field_name, strlen(fe->field_name)); + packet->append(STRING_WITH_LEN(")")); + } + /* Get possible foreign key definitions stored in InnoDB and append them to the CREATE TABLE statement @@ -2253,6 +2273,11 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, add_table_options(thd, table, create_info_arg, table_list->schema_table != 0, 0, packet); + if (table->versioned()) + { + packet->append(STRING_WITH_LEN(" WITH SYSTEM VERSIONING")); + } + #ifdef WITH_PARTITION_STORAGE_ENGINE { if (table->part_info && diff --git a/sql/sql_table.cc b/sql/sql_table.cc index bfc198a1a68..3913b14ccc8 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3046,10 +3046,12 @@ void promote_first_timestamp_column(List *column_definitions) if (is_timestamp_type(column_definition->sql_type) || // TIMESTAMP column_definition->unireg_check == Field::TIMESTAMP_OLD_FIELD) // Legacy { + DBUG_PRINT("info", ("field-ptr:%p", column_definition->field)); if ((column_definition->flags & NOT_NULL_FLAG) != 0 && // NOT NULL, column_definition->default_value == NULL && // no constant default, column_definition->unireg_check == Field::NONE && // no function default - column_definition->vcol_info == NULL) + column_definition->vcol_info == NULL && + !(column_definition->flags & (GENERATED_ROW_START_FLAG | GENERATED_ROW_END_FLAG))) // column isn't generated { DBUG_PRINT("info", ("First TIMESTAMP column '%s' was promoted to " "DEFAULT CURRENT_TIMESTAMP ON UPDATE " @@ -3144,6 +3146,39 @@ static void check_duplicate_key(THD *thd, Key *key, KEY *key_info, } } +static void +copy_info_about_generated_fields(Alter_info *dst_alter_info, + HA_CREATE_INFO *src_create_info) +{ + if (!src_create_info->versioned()) + return; + + const System_versioning_info *versioning_info = + src_create_info->get_system_versioning_info(); + DBUG_ASSERT(versioning_info); + const char *row_start_field = versioning_info->generated_as_row.start->c_ptr(); + DBUG_ASSERT(row_start_field); + const char *row_end_field = versioning_info->generated_as_row.end->c_ptr(); + DBUG_ASSERT(row_end_field); + + List_iterator it(dst_alter_info->create_list); + Create_field *column_definition = NULL; + while ( (column_definition = it++) ) + { + if (!my_strcasecmp(system_charset_info, + row_start_field, + column_definition->field_name)) + { + column_definition->flags |= GENERATED_ROW_START_FLAG; + } + else if (!my_strcasecmp(system_charset_info, + row_end_field, + column_definition->field_name)) + { + column_definition->flags |= GENERATED_ROW_END_FLAG; + } + } +} /* Preparation for table creation @@ -3212,6 +3247,9 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, } select_field_pos= alter_info->create_list.elements - select_field_count; + const System_versioning_info *versioning_info = + create_info->get_system_versioning_info(); + for (field_no=0; (sql_field=it++) ; field_no++) { CHARSET_INFO *save_cs; @@ -3437,6 +3475,23 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, */ if (sql_field->stored_in_db()) record_offset+= sql_field->pack_length; + + if (versioning_info) + { + const bool is_generated_as_row_start = + !my_strcasecmp(system_charset_info, + versioning_info->generated_as_row.start->c_ptr(), + sql_field->field_name); + const bool is_generated_as_row_end = + !my_strcasecmp(system_charset_info, + versioning_info->generated_as_row.end->c_ptr(), + sql_field->field_name); + if (is_generated_as_row_start && is_generated_as_row_end) + { + my_error(ER_SYS_START_AND_SYS_END_SAME, MYF(0), sql_field->field_name); + DBUG_RETURN(TRUE); + } + } } /* Update virtual fields' offset*/ it.rewind(); @@ -4285,6 +4340,58 @@ bool Column_definition::sp_prepare_create_field(THD *thd, MEM_ROOT *mem_root) } +static bool +prepare_keys_for_sys_ver(THD *thd, + HA_CREATE_INFO *create_info, + Alter_info *alter_info, + KEY **key_info, + uint key_count) +{ + if (!create_info->versioned()) + return false; + + const System_versioning_info *versioning_info= + create_info->get_system_versioning_info(); + + DBUG_ASSERT(versioning_info); + const char *row_start_field= versioning_info->generated_as_row.start->c_ptr(); + DBUG_ASSERT(row_start_field); + const char *row_end_field= versioning_info->generated_as_row.end->c_ptr(); + DBUG_ASSERT(row_end_field); + + List_iterator key_it(alter_info->key_list); + Key *key= NULL; + while ((key=key_it++)) + { + if (key->type != Key::PRIMARY && key->type != Key::UNIQUE) + continue; + + Key_part_spec *key_part= NULL; + List_iterator part_it(key->columns); + while ((key_part=part_it++)) + { + if (!my_strcasecmp(system_charset_info, + row_start_field, + key_part->field_name.str) || + + !my_strcasecmp(system_charset_info, + row_end_field, + key_part->field_name.str)) + break; + } + if (key_part) + continue; // Key already contains Sys_start or Sys_end + + const LEX_STRING &lex_sys_end= + versioning_info->generated_as_row.end->lex_string(); + Key_part_spec *key_part_sys_end_col= + new(thd->mem_root) Key_part_spec(lex_sys_end, 0); + key->columns.push_back(key_part_sys_end_col); + } + + return false; +} + handler *mysql_create_frm_image(THD *thd, const char *db, const char *table_name, HA_CREATE_INFO *create_info, @@ -4522,6 +4629,27 @@ handler *mysql_create_frm_image(THD *thd, } #endif + if (create_info->versioned()) + { + // FIXME: This test doesn't detect foreign key relationship on the side of + // parent table and System Time support will not work correctly for such + // table either. But this cannot be implemented without changes to innodb + // that are postponed for later time. + List_iterator_fast key_iterator(alter_info->key_list); + Key *key; + while ((key= key_iterator++)) + { + if (key->type == Key::FOREIGN_KEY) + { + my_error(ER_FOREIGN_KEY_ON_SYSTEM_VERSIONED, MYF(0)); + goto err; + } + } + if(prepare_keys_for_sys_ver(thd, create_info, alter_info, key_info, + *key_count)) + goto err; + } + if (mysql_prepare_create_table(thd, create_info, alter_info, &db_options, file, key_info, key_count, create_table_mode)) @@ -4952,6 +5080,8 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, else create_table_mode= C_ASSISTED_DISCOVERY; + copy_info_about_generated_fields(alter_info, create_info); + if (!opt_explicit_defaults_for_timestamp) promote_first_timestamp_column(&alter_info->create_list); diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h index 9d1c79cc7cf..f1e2135ce93 100644 --- a/sql/sql_trigger.h +++ b/sql/sql_trigger.h @@ -309,7 +309,7 @@ private: inline Field **TABLE::field_to_fill() { return triggers && triggers->nullable_fields() ? triggers->nullable_fields() - : field; + : non_generated_field ? non_generated_field : field; } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 35e1fe24b97..79cabf180a9 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -44,6 +44,9 @@ // mysql_derived_filling +#include "sql_insert.h" // For vers_insert_history_row() that may be + // needed for System Versioning. + /** True if the table's input and output record buffers are comparable using compare_record(TABLE*). @@ -280,6 +283,10 @@ int mysql_update(THD *thd, Explain_update *explain; query_plan.index= MAX_KEY; query_plan.using_filesort= FALSE; + + // For System Versioning (may need to insert new fields to a table). + ha_rows updated_sys_ver= 0; + DBUG_ENTER("mysql_update"); create_explain_query(thd->lex, thd->mem_root); @@ -354,6 +361,9 @@ int mysql_update(THD *thd, DBUG_RETURN(1); } + if (table->default_field) + table->mark_default_fields_for_write(false); + #ifndef NO_EMBEDDED_ACCESS_CHECKS /* Check values */ table_list->grant.want_privilege= table->grant.want_privilege= @@ -734,6 +744,11 @@ int mysql_update(THD *thd, while (!(error=info.read_record(&info)) && !thd->killed) { + if (table->versioned() && !table->vers_end_field()->is_max_timestamp()) + { + continue; + } + explain->tracker.on_record_read(); thd->inc_examined_row_count(1); if (!select || select->skip_record(thd) > 0) @@ -743,10 +758,17 @@ int mysql_update(THD *thd, explain->tracker.on_record_after_where(); store_record(table,record[1]); + if (fill_record_n_invoke_before_triggers(thd, table, fields, values, 0, TRG_EVENT_UPDATE)) break; /* purecov: inspected */ + if (table->versioned() && table->vers_update_fields()) + { + error= 1; + break; + } + found++; if (!can_compare_record || compare_record(table)) @@ -805,19 +827,29 @@ int mysql_update(THD *thd, else { /* Non-batched update */ - error= table->file->ha_update_row(table->record[1], + error= table->file->ha_update_row(table->record[1], table->record[0]); } - if (!error || error == HA_ERR_RECORD_IS_THE_SAME) - { - if (error != HA_ERR_RECORD_IS_THE_SAME) - updated++; - else - error= 0; - } - else if (!ignore || + if (error == HA_ERR_RECORD_IS_THE_SAME) + { + error= 0; + } + else if (!error) + { + updated++; + + if (table->versioned()) + { + store_record(table, record[2]); + if ((error = vers_insert_history_row(table, &updated_sys_ver))) + break; + + restore_record(table, record[2]); + } + } + else if (!ignore || table->file->is_fatal_error(error, HA_CHECK_ALL)) - { + { /* If (ignore && error is ignorable) we don't have to do anything; otherwise... @@ -1007,9 +1039,15 @@ int mysql_update(THD *thd, if (error < 0 && !thd->lex->analyze_stmt) { char buff[MYSQL_ERRMSG_SIZE]; - my_snprintf(buff, sizeof(buff), ER_THD(thd, ER_UPDATE_INFO), (ulong) found, - (ulong) updated, - (ulong) thd->get_stmt_da()->current_statement_warn_count()); + if (!table->versioned()) + my_snprintf(buff, sizeof(buff), ER_THD(thd, ER_UPDATE_INFO), (ulong) found, + (ulong) updated, + (ulong) thd->get_stmt_da()->current_statement_warn_count()); + else + my_snprintf(buff, sizeof(buff), + ER_THD(thd, ER_UPDATE_INFO_WITH_SYSTEM_VERSIONING), + (ulong) found, (ulong) updated, (ulong) updated_sys_ver, + (ulong) thd->get_stmt_da()->current_statement_warn_count()); my_ok(thd, (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated, id, buff); DBUG_PRINT("info",("%ld records updated", (long) updated)); @@ -1627,8 +1665,10 @@ multi_update::multi_update(THD *thd_arg, TABLE_LIST *table_list, tmp_tables(0), updated(0), found(0), fields(field_list), values(value_list), table_count(0), copy_field(0), handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(1), - transactional_tables(0), ignore(ignore_arg), error_handled(0), prepared(0) -{} + transactional_tables(0), ignore(ignore_arg), error_handled(0), prepared(0), + updated_sys_ver(0) +{ +} /* @@ -1877,7 +1917,7 @@ static bool safe_update_on_fly(THD *thd, JOIN_TAB *join_tab, return !is_key_used(table, table->s->primary_key, table->write_set); return TRUE; default: - break; // Avoid compler warning + break; // Avoid compiler warning } return FALSE; @@ -2097,6 +2137,11 @@ int multi_update::send_data(List ¬_used_values) if (table->status & (STATUS_NULL_ROW | STATUS_UPDATED)) continue; + if (table->versioned() && !table->vers_end_field()->is_max_timestamp()) + { + continue; + } + if (table == table_to_update) { /* @@ -2109,6 +2154,7 @@ int multi_update::send_data(List ¬_used_values) table->status|= STATUS_UPDATED; store_record(table,record[1]); + if (fill_record_n_invoke_before_triggers(thd, table, *fields_for_table[offset], *values_for_table[offset], 0, @@ -2127,6 +2173,13 @@ int multi_update::send_data(List ¬_used_values) if (table->default_field && table->update_default_fields(1, ignore)) DBUG_RETURN(1); + if (table->versioned() && + table->vers_update_fields()) + { + error= 1; + break; + } + if ((error= cur_table->view_check_option(thd, ignore)) != VIEW_CHECK_OK) { @@ -2174,6 +2227,23 @@ int multi_update::send_data(List ¬_used_values) error= 0; updated--; } + else if (table->versioned()) + { + restore_record(table,record[1]); + + // Set end time to now() + if (table->vers_end_field()->set_time()) + { + error= 1; + break; + } + + if ( (error= vers_insert_history_row(table, &updated_sys_ver)) ) + { + error= 1; + break; + } + } /* non-transactional or transactional table got modified */ /* either multi_update class' flag is raised in its branch */ if (table->file->has_transactions()) @@ -2200,6 +2270,7 @@ int multi_update::send_data(List ¬_used_values) */ uint field_num= 0; List_iterator_fast tbl_it(unupdated_check_opt_tables); + /* Set first tbl = table and then tbl to tables from tbl_it */ TABLE *tbl= table; do { @@ -2262,10 +2333,6 @@ void multi_update::abort_result_set() if (do_update && table_count > 1) { /* Add warning here */ - /* - todo/fixme: do_update() is never called with the arg 1. - should it change the signature to become argless? - */ (void) do_updates(); } } @@ -2447,19 +2514,44 @@ int multi_update::do_updates() goto err2; } } - if ((local_error=table->file->ha_update_row(table->record[1], - table->record[0])) && + if (table->versioned() && + table->vers_update_fields()) + { + goto err2; + } + + if ((local_error=table->file->ha_update_row(table->record[1], + table->record[0])) && local_error != HA_ERR_RECORD_IS_THE_SAME) { if (!ignore || table->file->is_fatal_error(local_error, HA_CHECK_ALL)) { err_table= table; - goto err; + goto err; } - } + } if (local_error != HA_ERR_RECORD_IS_THE_SAME) + { updated++; + + if (table->versioned()) + { + restore_record(table,record[1]); + + // Set end time to now() + if (table->vers_end_field()->set_time()) + { + goto err2; + } + + if ( (local_error= vers_insert_history_row(table, &updated_sys_ver)) ) + { + err_table = table; + goto err; + } + } + } else local_error= 0; } diff --git a/sql/sql_view.cc b/sql/sql_view.cc index fb4c2c3d835..08f42e9ce70 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -2010,7 +2010,7 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) RETURN FALSE OK - TRUE error (is not sent to cliet) + TRUE error (is not sent to client) */ bool insert_view_fields(THD *thd, List *list, TABLE_LIST *view) @@ -2038,7 +2038,7 @@ bool insert_view_fields(THD *thd, List *list, TABLE_LIST *view) } /* - checking view md5 check suum + checking view md5 check sum SINOPSYS view_checksum() diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 47c3882bba1..6b09055e323 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -758,6 +758,7 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr) uint sp_instr_addr; /* structs */ + system_versioning_for_select system_versioning; LEX_STRING lex_str; LEX_SYMBOL symbol; Lex_string_with_metadata_st lex_string_with_metadata; @@ -859,10 +860,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %parse-param { THD *thd } %lex-param { THD *thd } /* - Currently there are 103 shift/reduce conflicts. + Currently there are 106 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 103 +%expect 106 /* Comments for TOKENS. @@ -878,6 +879,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); INTERNAL : Not a real token, lex optimization OPERATOR : SQL operator FUTURE-USE : Reserved for future use + 32N2439 : Reserver keywords per ISO/IEC PDTR 19075-2, + http://jtc1sc32.org/doc/N2401-2450/32N2439-text_for_ballot-PDTR_19075-2.pdf + System Versioned Tables This makes the code grep-able, and helps maintenance. */ @@ -1090,6 +1094,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token FORCE_SYM %token FOREIGN /* SQL-2003-R */ %token FOR_SYM /* SQL-2003-R */ +%token FOR_SYSTEM_TIME_SYM /* internal */ %token FORMAT_SYM %token FOUND_SYM /* SQL-2003-R */ %token FROM @@ -1320,6 +1325,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token PARTITIONING_SYM %token PASSWORD_SYM %token PERCENT_RANK_SYM +%token PERIOD_SYM /* 32N2439 */ %token PERSISTENT_SYM %token PHASE_SYM %token PLUGINS_SYM @@ -1484,6 +1490,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token SWAPS_SYM %token SWITCHES_SYM %token SYSDATE +%token SYSTEM /* 32N2439 */ +%token SYSTEM_TIME_SYM /* 32N2439 */ %token TABLES %token TABLESPACE %token TABLE_REF_PRIORITY @@ -1552,6 +1560,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token VARIANCE_SYM %token VARYING /* SQL-2003-R */ %token VAR_SAMP_SYM +%token VERSIONING /* 32N2439 */ %token VIA_SYM %token VIEW_SYM /* SQL-2003-N */ %token VIRTUAL_SYM @@ -1638,6 +1647,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type text_string hex_or_bin_String opt_gconcat_separator + period_for_system_time_column_id %type int_type real_type @@ -1885,6 +1895,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); keep_gcc_happy key_using_alg part_column_list + period_for_system_time server_def server_options_list server_option definer_opt no_definer definer get_diagnostics parse_vcol_expr vcol_opt_specifier vcol_opt_attribute @@ -1908,6 +1919,7 @@ END_OF_INPUT %type sp_decl_idents sp_decl_idents_init_vars %type sp_handler_type sp_hcond_list +%type start_or_end %type sp_cond sp_hcond sqlstate signal_value opt_signal_value %type sp_decls sp_decl sp_decl_body sp_decl_variable_list %type sp_name @@ -1942,7 +1954,7 @@ END_OF_INPUT %type window_frame_extent; %type opt_window_frame_exclusion; %type window_frame_start window_frame_bound; - +%type opt_for_system_time_clause; %type '-' '+' '*' '/' '%' '(' ')' @@ -5837,6 +5849,13 @@ create_table_option: { Lex->create_info.used_fields|= HA_CREATE_USED_SEQUENCE; Lex->create_info.sequence= $3; + } + | WITH SYSTEM VERSIONING + { + System_versioning_info *info = Lex->vers_get_info(); + if (!info) + MYSQL_YYABORT; + info->declared_system_versioning = true; } ; @@ -5937,6 +5956,7 @@ field_list_item: column_def { } | key_def | constraint_def + | period_for_system_time ; column_def: @@ -6036,6 +6056,22 @@ constraint_def: } ; +period_for_system_time: + // If FOR_SYM is followed by SYSTEM_TIME_SYM then they are merged to: FOR_SYSTEM_TIME_SYM . + PERIOD_SYM FOR_SYSTEM_TIME_SYM '(' period_for_system_time_column_id ',' period_for_system_time_column_id ')' + { + System_versioning_info *info = Lex->vers_get_info(); + if (!info) + MYSQL_YYABORT; + if (!my_strcasecmp(system_charset_info, $4->c_ptr(), $6->c_ptr())) + { + my_error(ER_SYS_START_AND_SYS_END_SAME, MYF(0), $4->c_ptr()); + MYSQL_YYABORT; + } + info->set_period_for_system_time($4, $6); + } + ; + opt_check_constraint: /* empty */ { $$= (Virtual_column_info*) 0; } | check_constraint { $$= $1;} @@ -6130,6 +6166,46 @@ field_def: Lex->last_field->flags&= ~NOT_NULL_FLAG; // undo automatic NOT NULL for timestamps } vcol_opt_specifier vcol_opt_attribute + | opt_generated_always AS ROW_SYM start_or_end + { + System_versioning_info *info = + Lex->vers_get_info(); + if (!info) + MYSQL_YYABORT; + String *field_name = new (thd->mem_root) + String((const char*)Lex->last_field->field_name, system_charset_info); + if (!field_name) + MYSQL_YYABORT; + + String **p = NULL; + int err_nr = 0; + switch ($4) + { + case 1: + p = &info->generated_as_row.start; + err_nr = ER_SYS_START_MORE_THAN_ONCE; + break; + case 0: + p = &info->generated_as_row.end; + err_nr = ER_SYS_END_MORE_THAN_ONCE; + break; + default: + /* Not Reachable */ + MYSQL_YYABORT; + break; + } + if (*p) + { + my_error(err_nr, MYF(0), field_name->c_ptr()); + MYSQL_YYABORT; + } + *p = field_name; + } + ; + +start_or_end: + START_SYM { $$ = 1; } + | END { $$ = 0; } ; opt_generated_always: @@ -7535,6 +7611,9 @@ alter_list_item: Lex->create_last_non_select_table= Lex->last_table(); Lex->alter_info.flags|= Alter_info::ALTER_ADD_INDEX; } + | ADD period_for_system_time + { + } | add_column '(' create_field_list ')' { Lex->alter_info.flags|= Alter_info::ALTER_ADD_COLUMN | @@ -8587,6 +8666,60 @@ select_options: } ; +opt_for_system_time_clause: + /* empty */ + { + $$.init(); + } + | FOR_SYSTEM_TIME_SYM + AS OF_SYM + TIMESTAMP TEXT_STRING + { + Item *item= create_temporal_literal(thd, $5.str, $5.length, YYCSCL, + MYSQL_TYPE_DATETIME, true); + if (item == NULL) + MYSQL_YYABORT; + $$.init(FOR_SYSTEM_TIME_AS_OF, item); + } + | FOR_SYSTEM_TIME_SYM + AS OF_SYM + NOW_SYM + { + Item *item= new (thd->mem_root) Item_func_now_local(thd, 6); + if (item == NULL) + MYSQL_YYABORT; + $$.init(FOR_SYSTEM_TIME_AS_OF, item); + } + | FOR_SYSTEM_TIME_SYM + FROM + TIMESTAMP TEXT_STRING + TO_SYM + TIMESTAMP TEXT_STRING + { + Item *item1= create_temporal_literal(thd, $4.str, $4.length, YYCSCL, + MYSQL_TYPE_DATETIME, true); + Item *item2= create_temporal_literal(thd, $7.str, $7.length, YYCSCL, + MYSQL_TYPE_DATETIME, true); + if (item1 == NULL || item2 == NULL) + MYSQL_YYABORT; + $$.init(FOR_SYSTEM_TIME_FROM_TO, item1, item2); + } + | FOR_SYSTEM_TIME_SYM + BETWEEN_SYM + TIMESTAMP TEXT_STRING + AND_SYM + TIMESTAMP TEXT_STRING + { + Item *item1= create_temporal_literal(thd, $4.str, $4.length, YYCSCL, + MYSQL_TYPE_DATETIME, true); + Item *item2= create_temporal_literal(thd, $7.str, $7.length, YYCSCL, + MYSQL_TYPE_DATETIME, true); + if (item1 == NULL || item2 == NULL) + MYSQL_YYABORT; + $$.init(FOR_SYSTEM_TIME_BETWEEN, item1, item2); + } + ; + select_option_list: select_option_list select_option | select_option @@ -10994,7 +11127,7 @@ table_primary_ident: SELECT_LEX *sel= Select; sel->table_join_options= 0; } - table_ident opt_use_partition opt_table_alias opt_key_definition + table_ident opt_use_partition opt_table_alias opt_key_definition opt_for_system_time_clause { if (!($$= Select->add_table_to_list(thd, $2, $4, Select->get_table_join_options(), @@ -11004,6 +11137,7 @@ table_primary_ident: $3))) MYSQL_YYABORT; Select->add_joined_table($$); + $$->system_versioning= $6; } ; @@ -15891,6 +16025,16 @@ column_list: | column_list_id ; +period_for_system_time_column_id: + ident + { + String *new_str= new (thd->mem_root) String((const char*) $1.str,$1.length,system_charset_info); + if (new_str == NULL) + MYSQL_YYABORT; + $$= new_str; + } + ; + column_list_id: ident { @@ -16537,7 +16681,12 @@ trigger_tail: FOR_SYM remember_name /* $13 */ { /* $14 */ - Lex->raw_trg_on_table_name_end= YYLIP->get_tok_start(); + /* + FOR token is already passed through (see 'case FOR_SYM' in sql_lex.cc), + so we use _prev() to get it back. + */ + DBUG_ASSERT(YYLIP->lookahead_token >= 0); + Lex->raw_trg_on_table_name_end= YYLIP->get_tok_start_prev(); } EACH_SYM ROW_SYM diff --git a/sql/table.cc b/sql/table.cc index fae17fd8f20..742fad71134 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1197,6 +1197,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, uint len; uint ext_key_parts= 0; plugin_ref se_plugin= 0; + const uchar *system_period = 0; + MEM_ROOT *old_root= thd->mem_root; Virtual_column_info **table_check_constraints; DBUG_ENTER("TABLE_SHARE::init_from_binary_frm_image"); @@ -1290,6 +1292,11 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, } #endif /*HAVE_SPATIAL*/ break; + case EXTRA2_PERIOD_FOR_SYSTEM_TIME: + if (system_period || length != 2 * sizeof(uint16)) + goto err; + system_period = extra2; + break; default: /* abort frm parsing if it's an unknown but important extra2 value */ if (type >= EXTRA2_ENGINE_IMPORTANT) @@ -2470,6 +2477,35 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, } } + /* Set system versioning information. */ + if (system_period == NULL) + { + share->disable_system_versioning(); + } + else + { + DBUG_PRINT("info", ("Setting system versioning informations")); + uint16 row_start = uint2korr(system_period); + uint16 row_end = uint2korr(system_period + sizeof(uint16)); + if (row_start >= share->fields || row_end >= share->fields) + goto err; + DBUG_PRINT("info", ("Columns with system versioning: [%d, %d]", row_start, row_end)); + share->enable_system_versioning(row_start, row_end); + vers_start_field()->set_generated_row_start(); + vers_end_field()->set_generated_row_end(); + + if (vers_start_field()->type() != MYSQL_TYPE_TIMESTAMP) + { + my_error(ER_SYS_START_FIELD_MUST_BE_TIMESTAMP, MYF(0), share->table_name); + goto err; + } + if (vers_end_field()->type() != MYSQL_TYPE_TIMESTAMP) + { + my_error(ER_SYS_END_FIELD_MUST_BE_TIMESTAMP, MYF(0), share->table_name); + goto err; + } + } + /* the correct null_bytes can now be set, since bitfields have been taken into account @@ -3013,25 +3049,30 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, records=0; if ((db_stat & HA_OPEN_KEYFILE) || (prgflag & DELAYED_OPEN)) records=1; - if (prgflag & (READ_ALL+EXTRA_RECORD)) + if (prgflag & (READ_ALL + EXTRA_RECORD)) + { records++; - - if (!(record= (uchar*) alloc_root(&outparam->mem_root, - share->rec_buff_length * records))) - goto err; /* purecov: inspected */ + if (share->versioned) + records++; + } if (records == 0) { /* We are probably in hard repair, and the buffers should not be used */ - outparam->record[0]= outparam->record[1]= share->default_values; + record= share->default_values; } else { - outparam->record[0]= record; - if (records > 1) - outparam->record[1]= record+ share->rec_buff_length; - else - outparam->record[1]= outparam->record[0]; // Safety + if (!(record= (uchar*) alloc_root(&outparam->mem_root, + share->rec_buff_length * records))) + goto err; /* purecov: inspected */ + } + + for (i= 0; i < 3;) + { + outparam->record[i]= record; + if (++i < records) + record+= share->rec_buff_length; } if (!(field_ptr = (Field **) alloc_root(&outparam->mem_root, @@ -3056,6 +3097,26 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, } (*field_ptr)= 0; // End marker + if (share->versioned) + { + Field **fptr = NULL; + if (!(fptr = (Field **) alloc_root(&outparam->mem_root, + (uint) ((share->fields+1)* + sizeof(Field*))))) + goto err; + + outparam->non_generated_field = fptr; + for (i=0 ; i < share->fields; i++) + { + if (outparam->field[i]->is_generated()) + continue; + *fptr++ = outparam->field[i]; + } + (*fptr)= 0; // End marker + } + else + outparam->non_generated_field= NULL; + if (share->found_next_number_field) outparam->found_next_number_field= outparam->field[(uint) (share->found_next_number_field - share->field)]; @@ -6225,6 +6286,15 @@ void TABLE::mark_columns_needed_for_delete() if (need_signal) file->column_bitmaps_signal(); + + /* + For System Versioning we have to write and read Sys_end. + */ + if (s->versioned) + { + bitmap_set_bit(read_set, s->vers_end_field()->field_index); + bitmap_set_bit(write_set, s->vers_end_field()->field_index); + } } @@ -6301,6 +6371,15 @@ void TABLE::mark_columns_needed_for_update() need_signal= true; } } + /* + For System Versioning we have to read all columns since we will store + a copy of previous row with modified Sys_end column back to a table. + */ + if (s->versioned) + { + // We will copy old columns to a new row. + use_all_columns(); + } if (check_constraints) { mark_check_constraint_columns_for_read(); @@ -7485,6 +7564,29 @@ int TABLE::update_default_fields(bool update_command, bool ignore_errors) DBUG_RETURN(res); } +bool TABLE::vers_update_fields() +{ + DBUG_ENTER("vers_update_fields"); + + if (!versioned()) + DBUG_RETURN(FALSE); + + if (vers_start_field()->set_time()) + { + DBUG_RETURN(TRUE); + } + + if (vers_end_field()->set_max_timestamp()) + { + DBUG_RETURN(TRUE); + } + + bitmap_set_bit(write_set, vers_start_field()->field_index); + bitmap_set_bit(write_set, vers_end_field()->field_index); + + DBUG_RETURN(FALSE); +} + /** Reset markers that fields are being updated */ diff --git a/sql/table.h b/sql/table.h index f4ef2f05a9b..0e746d6c5fb 100644 --- a/sql/table.h +++ b/sql/table.h @@ -741,6 +741,38 @@ struct TABLE_SHARE plugin_ref default_part_plugin; #endif + /** + System versioning support. + */ + + bool versioned; + uint16 row_start_field; + uint16 row_end_field; + + void enable_system_versioning(uint16 row_start, uint row_end) + { + versioned = true; + row_start_field = row_start; + row_end_field = row_end; + } + + void disable_system_versioning() + { + versioned = false; + row_start_field = 0; + row_end_field = 0; + } + + Field *vers_start_field() + { + return field[row_start_field]; + } + + Field *vers_end_field() + { + return field[row_end_field]; + } + /** Cache the checked structure of this table. @@ -1051,7 +1083,7 @@ public: uint32 instance; /** Table cache instance this TABLE is belonging to */ THD *in_use; /* Which thread uses this */ - uchar *record[2]; /* Pointer to records */ + uchar *record[3]; /* Pointer to records */ uchar *write_row_record; /* Used as optimisation in THD::write_row */ uchar *insert_values; /* used by INSERT ... UPDATE */ @@ -1084,6 +1116,8 @@ public: Field **default_field; /* Fields with non-constant DEFAULT */ Field *next_number_field; /* Set if next_number is activated */ Field *found_next_number_field; /* Set on open */ + Field **non_generated_field; /* Like **field but without generated + fields */ Virtual_column_info **check_constraints; /* Table's triggers, 0 if there are no of them */ @@ -1431,6 +1465,7 @@ public: int update_virtual_field(Field *vf); int update_virtual_fields(handler *h, enum_vcol_update_mode update_mode); int update_default_fields(bool update, bool ignore_errors); + bool vers_update_fields(); void reset_default_fields(); inline ha_rows stat_records() { return used_stat_records; } @@ -1447,6 +1482,37 @@ public: bool with_cleanup); Field *find_field_by_name(const char *str) const; bool export_structure(THD *thd, class Row_definition_list *defs); + + /** + System versioning support. + */ + + bool versioned() const + { + return s->versioned; + } + + Field *vers_start_field() const + { + DBUG_ASSERT(versioned()); + return field[s->row_start_field]; + } + + Field *vers_end_field() const + { + DBUG_ASSERT(versioned()); + return field[s->row_end_field]; + } + +/** Number of additional fields used in versioned tables */ +#define VERSIONING_FIELDS 2 + + uint user_fields() const + { + return versioned() ? + s->fields - VERSIONING_FIELDS : + s->fields; + } }; @@ -1737,6 +1803,31 @@ class Item_in_subselect; 4) jtbm semi-join (jtbm_subselect != NULL) */ +enum for_system_time_type +{ + FOR_SYSTEM_TIME_UNSPECIFIED, FOR_SYSTEM_TIME_AS_OF, + FOR_SYSTEM_TIME_FROM_TO, FOR_SYSTEM_TIME_BETWEEN +}; + +/** System versioning support. */ +struct system_versioning_for_select +{ + enum for_system_time_type type; + Item *start, *end; + bool is_moved_to_where; + + void init( + const enum for_system_time_type t=FOR_SYSTEM_TIME_UNSPECIFIED, + Item * const s=NULL, + Item * const e=NULL) + { + type= t; + start= s; + end= e; + is_moved_to_where= false; + } +}; + struct LEX; class Index_hint; struct TABLE_LIST @@ -2192,6 +2283,10 @@ struct TABLE_LIST TABLE_LIST *find_underlying_table(TABLE *table); TABLE_LIST *first_leaf_for_name_resolution(); TABLE_LIST *last_leaf_for_name_resolution(); + + /** System versioning support. */ + system_versioning_for_select system_versioning; + /** @brief Find the bottom in the chain of embedded table VIEWs. @@ -2390,6 +2485,9 @@ struct TABLE_LIST void check_pushable_cond_for_table(Item *cond); Item *build_pushable_cond_for_table(THD *thd, Item *cond); + void print_system_versioning(THD *thd, table_map eliminated_tables, + String *str, enum_query_type query_type); + private: bool prep_check_option(THD *thd, uint8 check_opt_type); bool prep_where(THD *thd, Item **conds, bool no_where_clause); diff --git a/sql/unireg.cc b/sql/unireg.cc index 0bb8a4e77c6..0465626c132 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -87,6 +87,72 @@ static uchar *extra2_write(uchar *pos, enum extra2_frm_value_type type, return extra2_write(pos, type, reinterpret_cast(str)); } +static bool +versioned(HA_CREATE_INFO *create_info) +{ + return create_info->versioned(); +} + +static uint16 +get_row_start_field(HA_CREATE_INFO *create_info, List &create_fields) +{ + DBUG_ASSERT(versioned(create_info)); + + List_iterator it(create_fields); + Create_field*sql_field = NULL; + + const System_versioning_info *versioning_info = + create_info->get_system_versioning_info(); + DBUG_ASSERT(versioning_info); + + const char *row_start_field = versioning_info->generated_as_row.start->c_ptr(); + DBUG_ASSERT(row_start_field); + + for (unsigned field_no = 0; (sql_field = it++); ++field_no) + { + if (!my_strcasecmp(system_charset_info, + row_start_field, + sql_field->field_name)) + { + DBUG_ASSERT(field_no <= uint16(~0U)); + return uint16(field_no); + } + } + + DBUG_ASSERT(0); /* Not Reachable */ + return 0; +} + +static uint16 +get_row_end_field(HA_CREATE_INFO *create_info, List &create_fields) +{ + DBUG_ASSERT(versioned(create_info)); + + List_iterator it(create_fields); + Create_field*sql_field = NULL; + + const System_versioning_info *versioning_info = + create_info->get_system_versioning_info(); + DBUG_ASSERT(versioning_info); + + const char *row_end_field = versioning_info->generated_as_row.end->c_ptr(); + DBUG_ASSERT(row_end_field); + + for (unsigned field_no = 0; (sql_field = it++); ++field_no) + { + if (!my_strcasecmp(system_charset_info, + row_end_field, + sql_field->field_name)) + { + DBUG_ASSERT(field_no <= uint16(~0U)); + return uint16(field_no); + } + } + + DBUG_ASSERT(0); /* Not Reachable */ + return 0; +} + /** Create a frm (table definition) file @@ -219,6 +285,10 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table, if (gis_extra2_len) extra2_size+= 1 + (gis_extra2_len > 255 ? 3 : 1) + gis_extra2_len; + if (versioned(create_info)) + { + extra2_size+= 1 + 1 + 2 * sizeof(uint16); + } key_buff_length= uint4korr(fileinfo+47); @@ -275,6 +345,16 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table, } #endif /*HAVE_SPATIAL*/ + if (versioned(create_info)) + { + *pos++= EXTRA2_PERIOD_FOR_SYSTEM_TIME; + *pos++= 2 * sizeof(uint16); + int2store(pos, get_row_start_field(create_info, create_fields)); + pos+= sizeof(uint16); + int2store(pos, get_row_end_field(create_info, create_fields)); + pos+= sizeof(uint16); + } + int4store(pos, filepos); // end of the extra2 segment pos+= 4; diff --git a/sql/unireg.h b/sql/unireg.h index b1cab841092..475945311e4 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -172,6 +172,7 @@ enum extra2_frm_value_type { EXTRA2_TABLEDEF_VERSION=0, EXTRA2_DEFAULT_PART_ENGINE=1, EXTRA2_GIS=2, + EXTRA2_PERIOD_FOR_SYSTEM_TIME=4, #define EXTRA2_ENGINE_IMPORTANT 128 diff --git a/storage/tokudb/mysql-test/tokudb/r/tokudb_support_xa.result b/storage/tokudb/mysql-test/tokudb/r/tokudb_support_xa.result index 120e8de7c7f..fd32fa031c7 100644 --- a/storage/tokudb/mysql-test/tokudb/r/tokudb_support_xa.result +++ b/storage/tokudb/mysql-test/tokudb/r/tokudb_support_xa.result @@ -43,7 +43,7 @@ SET @@session.tokudb_support_xa = "T"; ERROR 42000: Variable 'tokudb_support_xa' can't be set to the value of 'T' SET @@session.tokudb_support_xa = "Y"; ERROR 42000: Variable 'tokudb_support_xa' can't be set to the value of 'Y' -SET @@session.tokudb_support_xa = OF; +SET @@session.tokudb_support_xa = OFF; SELECT @@session.tokudb_support_xa; @@session.tokudb_support_xa 0 diff --git a/storage/tokudb/mysql-test/tokudb/t/tokudb_support_xa.test b/storage/tokudb/mysql-test/tokudb/t/tokudb_support_xa.test index f0ad03b91ee..fa1efde7cf7 100644 --- a/storage/tokudb/mysql-test/tokudb/t/tokudb_support_xa.test +++ b/storage/tokudb/mysql-test/tokudb/t/tokudb_support_xa.test @@ -39,7 +39,7 @@ SET @@session.tokudb_support_xa = 1.6; SET @@session.tokudb_support_xa = "T"; --Error ER_WRONG_VALUE_FOR_VAR SET @@session.tokudb_support_xa = "Y"; -SET @@session.tokudb_support_xa = OF; +SET @@session.tokudb_support_xa = OFF; SELECT @@session.tokudb_support_xa; # for global -- cgit v1.2.1 From 8f5f4c2160f40fae180c51d7c8f2e3c358fdfb59 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Fri, 16 Sep 2016 16:55:58 +0000 Subject: Scripts: WITH_INNOBASE_STORAGE_ENGINE fix --- CMakeLists.txt | 9 +++++++++ storage/xtradb/CMakeLists.txt | 1 + 2 files changed, 10 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c4e0037588..29f672428a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -363,6 +363,15 @@ IF(WITH_UNIT_TESTS) ENDIF() ENDIF() +IF(WITH_INNOBASE_STORAGE_ENGINE) + SET(WITH_XTRADB_STORAGE_ENGINE OFF) + IF(PLUGIN_XTRADB STREQUAL STATIC) + SET(PLUGIN_XTRADB DYNAMIC) + ENDIF() +ELSE() + SET(WITH_XTRADB_STORAGE_ENGINE ON) +ENDIF() + SET (MYSQLD_STATIC_PLUGIN_LIBS "" CACHE INTERNAL "") # mariadb_connector_c fetches submodules which is useful for plugins diff --git a/storage/xtradb/CMakeLists.txt b/storage/xtradb/CMakeLists.txt index ba0797dd422..441d2d2773b 100644 --- a/storage/xtradb/CMakeLists.txt +++ b/storage/xtradb/CMakeLists.txt @@ -501,6 +501,7 @@ SET(INNOBASE_SOURCES MYSQL_ADD_PLUGIN(xtradb ${INNOBASE_SOURCES} STORAGE_ENGINE RECOMPILE_FOR_EMBEDDED + MODULE_OUTPUT_NAME ha_innodb LINK_LIBRARIES ${ZLIB_LIBRARY} ${CRC32_VPMSUM_LIBRARY} -- cgit v1.2.1 From 8936abcd87acf8b31a605baceeee2a97129dd8b1 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Sat, 17 Sep 2016 14:35:48 +0000 Subject: Delete: code duplication fix --- sql/sql_delete.cc | 47 ++++++++++++++++++++--------------------------- sql/table.h | 2 ++ 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 4983aafe9e9..b739197ca45 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -212,6 +212,22 @@ void Update_plan::save_explain_data_intern(MEM_ROOT *mem_root, } +inline +int TABLE::delete_row() +{ + int error; + if (!versioned()) + error= file->ha_delete_row(record[0]); + else + { + store_record(this, record[1]); + vers_end_field()->set_time(); + error= file->ha_update_row(record[1], record[0]); + } + return error; +} + + /** Implement DELETE SQL word. @@ -587,15 +603,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, break; } - if (!table->versioned()) - error= table->file->ha_delete_row(table->record[0]); - else - { - store_record(table,record[1]); - table->vers_end_field()->set_time(); - error= table->file->ha_update_row(table->record[1], - table->record[0]); - } + error= table->delete_row(); if (!error) { deleted++; @@ -1086,15 +1094,8 @@ int multi_delete::send_data(List &values) TRG_ACTION_BEFORE, FALSE)) DBUG_RETURN(1); table->status|= STATUS_DELETED; - if (!table->versioned()) - error= table->file->ha_delete_row(table->record[0]); - else - { - store_record(table,record[1]); - table->vers_end_field()->set_time(); - error= table->file->ha_update_row(table->record[1], - table->record[0]); - } + + error= table->delete_row(); if (!error) { deleted++; @@ -1275,15 +1276,7 @@ int multi_delete::do_table_deletes(TABLE *table, SORT_INFO *sort_info, break; } - if (!table->versioned()) - local_error= table->file->ha_delete_row(table->record[0]); - else - { - store_record(table,record[1]); - table->vers_end_field()->set_time(); - local_error= table->file->ha_update_row(table->record[1], - table->record[0]); - } + local_error= table->delete_row(); if (local_error && !ignore) { table->file->print_error(local_error, MYF(0)); diff --git a/sql/table.h b/sql/table.h index 0e746d6c5fb..b66f48708eb 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1504,6 +1504,8 @@ public: return field[s->row_end_field]; } + int delete_row(); + /** Number of additional fields used in versioned tables */ #define VERSIONING_FIELDS 2 -- cgit v1.2.1 From 013345d1191cbb98eb6b40997d93570746289c77 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Sun, 18 Sep 2016 04:43:05 +0000 Subject: vers_update_fields: assert instead of return --- sql/table.cc | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/sql/table.cc b/sql/table.cc index 742fad71134..a09772d2f09 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -7568,18 +7568,9 @@ bool TABLE::vers_update_fields() { DBUG_ENTER("vers_update_fields"); - if (!versioned()) - DBUG_RETURN(FALSE); - - if (vers_start_field()->set_time()) - { - DBUG_RETURN(TRUE); - } - - if (vers_end_field()->set_max_timestamp()) - { - DBUG_RETURN(TRUE); - } + DBUG_ASSERT(versioned()); + DBUG_ASSERT(!vers_start_field()->set_time()); + DBUG_ASSERT(!vers_end_field()->set_max_timestamp()); bitmap_set_bit(write_set, vers_start_field()->field_index); bitmap_set_bit(write_set, vers_end_field()->field_index); -- cgit v1.2.1 From d8c8d7b9462e3a1c07c97a4cc8e0cb3e5c2ccbae Mon Sep 17 00:00:00 2001 From: Kosov Eugene Date: Wed, 21 Sep 2016 23:30:52 +0300 Subject: added implicitly generated fields in versioned tables support and refactored code a bit --- mysql-test/r/create.result | 13 ++++++++++++ mysql-test/t/create.test | 8 ++++++++ sql/handler.cc | 50 ++++++++++++++++++++++++++++++++++++++++++++++ sql/handler.h | 13 ++++++++++-- sql/sql_lex.h | 5 ++--- sql/sql_parse.cc | 11 ++++++---- sql/sql_yacc.yy | 36 +++++++++++++++------------------ 7 files changed, 107 insertions(+), 29 deletions(-) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 941ba2837d2..e445842192f 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -1949,6 +1949,19 @@ t1 CREATE TABLE `t1` ( PERIOD FOR SYSTEM_TIME (`Sys_start`, `Sys_end`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING drop table if exists t1; +# Versioning fields are set implicitly. +create table t1 ( +XNo INT UNSIGNED +) WITH SYSTEM VERSIONING; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `XNo` int(10) unsigned DEFAULT NULL, + `sys_trx_start` timestamp(6) NULL GENERATED AS ROW START, + `sys_trx_end` timestamp(6) NULL GENERATED AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +drop table if exists t1; create table t1 ( XNo INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 5e5c5008d8e..5732fbbe03d 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -1799,6 +1799,14 @@ SHOW CREATE TABLE t1; drop table if exists t1; +--echo # Versioning fields are set implicitly. +create table t1 ( + XNo INT UNSIGNED +) WITH SYSTEM VERSIONING; +SHOW CREATE TABLE t1; + +drop table if exists t1; + --error ER_SYS_START_MORE_THAN_ONCE create table t1 ( XNo INT UNSIGNED, diff --git a/sql/handler.cc b/sql/handler.cc index 5d0ec99e978..b27dc224c48 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6552,3 +6552,53 @@ int del_global_index_stat(THD *thd, TABLE* table, KEY* key_info) mysql_mutex_unlock(&LOCK_global_index_stats); DBUG_RETURN(res); } + +static bool create_string(MEM_ROOT *mem_root, String **s, const char *value) +{ + *s= new (mem_root) String(value, system_charset_info); + return *s == NULL; +} + +static bool create_sys_trx_field_if_missing(THD *thd, const char *field_name, + Alter_info *alter_info, String **s) +{ + Create_field *f= new (thd->mem_root) Create_field(); + if (!f) + return true; + + f->field_name= field_name; + f->charset= system_charset_info; + f->sql_type= MYSQL_TYPE_TIMESTAMP; + f->length= 6; + f->decimals= 0; + + if (f->check(thd)) + return true; + + if (create_string(thd->mem_root, s, field_name)) + return true; + + alter_info->create_list.push_back(f); + return false; +} + +bool System_versioning_info::add_implicit_fields(THD *thd, + Alter_info *alter_info) +{ + if (!declared_system_versioning) + return false; + + // If user specified some of these he must specify the others too. Do nothing. + if (generated_as_row.start || generated_as_row.end || + period_for_system_time.start || period_for_system_time.end) + return false; + + return create_sys_trx_field_if_missing(thd, "sys_trx_start", alter_info, + &generated_as_row.start) || + create_sys_trx_field_if_missing(thd, "sys_trx_end", alter_info, + &generated_as_row.end) || + create_string(thd->mem_root, &period_for_system_time.start, + "sys_trx_start") || + create_string(thd->mem_root, &period_for_system_time.end, + "sys_trx_end"); +} diff --git a/sql/handler.h b/sql/handler.h index 2b911cd94c5..e88579f9d9d 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1683,6 +1683,9 @@ struct System_versioning_info set_period_for_system_time(NULL, NULL); } + /** Returns true on failure */ + bool add_implicit_fields(THD *thd, Alter_info *alter_info); + /** User has added 'WITH SYSTEM VERSIONING' to table definition */ bool declared_system_versioning; @@ -1777,11 +1780,17 @@ struct Table_scope_and_contents_source_st : ha_default_handlerton(thd); } - bool versioned() + bool versioned() const { return system_versioning_info.versioned; } - const System_versioning_info *get_system_versioning_info() + const System_versioning_info *get_system_versioning_info() const + { + if (!versioned()) + return NULL; + return &system_versioning_info; + } + System_versioning_info *get_system_versioning_info() { if (!versioned()) return NULL; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index a7fe77ca5a7..9b625d3b7b3 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3561,10 +3561,9 @@ public: bool add_unit_in_brackets(SELECT_LEX *nselect); void check_automatic_up(enum sub_select_type type); - System_versioning_info *vers_get_info() + System_versioning_info &vers_get_info() { - create_info.system_versioning_info.versioned = true; - return &create_info.system_versioning_info; + return create_info.system_versioning_info; } }; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 5484467509a..9bae9ecc658 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3849,10 +3849,6 @@ mysql_execute_command(THD *thd) copy. */ Alter_info alter_info(lex->alter_info, thd->mem_root); - - if (check_system_versioning(&create_info)) - goto end_with_restore_list; - if (thd->is_fatal_error) { /* If out of memory when creating a copy of alter_info. */ @@ -3860,6 +3856,13 @@ mysql_execute_command(THD *thd) goto end_with_restore_list; } + if (System_versioning_info *info= create_info.get_system_versioning_info()) + if (info->add_implicit_fields(thd, &alter_info)) + goto end_with_restore_list; + + if (check_system_versioning(&create_info)) + goto end_with_restore_list; + /* Check privileges */ if ((res= create_table_precheck(thd, select_tables, create_table))) goto end_with_restore_list; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 6b09055e323..7e8ef6ec8fb 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5852,10 +5852,9 @@ create_table_option: } | WITH SYSTEM VERSIONING { - System_versioning_info *info = Lex->vers_get_info(); - if (!info) - MYSQL_YYABORT; - info->declared_system_versioning = true; + System_versioning_info &info= Lex->vers_get_info(); + info.declared_system_versioning= true; + info.versioned= true; } ; @@ -6060,15 +6059,14 @@ period_for_system_time: // If FOR_SYM is followed by SYSTEM_TIME_SYM then they are merged to: FOR_SYSTEM_TIME_SYM . PERIOD_SYM FOR_SYSTEM_TIME_SYM '(' period_for_system_time_column_id ',' period_for_system_time_column_id ')' { - System_versioning_info *info = Lex->vers_get_info(); - if (!info) - MYSQL_YYABORT; + System_versioning_info &info= Lex->vers_get_info(); if (!my_strcasecmp(system_charset_info, $4->c_ptr(), $6->c_ptr())) { my_error(ER_SYS_START_AND_SYS_END_SAME, MYF(0), $4->c_ptr()); MYSQL_YYABORT; } - info->set_period_for_system_time($4, $6); + info.set_period_for_system_time($4, $6); + info.versioned= true; } ; @@ -6168,26 +6166,24 @@ field_def: vcol_opt_specifier vcol_opt_attribute | opt_generated_always AS ROW_SYM start_or_end { - System_versioning_info *info = - Lex->vers_get_info(); - if (!info) - MYSQL_YYABORT; - String *field_name = new (thd->mem_root) + System_versioning_info &info= Lex->vers_get_info(); + info.versioned= true; + String *field_name= new (thd->mem_root) String((const char*)Lex->last_field->field_name, system_charset_info); if (!field_name) MYSQL_YYABORT; - String **p = NULL; - int err_nr = 0; + String **p= NULL; + int err_nr= 0; switch ($4) { case 1: - p = &info->generated_as_row.start; - err_nr = ER_SYS_START_MORE_THAN_ONCE; + p= &info.generated_as_row.start; + err_nr= ER_SYS_START_MORE_THAN_ONCE; break; case 0: - p = &info->generated_as_row.end; - err_nr = ER_SYS_END_MORE_THAN_ONCE; + p= &info.generated_as_row.end; + err_nr= ER_SYS_END_MORE_THAN_ONCE; break; default: /* Not Reachable */ @@ -6199,7 +6195,7 @@ field_def: my_error(err_nr, MYF(0), field_name->c_ptr()); MYSQL_YYABORT; } - *p = field_name; + *p= field_name; } ; -- cgit v1.2.1 From bd0b21d22cd76a0f52fde3942721cc2331d4be46 Mon Sep 17 00:00:00 2001 From: Kosov Eugene Date: Thu, 22 Sep 2016 15:03:05 +0300 Subject: SQL: fix for lost code in debug macros --- sql/sql_insert.cc | 13 ++++--------- sql/sql_update.cc | 22 ++++++---------------- sql/table.cc | 11 +++++++---- sql/table.h | 2 +- 4 files changed, 18 insertions(+), 30 deletions(-) diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 4787356c8b6..39a8c61c231 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1029,12 +1029,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, } } - if (table->versioned() && - table->vers_update_fields()) - { - error= 1; - break; - } + if (table->versioned()) + table->vers_update_fields(); if ((res= table_list->view_check_option(thd, (values_list.elements == 1 ? @@ -3799,9 +3795,8 @@ int select_insert::send_data(List &values) DBUG_RETURN(0); thd->count_cuted_fields= CHECK_FIELD_WARN; // Calculate cuted fields - if (table->versioned() && - table->vers_update_fields()) - DBUG_RETURN(1); + if (table->versioned()) + table->vers_update_fields(); store_values(values); if (table->default_field && table->update_default_fields(0, info.ignore)) DBUG_RETURN(1); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 79cabf180a9..da01bd26873 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -763,11 +763,8 @@ int mysql_update(THD *thd, TRG_EVENT_UPDATE)) break; /* purecov: inspected */ - if (table->versioned() && table->vers_update_fields()) - { - error= 1; - break; - } + if (table->versioned()) + table->vers_update_fields(); found++; @@ -2173,12 +2170,8 @@ int multi_update::send_data(List ¬_used_values) if (table->default_field && table->update_default_fields(1, ignore)) DBUG_RETURN(1); - if (table->versioned() && - table->vers_update_fields()) - { - error= 1; - break; - } + if (table->versioned()) + table->vers_update_fields(); if ((error= cur_table->view_check_option(thd, ignore)) != VIEW_CHECK_OK) @@ -2514,11 +2507,8 @@ int multi_update::do_updates() goto err2; } } - if (table->versioned() && - table->vers_update_fields()) - { - goto err2; - } + if (table->versioned()) + table->vers_update_fields(); if ((local_error=table->file->ha_update_row(table->record[1], table->record[0])) && diff --git a/sql/table.cc b/sql/table.cc index a09772d2f09..ca449d628d1 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -7564,18 +7564,21 @@ int TABLE::update_default_fields(bool update_command, bool ignore_errors) DBUG_RETURN(res); } -bool TABLE::vers_update_fields() +void TABLE::vers_update_fields() { DBUG_ENTER("vers_update_fields"); DBUG_ASSERT(versioned()); - DBUG_ASSERT(!vers_start_field()->set_time()); - DBUG_ASSERT(!vers_end_field()->set_max_timestamp()); + bool res= !vers_start_field()->set_time(); + DBUG_ASSERT(res); + res= !vers_end_field()->set_max_timestamp(); + DBUG_ASSERT(res); + (void)res; bitmap_set_bit(write_set, vers_start_field()->field_index); bitmap_set_bit(write_set, vers_end_field()->field_index); - DBUG_RETURN(FALSE); + DBUG_VOID_RETURN; } /** diff --git a/sql/table.h b/sql/table.h index b66f48708eb..7416f27756d 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1465,7 +1465,7 @@ public: int update_virtual_field(Field *vf); int update_virtual_fields(handler *h, enum_vcol_update_mode update_mode); int update_default_fields(bool update, bool ignore_errors); - bool vers_update_fields(); + void vers_update_fields(); void reset_default_fields(); inline ha_rows stat_records() { return used_stat_records; } -- cgit v1.2.1 From 84e1971128156b366ac1f2e8476a8001008e36c7 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Thu, 22 Sep 2016 05:56:34 +0000 Subject: IB: 0.2 part I * SYS_VTQ internal InnoDB table; * I_S.INNODB_SYS_VTQ table; * vers_notify_vtq(): add record to SYS_VTQ on versioned DML; * SYS_VTQ columns filled: TRX_ID, BEGIN_TS. --- sql/handler.h | 1 + sql/sql_class.cc | 6 + storage/innobase/dict/dict0crea.cc | 109 +++++++++++++ storage/innobase/dict/dict0load.cc | 64 +++++++- storage/innobase/handler/ha_innodb.cc | 11 +- storage/innobase/handler/i_s.cc | 281 ++++++++++++++++++++++++++++++++++ storage/innobase/handler/i_s.h | 1 + storage/innobase/include/dict0boot.h | 17 ++ storage/innobase/include/dict0crea.h | 4 + storage/innobase/include/dict0dict.h | 1 + storage/innobase/include/dict0load.h | 20 +++ storage/innobase/include/dict0mem.h | 4 +- storage/innobase/include/que0que.h | 3 - storage/innobase/include/row0ins.h | 5 + storage/innobase/include/trx0trx.h | 1 + storage/innobase/include/univ.i | 2 + storage/innobase/row/row0ins.cc | 64 ++++++++ storage/innobase/row/row0mysql.cc | 18 ++- storage/innobase/srv/srv0start.cc | 4 + storage/innobase/trx/trx0trx.cc | 19 ++- 20 files changed, 618 insertions(+), 17 deletions(-) diff --git a/sql/handler.h b/sql/handler.h index e88579f9d9d..986896cc48b 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -401,6 +401,7 @@ enum enum_alter_inplace_result { #define HA_LEX_CREATE_TMP_TABLE 1U #define HA_CREATE_TMP_ALTER 8U #define HA_LEX_CREATE_SEQUENCE 16U +#define HA_VERSIONED_TABLE 32U #define HA_MAX_REC_LENGTH 65535 diff --git a/sql/sql_class.cc b/sql/sql_class.cc index abd680d749f..0ed78b2dfa8 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -4627,6 +4627,12 @@ extern "C" int thd_rpl_is_parallel(const MYSQL_THD thd) return thd->rgi_slave && thd->rgi_slave->is_parallel_exec; } +/* Returns high resolution timestamp for the start + of the current query. */ +extern "C" time_t thd_start_time(const MYSQL_THD thd) +{ + return thd->start_time; +} /* Returns high resolution timestamp for the start of the current query. */ diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc index c1bd5c2d368..0b0902ba1b7 100644 --- a/storage/innobase/dict/dict0crea.cc +++ b/storage/innobase/dict/dict0crea.cc @@ -1878,6 +1878,115 @@ dict_create_or_check_sys_virtual() return(err); } +UNIV_INTERN +dberr_t +dict_create_or_check_vtq_table(void) +/*================================================*/ +{ + trx_t* trx; + my_bool srv_file_per_table_backup; + dberr_t err; + dberr_t sys_vtq_err; + + ut_a(srv_get_active_thread_type() == SRV_NONE); + + /* Note: The master thread has not been started at this point. */ + + + sys_vtq_err = dict_check_if_system_table_exists( + "SYS_VTQ", DICT_NUM_FIELDS__SYS_VTQ + 1, 3); + + if (sys_vtq_err == DB_SUCCESS) { + mutex_enter(&dict_sys->mutex); + dict_sys->sys_vtq = dict_table_get_low("SYS_VTQ"); + mutex_exit(&dict_sys->mutex); + return(DB_SUCCESS); + } + + trx = trx_allocate_for_mysql(); + + trx_set_dict_operation(trx, TRX_DICT_OP_TABLE); + + trx->op_info = "creating VTQ sys table"; + + row_mysql_lock_data_dictionary(trx); + + /* Check which incomplete table definition to drop. */ + + if (sys_vtq_err == DB_CORRUPTION) { + ib::warn() << + "Dropping incompletely created " + "SYS_VTQ table."; + row_drop_table_for_mysql("SYS_VTQ", trx, false, TRUE); + } + + ib::warn() << + "Creating VTQ system table."; + + srv_file_per_table_backup = srv_file_per_table; + + /* We always want SYSTEM tables to be created inside the system + tablespace. */ + + srv_file_per_table = 0; + + err = que_eval_sql( + NULL, + "PROCEDURE CREATE_VTQ_SYS_TABLE_PROC () IS\n" + "BEGIN\n" + "CREATE TABLE\n" + "SYS_VTQ(TRX_ID BIGINT UNSIGNED, BEGIN_TS BIGINT UNSIGNED," + " COMMIT_TS BIGINT UNSIGNED, CONCURR_TRX BLOB);\n" + "CREATE UNIQUE CLUSTERED INDEX TRX_ID_IND" + " ON SYS_VTQ (TRX_ID);\n" + "CREATE INDEX BEGIN_TS_IND" + " ON SYS_VTQ (BEGIN_TS);\n" + "CREATE INDEX COMMIT_TS_IND" + " ON SYS_VTQ (COMMIT_TS);\n" + "END;\n", + FALSE, trx); + + if (err != DB_SUCCESS) { + ib::error() << "Creation of SYS_VTQ" + " failed: " << ut_strerr(err) << ". Tablespace is" + " full or too many transactions." + " Dropping incompletely created tables."; + + ut_ad(err == DB_OUT_OF_FILE_SPACE + || err == DB_TOO_MANY_CONCURRENT_TRXS); + + row_drop_table_for_mysql("SYS_VTQ", trx, false, TRUE); + + if (err == DB_OUT_OF_FILE_SPACE) { + err = DB_MUST_GET_MORE_FILE_SPACE; + } + } + + trx_commit_for_mysql(trx); + + row_mysql_unlock_data_dictionary(trx); + + trx_free_for_mysql(trx); + + srv_file_per_table = srv_file_per_table_backup; + + if (err == DB_SUCCESS) { + ib::info() << + "VTQ system table created"; + } + + /* Note: The master thread has not been started at this point. */ + /* Confirm and move to the non-LRU part of the table LRU list. */ + sys_vtq_err = dict_check_if_system_table_exists( + "SYS_VTQ", DICT_NUM_FIELDS__SYS_VTQ + 1, 3); + ut_a(sys_vtq_err == DB_SUCCESS); + mutex_enter(&dict_sys->mutex); + dict_sys->sys_vtq = dict_table_get_low("SYS_VTQ"); + mutex_exit(&dict_sys->mutex); + + return(err); +} + /****************************************************************//** Evaluate the given foreign key SQL statement. @return error code or DB_SUCCESS */ diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc index da72126793f..b646123048b 100644 --- a/storage/innobase/dict/dict0load.cc +++ b/storage/innobase/dict/dict0load.cc @@ -50,7 +50,7 @@ Created 4/24/1996 Heikki Tuuri #include /** Following are the InnoDB system tables. The positions in -this array are referenced by enum dict_system_table_id. */ +this array are referenced by enum dict_system_id_t. */ static const char* SYSTEM_TABLE_NAME[] = { "SYS_TABLES", "SYS_INDEXES", @@ -60,7 +60,8 @@ static const char* SYSTEM_TABLE_NAME[] = { "SYS_FOREIGN_COLS", "SYS_TABLESPACES", "SYS_DATAFILES", - "SYS_VIRTUAL" + "SYS_VIRTUAL", + "SYS_VTQ" }; /** Loads a table definition and also all its index definitions. @@ -821,6 +822,64 @@ err_len: return(NULL); } +/********************************************************************//** +This function parses a SYS_VTQ record, extracts necessary +information from the record and returns it to the caller. +@return error message, or NULL on success */ +UNIV_INTERN +const char* +dict_process_sys_vtq( +/*=======================*/ +mem_heap_t* heap, /*!< in/out: heap memory */ +const rec_t* rec, /*!< in: current rec */ +ullong* col_trx_id, /*!< out: field values */ +ullong* col_begin_ts, +ullong* col_commit_ts, +ullong* col_concurr_trx) +{ + ulint len; + const byte* field; + + if (rec_get_deleted_flag(rec, 0)) { + return("delete-marked record in SYS_VTQ"); + } + + if (rec_get_n_fields_old(rec) != DICT_NUM_FIELDS__SYS_VTQ) { + return("wrong number of columns in SYS_VTQ record"); + } + + field = rec_get_nth_field_old( + rec, DICT_FLD__SYS_VTQ__TRX_ID, &len); + if (len != sizeof(col_trx_id)) { + err_len: + return("incorrect column length in SYS_VTQ"); + } + *col_trx_id = mach_read_from_8(field); + + field = rec_get_nth_field_old( + rec, DICT_FLD__SYS_VTQ__BEGIN_TS, &len); + if (len != sizeof(col_begin_ts)) { + goto err_len; + } + *col_begin_ts = mach_read_from_8(field); + + field = rec_get_nth_field_old( + rec, DICT_FLD__SYS_VTQ__COMMIT_TS, &len); + if (len != sizeof(col_commit_ts)) { + goto err_len; + } + *col_commit_ts = mach_read_from_8(field); + + field = rec_get_nth_field_old( + rec, DICT_FLD__SYS_VTQ__CONCURR_TRX, &len); + if (len != sizeof(col_concurr_trx)) { + goto err_len; + } + *col_concurr_trx = mach_read_from_8(field); + + return(NULL); +} + /** Get the first filepath from SYS_DATAFILES for a given space_id. @param[in] space_id Tablespace ID @return First filepath (caller must invoke ut_free() on it) @@ -3714,3 +3773,4 @@ dict_table_open_on_index_id( } return table; } + diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 88282c698eb..7e90511e9e1 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -1781,9 +1781,7 @@ thd_start_time_in_secs( /*===================*/ THD* thd) /*!< in: thread handle, or NULL */ { - // FIXME: This function should be added to the server code. - //return(thd_start_time(thd)); - return(ulint(ut_time())); + return(thd_start_time(thd)); } /** Enter InnoDB engine after checking the max number of user threads @@ -12855,6 +12853,10 @@ index_bad: DBUG_EXECUTE_IF("innodb_test_wrong_fts_aux_table_name", m_flags2 &= ~DICT_TF2_FTS_AUX_HEX_NAME;); + if (m_create_info->options & HA_VERSIONED_TABLE) { + m_flags2 |= DICT_TF2_VERSIONED; + } + DBUG_RETURN(true); } @@ -22000,7 +22002,8 @@ i_s_innodb_sys_virtual, i_s_innodb_mutexes, i_s_innodb_sys_semaphore_waits, i_s_innodb_tablespaces_encryption, -i_s_innodb_tablespaces_scrubbing +i_s_innodb_tablespaces_scrubbing, +i_s_innodb_vtq maria_declare_plugin_end; /** @brief Initialize the default value of innodb_commit_concurrency. diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index 6bf16573efd..d53f4fe9df2 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -347,6 +347,54 @@ field_store_ulint( # define I_S_AHI 0 /* Omit the IS_HASHED column */ #endif +/*******************************************************************//** +Auxiliary function to store ulint value in MYSQL_TYPE_LONGLONG field. +If the value is UINT64_UNDEFINED then the field it set to NULL. +@return 0 on success */ +int +field_store_ullong( +/*==============*/ + Field* field, /*!< in/out: target field for storage */ + ullong n) /*!< in: value to store */ +{ + int ret; + + if (n != UINT64_UNDEFINED) { + ret = field->store(n, 1); + field->set_notnull(); + } else { + ret = 0; /* success */ + field->set_null(); + } + + return(ret); +} + +/*******************************************************************//** +Auxiliary function to store packed timestamp value in MYSQL_TYPE_DATETIME field. +If the value is ULINT_UNDEFINED then the field it set to NULL. +@return 0 on success */ +int +field_store_packed_ts( +/*==============*/ +Field* field, /*!< in/out: target field for storage */ +ullong n) /*!< in: value to store */ +{ + int ret; + MYSQL_TIME tmp; + + if (n != UINT64_UNDEFINED) { + unpack_time(n, &tmp); + ret = field->store_time(&tmp); + field->set_notnull(); + } else { + ret = 0; /* success */ + field->set_null(); + } + + return(ret); +} + /* Fields of the dynamic table INFORMATION_SCHEMA.innodb_trx */ static ST_FIELD_INFO innodb_trx_fields_info[] = { @@ -9608,3 +9656,236 @@ UNIV_INTERN struct st_maria_plugin i_s_innodb_sys_semaphore_waits = STRUCT_FLD(version_info, INNODB_VERSION_STR), STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE), }; + + +/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_vtq */ +static ST_FIELD_INFO innodb_vtq_fields_info[] = +{ +#define SYS_VTQ_TRX_ID 0 + { STRUCT_FLD(field_name, "trx_id"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE) }, + +#define SYS_VTQ_BEGIN_TS 1 + { STRUCT_FLD(field_name, "begin_ts"), + STRUCT_FLD(field_length, 6), + STRUCT_FLD(field_type, MYSQL_TYPE_TIMESTAMP), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE) }, + +#define SYS_VTQ_COMMIT_TS 2 + { STRUCT_FLD(field_name, "commit_ts"), + STRUCT_FLD(field_length, 6), + STRUCT_FLD(field_type, MYSQL_TYPE_TIMESTAMP), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE) }, + +#define SYS_VTQ_CONCURR_TRX 3 + { STRUCT_FLD(field_name, "concurr_trx"), + STRUCT_FLD(field_length, 120), + STRUCT_FLD(field_type, MYSQL_TYPE_MEDIUM_BLOB), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE) }, + + END_OF_ST_FIELD_INFO +}; + +/**********************************************************************//** +Function to fill INFORMATION_SCHEMA.INNODB_SYS_VTQ with information +collected by scanning SYS_VTQ table. +@return 0 on success */ +static +int +i_s_dict_fill_vtq( +/*========================*/ + THD* thd, /*!< in: thread */ + ullong col_trx_id, /*!< in: table fields */ + ullong col_begin_ts, + ullong col_commit_ts, + ullong col_concurr_trx, + TABLE* table_to_fill) /*!< in/out: fill this table */ +{ + Field** fields; + + DBUG_ENTER("i_s_dict_fill_vtq"); + fields = table_to_fill->field; + + OK(field_store_ullong(fields[SYS_VTQ_TRX_ID], col_trx_id)); + OK(field_store_packed_ts(fields[SYS_VTQ_BEGIN_TS], col_begin_ts)); + OK(field_store_packed_ts(fields[SYS_VTQ_COMMIT_TS], col_commit_ts)); + OK(field_store_ullong(fields[SYS_VTQ_CONCURR_TRX], col_concurr_trx)); + + OK(schema_table_store_record(thd, table_to_fill)); + + DBUG_RETURN(0); +} + +/*******************************************************************//** +Function to populate INFORMATION_SCHEMA.INNODB_SYS_VTQ table. +Loop through each record in SYS_VTQ, and extract the column +information and fill the INFORMATION_SCHEMA.INNODB_SYS_VTQ table. +@return 0 on success */ + +static const int I_S_SYS_VTQ_LIMIT = 1000; // maximum number of records in I_S.INNODB_SYS_VTQ + +static +int +i_s_sys_vtq_fill_table( +/*=========================*/ + THD* thd, /*!< in: thread */ + TABLE_LIST* tables, /*!< in/out: tables to fill */ + Item* ) /*!< in: condition (not used) */ +{ + btr_pcur_t pcur; + const rec_t* rec; + mem_heap_t* heap; + mtr_t mtr; + int err = 0; + + DBUG_ENTER("i_s_sys_vtq_fill_table"); + RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name); + + /* deny access to user without PROCESS_ACL privilege */ + if (check_global_access(thd, PROCESS_ACL)) { + DBUG_RETURN(0); + } + + heap = mem_heap_create(1000); + mutex_enter(&dict_sys->mutex); + mtr_start(&mtr); + + rec = dict_startscan_system(&pcur, &mtr, SYS_VTQ); + + for (int i = 0; rec && i < I_S_SYS_VTQ_LIMIT; ++i) { + const char* err_msg; + ullong col_trx_id; + ullong col_begin_ts; + ullong col_commit_ts; + ullong col_concurr_trx; + + /* Extract necessary information from a SYS_VTQ row */ + err_msg = dict_process_sys_vtq( + heap, + rec, + &col_trx_id, + &col_begin_ts, + &col_commit_ts, + &col_concurr_trx); + + mtr_commit(&mtr); + mutex_exit(&dict_sys->mutex); + + if (!err_msg) { + err = i_s_dict_fill_vtq( + thd, + col_trx_id, + col_begin_ts, + col_commit_ts, + col_concurr_trx, + tables->table); + } else { + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + ER_CANT_FIND_SYSTEM_REC, "%s", + err_msg); + err = 1; + } + + if (err) + break; + + mem_heap_empty(heap); + + /* Get the next record */ + mutex_enter(&dict_sys->mutex); + mtr_start(&mtr); + rec = dict_getnext_system(&pcur, &mtr); + } + + if (!err) { + mtr_commit(&mtr); + mutex_exit(&dict_sys->mutex); + } + mem_heap_free(heap); + + DBUG_RETURN(err); +} + +/*******************************************************************//** +Bind the dynamic table INFORMATION_SCHEMA.innodb_vtq +@return 0 on success */ +static +int +innodb_vtq_init( +/*===================*/ +void* p) /*!< in/out: table schema object */ +{ + ST_SCHEMA_TABLE* schema; + + DBUG_ENTER("innodb_vtq_init"); + + schema = (ST_SCHEMA_TABLE*) p; + + schema->fields_info = innodb_vtq_fields_info; + schema->fill_table = i_s_sys_vtq_fill_table; + + DBUG_RETURN(0); +} + +UNIV_INTERN struct st_maria_plugin i_s_innodb_vtq = +{ + /* the plugin type (a MYSQL_XXX_PLUGIN value) */ + /* int */ + STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN), + + /* pointer to type-specific plugin descriptor */ + /* void* */ + STRUCT_FLD(info, &i_s_info), + + /* plugin name */ + /* const char* */ + STRUCT_FLD(name, "INNODB_VTQ"), + + /* plugin author (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(author, plugin_author), + + /* general descriptive text (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(descr, "InnoDB Versioning Transaction Query table"), + + /* the plugin license (PLUGIN_LICENSE_XXX) */ + /* int */ + STRUCT_FLD(license, PLUGIN_LICENSE_GPL), + + /* the function to invoke when plugin is loaded */ + /* int (*)(void*); */ + STRUCT_FLD(init, innodb_vtq_init), + + /* the function to invoke when plugin is unloaded */ + /* int (*)(void*); */ + STRUCT_FLD(deinit, i_s_common_deinit), + + /* plugin version (for SHOW PLUGINS) */ + /* unsigned int */ + STRUCT_FLD(version, INNODB_VERSION_SHORT), + + /* struct st_mysql_show_var* */ + STRUCT_FLD(status_vars, NULL), + + /* struct st_mysql_sys_var** */ + STRUCT_FLD(system_vars, NULL), + + /* Maria extension */ + STRUCT_FLD(version_info, INNODB_VERSION_STR), + STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_GAMMA), +}; diff --git a/storage/innobase/handler/i_s.h b/storage/innobase/handler/i_s.h index 8d34fbf8fbb..dc3e37f207e 100644 --- a/storage/innobase/handler/i_s.h +++ b/storage/innobase/handler/i_s.h @@ -64,6 +64,7 @@ extern struct st_maria_plugin i_s_innodb_sys_virtual; extern struct st_maria_plugin i_s_innodb_tablespaces_encryption; extern struct st_maria_plugin i_s_innodb_tablespaces_scrubbing; extern struct st_maria_plugin i_s_innodb_sys_semaphore_waits; +extern struct st_maria_plugin i_s_innodb_vtq; /** maximum number of buffer page info we would cache. */ #define MAX_BUF_INFO_CACHED 10000 diff --git a/storage/innobase/include/dict0boot.h b/storage/innobase/include/dict0boot.h index d6de7dcf71b..22b0489386d 100644 --- a/storage/innobase/include/dict0boot.h +++ b/storage/innobase/include/dict0boot.h @@ -325,6 +325,23 @@ enum dict_fld_sys_datafiles_enum { DICT_FLD__SYS_DATAFILES__PATH = 3, DICT_NUM_FIELDS__SYS_DATAFILES = 4 }; +/* The columns in SYS_VTQ */ +enum dict_col_sys_vtq_enum +{ + DICT_COL__SYS_VTQ__TRX_ID = 0, + DICT_NUM_COLS__SYS_VTQ = 1 +}; +/* The field numbers in the SYS_VTQ clustered index */ +enum dict_fld_sys_vtq_enum +{ + DICT_FLD__SYS_VTQ__TRX_ID = 0, + DICT_FLD__SYS_VTQ__DB_TRX_ID = 1, + DICT_FLD__SYS_VTQ__DB_ROLL_PTR = 2, + DICT_FLD__SYS_VTQ__BEGIN_TS = 3, + DICT_FLD__SYS_VTQ__COMMIT_TS = 4, + DICT_FLD__SYS_VTQ__CONCURR_TRX = 5, + DICT_NUM_FIELDS__SYS_VTQ = 6 +}; /* The columns in SYS_VIRTUAL */ enum dict_col_sys_virtual_enum { diff --git a/storage/innobase/include/dict0crea.h b/storage/innobase/include/dict0crea.h index f53ea74717d..2999f9505e9 100644 --- a/storage/innobase/include/dict0crea.h +++ b/storage/innobase/include/dict0crea.h @@ -312,6 +312,10 @@ struct tab_node_t{ storage */ }; +UNIV_INTERN +dberr_t +dict_create_or_check_vtq_table(void); + /* Table create node states */ #define TABLE_BUILD_TABLE_DEF 1 #define TABLE_BUILD_COL_DEF 2 diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index 18578388723..56ca8325d45 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -1738,6 +1738,7 @@ struct dict_sys_t{ dict_table_t* sys_indexes; /*!< SYS_INDEXES table */ dict_table_t* sys_fields; /*!< SYS_FIELDS table */ dict_table_t* sys_virtual; /*!< SYS_VIRTUAL table */ + dict_table_t* sys_vtq; /*!< SYS_VTQ table */ /*=============================*/ UT_LIST_BASE_NODE_T(dict_table_t) diff --git a/storage/innobase/include/dict0load.h b/storage/innobase/include/dict0load.h index fb443caf770..197a61b4ebe 100644 --- a/storage/innobase/include/dict0load.h +++ b/storage/innobase/include/dict0load.h @@ -52,6 +52,7 @@ enum dict_system_id_t { SYS_TABLESPACES, SYS_DATAFILES, SYS_VIRTUAL, + SYS_VTQ, /* This must be last item. Defines the number of system tables. */ SYS_NUM_SYSTEM_TABLES @@ -314,6 +315,20 @@ dict_process_sys_datafiles( const rec_t* rec, /*!< in: current SYS_DATAFILES rec */ ulint* space, /*!< out: pace id */ const char** path); /*!< out: datafile path */ +/********************************************************************//** +This function parses a SYS_VTQ record, extracts necessary +information from the record and returns it to the caller. +@return error message, or NULL on success */ +UNIV_INTERN +const char* +dict_process_sys_vtq( +/*=======================*/ +mem_heap_t* heap, /*!< in/out: heap memory */ +const rec_t* rec, /*!< in: current rec */ +ullong* col_trx_id, /*!< out: field values */ +ullong* col_begin_ts, +ullong* col_commit_ts, +ullong* col_concurr_trx); /** Update the record for space_id in SYS_TABLESPACES to this filepath. @param[in] space_id Tablespace ID @@ -338,4 +353,9 @@ dict_replace_tablespace_and_filepath( const char* filepath, ulint fsp_flags); + +UNIV_INTERN +dict_table_t* +get_vtq_table(); + #endif diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 9b87e654b21..f1193d314f8 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -300,7 +300,7 @@ ROW_FORMAT=REDUNDANT. InnoDB engines do not check these flags for unknown bits in order to protect backward incompatibility. */ /* @{ */ /** Total number of bits in table->flags2. */ -#define DICT_TF2_BITS 9 +#define DICT_TF2_BITS 10 #define DICT_TF2_UNUSED_BIT_MASK (~0U << DICT_TF2_BITS | \ 1U << DICT_TF_POS_SHARED_SPACE) #define DICT_TF2_BIT_MASK ~DICT_TF2_UNUSED_BIT_MASK @@ -329,6 +329,8 @@ use its own tablespace instead of the system tablespace. */ index tables) of a FTS table are in HEX format. */ #define DICT_TF2_FTS_AUX_HEX_NAME 64U + +#define DICT_TF2_VERSIONED 512 /* @} */ #define DICT_TF2_FLAG_SET(table, flag) \ diff --git a/storage/innobase/include/que0que.h b/storage/innobase/include/que0que.h index 763b16820d8..13be7291f00 100644 --- a/storage/innobase/include/que0que.h +++ b/storage/innobase/include/que0que.h @@ -380,9 +380,6 @@ struct que_thr_t{ UT_LIST_NODE_T(que_thr_t) thrs; /*!< list of thread nodes of the fork node */ - UT_LIST_NODE_T(que_thr_t) - trx_thrs; /*!< lists of threads in wait list of - the trx */ UT_LIST_NODE_T(que_thr_t) queue; /*!< list of runnable thread nodes in the server task queue */ diff --git a/storage/innobase/include/row0ins.h b/storage/innobase/include/row0ins.h index 8cb3a2f16cd..541a3b4e70e 100644 --- a/storage/innobase/include/row0ins.h +++ b/storage/innobase/include/row0ins.h @@ -180,6 +180,11 @@ row_ins_step( /*=========*/ que_thr_t* thr); /*!< in: query thread */ +/***********************************************************//** +Inserts a row to SYS_VTQ table. +@return error state */ +dberr_t vers_notify_vtq(que_thr_t * thr, mem_heap_t * heap); + /* Insert node structure */ struct ins_node_t{ diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index b08148578dc..7cc95b28c0d 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -1267,6 +1267,7 @@ struct trx_t { os_event_t wsrep_event; /* event waited for in srv_conc_slot */ #endif /* WITH_WSREP */ + bool vtq_notified; ulint magic_n; /** @return whether any persistent undo log has been generated */ diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i index cb2674ebddf..86f612b0273 100644 --- a/storage/innobase/include/univ.i +++ b/storage/innobase/include/univ.i @@ -494,6 +494,8 @@ typedef uint64_t ib_uint64_t; typedef uint32_t ib_uint32_t; #endif /* _WIN32 */ +typedef ib_uint64_t ullong; + #ifdef _WIN64 typedef unsigned __int64 ulint; typedef __int64 lint; diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index f596f3d8f27..4fa07aca808 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -3798,3 +3798,67 @@ error_handling: return(thr); } + +inline +void set_row_field_8(dtuple_t* row, int field_num, ib_uint64_t data, mem_heap_t* heap) +{ + dfield_t* dfield = dtuple_get_nth_field(row, field_num); + byte* buf = static_cast(mem_heap_alloc(heap, 8)); + mach_write_to_8(buf, data); + dfield_set_data(dfield, buf, 8); +} + +#include "my_time.h" +#include "sql_time.h" + +/***********************************************************//** +Inserts a row to SYS_VTQ table. +@return error state */ +UNIV_INTERN +dberr_t +vers_notify_vtq(que_thr_t* thr, mem_heap_t* heap) +{ + dberr_t err; + trx_t* trx = thr_get_trx(thr); + dict_table_t* sys_vtq = dict_sys->sys_vtq; + ins_node_t* node = ins_node_create(INS_DIRECT, sys_vtq, heap); + + node->select = NULL; + node->values_list = NULL; // for INS_VALUES + + dtuple_t* row = dtuple_create(heap, dict_table_get_n_cols(sys_vtq)); + dict_table_copy_types(row, sys_vtq); + + struct tm unix_time; + MYSQL_TIME mysql_time; + localtime_r(&trx->start_time, &unix_time); + localtime_to_TIME(&mysql_time, &unix_time); + mysql_time.second_part = trx->start_time_micro; + ullong start_time = pack_time(&mysql_time); + + set_row_field_8(row, DICT_FLD__SYS_VTQ__TRX_ID, trx->id, heap); + set_row_field_8(row, DICT_FLD__SYS_VTQ__BEGIN_TS - 2, start_time, heap); + set_row_field_8(row, DICT_FLD__SYS_VTQ__COMMIT_TS - 2, start_time, heap); + set_row_field_8(row, DICT_FLD__SYS_VTQ__CONCURR_TRX - 2, 3, heap); + + ins_node_set_new_row(node, row); + + trx_write_trx_id(node->trx_id_buf, trx->id); + err = lock_table(0, node->table, LOCK_IX, thr); + DBUG_EXECUTE_IF("ib_row_ins_ix_lock_wait", + err = DB_LOCK_WAIT;); + + if (err != DB_SUCCESS) { + goto end_func; + } + + node->trx_id = trx->id; + node->state = INS_NODE_ALLOC_ROW_ID; + err = row_ins(node, thr); + +end_func: + trx->error_state = err; + if (err != DB_SUCCESS) + fprintf(stderr, "InnoDB: failed to insert VTQ record (see SQL error message)\n"); + return err; +} diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 03d7ac628a7..68cc4372bef 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -1537,6 +1537,14 @@ error_exit: node->duplicate = NULL; + if (!trx->vtq_notified && DICT_TF2_FLAG_IS_SET(node->table, DICT_TF2_VERSIONED)) { + trx->vtq_notified = true; + err = vers_notify_vtq(thr, node->table->heap); + if (err != DB_SUCCESS) { + goto error_exit; + } + } + if (dict_table_has_fts_index(table)) { doc_id_t doc_id; @@ -1981,7 +1989,7 @@ run_again: err = trx->error_state; if (err != DB_SUCCESS) { - + error_exit: que_thr_stop_for_mysql(thr); if (err == DB_RECORD_NOT_FOUND) { @@ -2129,6 +2137,14 @@ run_again: } } + if (!trx->vtq_notified && DICT_TF2_FLAG_IS_SET(node->table, DICT_TF2_VERSIONED)) { + trx->vtq_notified = true; + err = vers_notify_vtq(thr, node->table->heap); + if (err != DB_SUCCESS) { + goto error; + } + } + trx->op_info = ""; que_thr_stop_for_mysql_no_error(thr, trx); diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index bcb52fc5bfb..93f1554b444 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -2534,6 +2534,10 @@ files_checked: err = dict_create_or_check_sys_tablespace(); if (err == DB_SUCCESS) { err = dict_create_or_check_sys_virtual(); + if (err == DB_SUCCESS) { + /* Create the SYS_VTQ system table */ + err = dict_create_or_check_vtq_table(); + } } } switch (err) { diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 36324c43970..e934d1501e9 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -1349,15 +1349,22 @@ trx_start_low( } } - if (trx->mysql_thd != NULL) { - trx->start_time = thd_start_time_in_secs(trx->mysql_thd); - trx->start_time_micro = thd_query_start_micro(trx->mysql_thd); + ut_usectime((ulong *)&trx->start_time, + (ulong *)&trx->start_time_micro); - } else { - trx->start_time = ut_time(); - trx->start_time_micro = 0; + if (trx->mysql_thd != NULL) { + time_t start_time = thd_start_time_in_secs(trx->mysql_thd); + ib_uint64_t start_utime = thd_query_start_micro(trx->mysql_thd); + if (start_time < trx->start_time || + (start_time == trx->start_time && start_utime < trx->start_time_micro)) + { + trx->start_time = start_time; + trx->start_time_micro = start_utime; + } } + trx->vtq_notified = false; + ut_a(trx->error_state == DB_SUCCESS); MONITOR_INC(MONITOR_TRX_ACTIVE); -- cgit v1.2.1 From 9186cae449eb0fa381b1d3be30e214f6dc5456c6 Mon Sep 17 00:00:00 2001 From: Kosov Eugene Date: Fri, 23 Sep 2016 18:03:02 +0300 Subject: Style: related to DBUG_ASSERT usage --- sql/table.cc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/sql/table.cc b/sql/table.cc index ca449d628d1..c9729d17d9c 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -7568,12 +7568,10 @@ void TABLE::vers_update_fields() { DBUG_ENTER("vers_update_fields"); - DBUG_ASSERT(versioned()); - bool res= !vers_start_field()->set_time(); - DBUG_ASSERT(res); - res= !vers_end_field()->set_max_timestamp(); - DBUG_ASSERT(res); - (void)res; + if (vers_start_field()->set_time()) + DBUG_ASSERT(0); + if (vers_end_field()->set_max_timestamp()) + DBUG_ASSERT(0); bitmap_set_bit(write_set, vers_start_field()->field_index); bitmap_set_bit(write_set, vers_end_field()->field_index); -- cgit v1.2.1 From 87507451e7beb3ae76f711f2796c407cbf7090f7 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Fri, 23 Sep 2016 16:01:14 +0000 Subject: SQL: fractions in I_S TIMESTAMP fields --- sql/item.h | 4 ++-- sql/sql_show.cc | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/sql/item.h b/sql/item.h index 7eea60e8213..e5a3215d13e 100644 --- a/sql/item.h +++ b/sql/item.h @@ -3622,10 +3622,10 @@ class Item_return_date_time :public Item_partition_func_safe_string enum_field_types date_time_field_type; public: Item_return_date_time(THD *thd, const char *name_arg, uint length_arg, - enum_field_types field_type_arg): + enum_field_types field_type_arg, uint dec_arg= 0): Item_partition_func_safe_string(thd, name_arg, length_arg, &my_charset_bin), date_time_field_type(field_type_arg) - { decimals= 0; } + { decimals= dec_arg; } enum_field_types field_type() const { return date_time_field_type; } }; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index e3613c1e0e7..084e98b143f 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -7730,7 +7730,8 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) if (!(item=new (mem_root) Item_return_date_time(thd, fields_info->field_name, strlen(fields_info->field_name), - fields_info->field_type))) + fields_info->field_type, + fields_info->field_length))) DBUG_RETURN(0); item->decimals= fields_info->field_length; break; -- cgit v1.2.1 From 7deb6cb39e98d0b2648528d5b6f4f4c2ed5b2e6f Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Sat, 24 Sep 2016 09:36:57 +0000 Subject: Scripts: WITH_INNOBASE_STORAGE_ENGINE fix 2 (590af2a4fda6e76b12b58b514099af408dcc40df) --- CMakeLists.txt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 29f672428a9..eec96eea542 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -364,12 +364,11 @@ IF(WITH_UNIT_TESTS) ENDIF() IF(WITH_INNOBASE_STORAGE_ENGINE) - SET(WITH_XTRADB_STORAGE_ENGINE OFF) - IF(PLUGIN_XTRADB STREQUAL STATIC) - SET(PLUGIN_XTRADB DYNAMIC) - ENDIF() + SET(PLUGIN_INNOBASE STATIC CACHE STRING "" FORCE) + SET(PLUGIN_XTRADB DYNAMIC CACHE STRING "" FORCE) ELSE() - SET(WITH_XTRADB_STORAGE_ENGINE ON) + SET(PLUGIN_INNOBASE DYNAMIC CACHE STRING "" FORCE) + SET(PLUGIN_XTRADB STATIC CACHE STRING "" FORCE) ENDIF() SET (MYSQLD_STATIC_PLUGIN_LIBS "" CACHE INTERNAL "") -- cgit v1.2.1 From 002a1bd0769fc85f1e4e4670b9cc3b907ab2e11b Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 26 Sep 2016 05:55:13 +0000 Subject: Scripts: use InnoDB in tests, XtraDB disabled --- mysql-test/suite.pm | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/mysql-test/suite.pm b/mysql-test/suite.pm index f501e610e53..f0f1c3aa697 100644 --- a/mysql-test/suite.pm +++ b/mysql-test/suite.pm @@ -7,16 +7,15 @@ sub skip_combinations { my @combinations; # disable innodb/xtradb combinatons for configurations that were not built - push @combinations, 'innodb_plugin' unless $ENV{HA_INNODB_SO}; + push @combinations, 'innodb_plugin'; # unless $ENV{HA_INNODB_SO}; - push @combinations, qw(xtradb innodb) unless $::mysqld_variables{'innodb'} eq "ON"; - - # unconditionally, for now in 10.2. Later it could check for xtradb I_S plugins - push @combinations, 'xtradb'; + # if something is compiled in, it's xtradb. innodb is MODULE_ONLY: + push @combinations, 'xtradb'; # unless $::mysqld_variables{'innodb'} eq "ON"; + # push @combinations, 'innodb'; # XtraDB is RECOMPILE_FOR_EMBEDDED, ha_xtradb.so cannot work with embedded server - push @combinations, 'xtradb_plugin' if not $ENV{HA_XTRADB_SO} - or $::opt_embedded_server; + push @combinations, 'xtradb_plugin'; # if not $ENV{HA_XTRADB_SO} + # or $::opt_embedded_server; my %skip = ( 'include/have_innodb.combinations' => [ @combinations ], 'include/have_xtradb.combinations' => [ @combinations ]); -- cgit v1.2.1 From bdb12d149992910e54051c8eb800ff2610712987 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 26 Sep 2016 08:37:53 +0000 Subject: IB: 0.2 part II * moved vers_notify_vtq() to commit phase; * low_level insert (load test passed); * rest of SYS_VTQ columns filled: COMMIT_TS, CONCURR_TRX; * savepoints support; * I_S.INNODB_SYS_VTQ adjustments: - limit to I_S_SYS_VTQ_LIMIT(10000) of most recent records; - CONCURR_TRX limit to I_S_MAX_CONCURR_TRX(100) with '...' truncation marker; - TIMESTAMP fields show fractions of seconds. --- CMakeLists.txt | 2 +- sql/sql_time.cc | 13 +++ sql/sql_time.h | 10 ++ storage/innobase/btr/btr0pcur.cc | 62 +++++++++- storage/innobase/dict/dict0load.cc | 91 ++++++++++----- storage/innobase/handler/ha_innodb.cc | 5 + storage/innobase/handler/i_s.cc | 21 ++-- storage/innobase/include/btr0pcur.h | 38 +++++++ storage/innobase/include/btr0pcur.ic | 36 ++++++ storage/innobase/include/dict0load.h | 6 +- storage/innobase/include/row0ins.h | 8 +- storage/innobase/include/trx0trx.h | 2 +- storage/innobase/include/trx0types.h | 1 + storage/innobase/row/row0ins.cc | 208 ++++++++++++++++++++++++---------- storage/innobase/row/row0mysql.cc | 17 +-- storage/innobase/trx/trx0roll.cc | 2 + storage/innobase/trx/trx0trx.cc | 5 +- 17 files changed, 407 insertions(+), 120 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index eec96eea542..869e65baf8d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -365,7 +365,7 @@ ENDIF() IF(WITH_INNOBASE_STORAGE_ENGINE) SET(PLUGIN_INNOBASE STATIC CACHE STRING "" FORCE) - SET(PLUGIN_XTRADB DYNAMIC CACHE STRING "" FORCE) + SET(PLUGIN_XTRADB NO CACHE STRING "" FORCE) ELSE() SET(PLUGIN_INNOBASE DYNAMIC CACHE STRING "" FORCE) SET(PLUGIN_XTRADB STATIC CACHE STRING "" FORCE) diff --git a/sql/sql_time.cc b/sql/sql_time.cc index cad4bae03e8..6f37f97feef 100644 --- a/sql/sql_time.cc +++ b/sql/sql_time.cc @@ -475,6 +475,19 @@ void localtime_to_TIME(MYSQL_TIME *to, struct tm *from) to->second= (int) from->tm_sec; } + +/* + Convert seconds since Epoch to TIME +*/ + +void unix_time_to_TIME(MYSQL_TIME *to, time_t secs, suseconds_t usecs) +{ + struct tm tm_time; + localtime_r(&secs, &tm_time); + localtime_to_TIME(to, &tm_time); + to->second_part = usecs; +} + void calc_time_from_sec(MYSQL_TIME *to, long seconds, long microseconds) { long t_seconds; diff --git a/sql/sql_time.h b/sql/sql_time.h index e0cab5cfa66..fd0c0273dcf 100644 --- a/sql/sql_time.h +++ b/sql/sql_time.h @@ -171,6 +171,16 @@ bool calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2, int lsign, MYSQL_TIME *l_time3, ulonglong fuzzydate); int my_time_compare(const MYSQL_TIME *a, const MYSQL_TIME *b); void localtime_to_TIME(MYSQL_TIME *to, struct tm *from); +void unix_time_to_TIME(MYSQL_TIME *to, time_t secs, suseconds_t usecs); + +inline +longlong unix_time_to_packed(time_t secs, suseconds_t usecs) +{ + MYSQL_TIME mysql_time; + unix_time_to_TIME(&mysql_time, secs, usecs); + return pack_time(&mysql_time); +} + void calc_time_from_sec(MYSQL_TIME *to, long seconds, long microseconds); uint calc_week(MYSQL_TIME *l_time, uint week_behaviour, uint *year); diff --git a/storage/innobase/btr/btr0pcur.cc b/storage/innobase/btr/btr0pcur.cc index 445aa3504b7..9160265aae9 100644 --- a/storage/innobase/btr/btr0pcur.cc +++ b/storage/innobase/btr/btr0pcur.cc @@ -452,6 +452,66 @@ btr_pcur_move_to_next_page( ut_d(page_check_dir(next_page)); } +/*********************************************************//** +Moves the persistent cursor to the last record on the previous page. Releases the +latch on the current page, and bufferunfixes it. Note that there must not be +modifications on the current page, as then the x-latch can be released only in +mtr_commit. */ +UNIV_INTERN +void +btr_pcur_move_to_prev_page( +/*=======================*/ + btr_pcur_t* cursor, /*!< in: persistent cursor; must be on the + last record of the current page */ + mtr_t* mtr) /*!< in: mtr */ +{ + ulint prev_page_no; + page_t* page; + buf_block_t* prev_block; + page_t* prev_page; + ulint mode; + + ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED); + ut_ad(cursor->latch_mode != BTR_NO_LATCHES); + ut_ad(btr_pcur_is_before_first_on_page(cursor)); + + cursor->old_stored = false; + + page = btr_pcur_get_page(cursor); + prev_page_no = btr_page_get_prev(page, mtr); + + ut_ad(prev_page_no != FIL_NULL); + + mode = cursor->latch_mode; + switch (mode) { + case BTR_SEARCH_TREE: + mode = BTR_SEARCH_LEAF; + break; + case BTR_MODIFY_TREE: + mode = BTR_MODIFY_LEAF; + } + + buf_block_t* block = btr_pcur_get_block(cursor); + + prev_block = btr_block_get( + page_id_t(block->page.id.space(), prev_page_no), + block->page.size, mode, + btr_pcur_get_btr_cur(cursor)->index, mtr); + + prev_page = buf_block_get_frame(prev_block); +#ifdef UNIV_BTR_DEBUG + ut_a(page_is_comp(prev_page) == page_is_comp(page)); + ut_a(btr_page_get_next(prev_page, mtr) + == btr_pcur_get_block(cursor)->page.id.page_no()); +#endif /* UNIV_BTR_DEBUG */ + + btr_leaf_page_release(btr_pcur_get_block(cursor), mode, mtr); + + page_cur_set_after_last(prev_block, btr_pcur_get_page_cur(cursor)); + + page_check_dir(prev_page); +} + /*********************************************************//** Moves the persistent cursor backward if it is on the first record of the page. Commits mtr. Note that to prevent a possible deadlock, the operation @@ -461,7 +521,7 @@ alphabetical position of the cursor is guaranteed to be sensible on return, but it may happen that the cursor is not positioned on the last record of any page, because the structure of the tree may have changed during the time when the cursor had no latches. */ -static +UNIV_INTERN void btr_pcur_move_backward_from_page( /*=============================*/ diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc index b646123048b..0fe6981f675 100644 --- a/storage/innobase/dict/dict0load.cc +++ b/storage/innobase/dict/dict0load.cc @@ -319,7 +319,10 @@ dict_getnext_system_low( rec_t* rec = NULL; while (!rec || rec_get_deleted_flag(rec, 0)) { - btr_pcur_move_to_next_user_rec(pcur, mtr); + if (pcur->search_mode == PAGE_CUR_L) + btr_pcur_move_to_prev_user_rec(pcur, mtr); + else + btr_pcur_move_to_next_user_rec(pcur, mtr); rec = btr_pcur_get_rec(pcur); @@ -346,7 +349,8 @@ dict_startscan_system( btr_pcur_t* pcur, /*!< out: persistent cursor to the record */ mtr_t* mtr, /*!< in: the mini-transaction */ - dict_system_id_t system_id) /*!< in: which system table to open */ + dict_system_id_t system_id, /*!< in: which system table to open */ + bool from_left) { dict_table_t* system_table; dict_index_t* clust_index; @@ -358,7 +362,7 @@ dict_startscan_system( clust_index = UT_LIST_GET_FIRST(system_table->indexes); - btr_pcur_open_at_index_side(true, clust_index, BTR_SEARCH_LEAF, pcur, + btr_pcur_open_at_index_side(from_left, clust_index, BTR_SEARCH_LEAF, pcur, true, 0, mtr); rec = dict_getnext_system_low(pcur, mtr); @@ -822,6 +826,15 @@ err_len: return(NULL); } + +inline +const char* dict_print_error(mem_heap_t* heap, ulint col, ulint len, ulint expected) +{ + return mem_heap_printf(heap, + "incorrect column %lu length in SYS_VTQ; got: %lu, expected: %lu", + col, len, expected); +} + /********************************************************************//** This function parses a SYS_VTQ record, extracts necessary information from the record and returns it to the caller. @@ -832,13 +845,15 @@ dict_process_sys_vtq( /*=======================*/ mem_heap_t* heap, /*!< in/out: heap memory */ const rec_t* rec, /*!< in: current rec */ -ullong* col_trx_id, /*!< out: field values */ +trx_id_t* col_trx_id, /*!< out: field values */ ullong* col_begin_ts, ullong* col_commit_ts, -ullong* col_concurr_trx) +char** col_concurr_trx) { - ulint len; - const byte* field; + ulint len, col, concurr_n; + const byte *field, *ptr; + char *out; + trx_id_t trx_id; if (rec_get_deleted_flag(rec, 0)) { return("delete-marked record in SYS_VTQ"); @@ -847,35 +862,57 @@ ullong* col_concurr_trx) if (rec_get_n_fields_old(rec) != DICT_NUM_FIELDS__SYS_VTQ) { return("wrong number of columns in SYS_VTQ record"); } - + /* TRX_ID */ field = rec_get_nth_field_old( - rec, DICT_FLD__SYS_VTQ__TRX_ID, &len); - if (len != sizeof(col_trx_id)) { - err_len: - return("incorrect column length in SYS_VTQ"); - } - *col_trx_id = mach_read_from_8(field); + rec, (col = DICT_FLD__SYS_VTQ__TRX_ID), &len); + + if (len != sizeof(trx_id_t)) + return dict_print_error(heap, col, len, sizeof(trx_id_t)); + *col_trx_id = mach_read_from_8(field); + /* BEGIN_TS */ field = rec_get_nth_field_old( - rec, DICT_FLD__SYS_VTQ__BEGIN_TS, &len); - if (len != sizeof(col_begin_ts)) { - goto err_len; - } + rec, (col = DICT_FLD__SYS_VTQ__BEGIN_TS), &len); + + if (len != sizeof(ullong)) + return dict_print_error(heap, col, len, sizeof(ullong)); + *col_begin_ts = mach_read_from_8(field); + /* COMMIT_TS */ + field = rec_get_nth_field_old( + rec, (col = DICT_FLD__SYS_VTQ__COMMIT_TS), &len); + if (len != sizeof(ullong)) + return dict_print_error(heap, col, len, sizeof(ullong)); + + *col_commit_ts = mach_read_from_8(field); + /* CONCURR_TRX */ field = rec_get_nth_field_old( - rec, DICT_FLD__SYS_VTQ__COMMIT_TS, &len); - if (len != sizeof(col_commit_ts)) { - goto err_len; + rec, (col = DICT_FLD__SYS_VTQ__CONCURR_TRX), &len); + concurr_n = len / sizeof(trx_id_t); + if (len != concurr_n * sizeof(trx_id_t)) + return dict_print_error(heap, col, len, concurr_n * sizeof(trx_id_t)); + + bool truncated = false; + if (concurr_n > I_S_MAX_CONCURR_TRX) { + concurr_n = I_S_MAX_CONCURR_TRX; + truncated = true; } - *col_commit_ts = mach_read_from_8(field); - field = rec_get_nth_field_old( - rec, DICT_FLD__SYS_VTQ__CONCURR_TRX, &len); - if (len != sizeof(col_concurr_trx)) { - goto err_len; + if (concurr_n == 0) { + *col_concurr_trx = NULL; + return(NULL); + } + *col_concurr_trx = static_cast(mem_heap_alloc(heap, concurr_n * (TRX_ID_MAX_LEN + 1) + 3 + 1)); + ptr = field, out = *col_concurr_trx; + for (ulint i = 0; i < concurr_n; + ++i, ptr += sizeof(trx_id_t)) + { + trx_id = mach_read_from_8(ptr); + out += ut_snprintf(out, TRX_ID_MAX_LEN + 1, TRX_ID_FMT " ", trx_id); } - *col_concurr_trx = mach_read_from_8(field); + if (truncated) + strcpy(out, "..."); return(NULL); } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 7e90511e9e1..acba2461f55 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -4816,6 +4816,11 @@ innobase_commit( if (commit_trx || (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) { + /* Notify VTQ on System Versioned tables update */ + if (trx->vtq_notify_on_commit) { + vers_notify_vtq(trx); + trx->vtq_notify_on_commit = false; + } DBUG_EXECUTE_IF("crash_innodb_before_commit", DBUG_SUICIDE();); diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index d53f4fe9df2..7125e2645aa 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -9690,10 +9690,11 @@ static ST_FIELD_INFO innodb_vtq_fields_info[] = #define SYS_VTQ_CONCURR_TRX 3 { STRUCT_FLD(field_name, "concurr_trx"), - STRUCT_FLD(field_length, 120), - STRUCT_FLD(field_type, MYSQL_TYPE_MEDIUM_BLOB), + // 3 for "..." if list is truncated + STRUCT_FLD(field_length, I_S_MAX_CONCURR_TRX * (TRX_ID_MAX_LEN + 1) + 3), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), STRUCT_FLD(value, 0), - STRUCT_FLD(field_flags, 0), + STRUCT_FLD(field_flags, MY_I_S_MAYBE_NULL), STRUCT_FLD(old_name, ""), STRUCT_FLD(open_method, SKIP_OPEN_TABLE) }, @@ -9712,7 +9713,7 @@ i_s_dict_fill_vtq( ullong col_trx_id, /*!< in: table fields */ ullong col_begin_ts, ullong col_commit_ts, - ullong col_concurr_trx, + char* col_concurr_trx, TABLE* table_to_fill) /*!< in/out: fill this table */ { Field** fields; @@ -9723,7 +9724,7 @@ i_s_dict_fill_vtq( OK(field_store_ullong(fields[SYS_VTQ_TRX_ID], col_trx_id)); OK(field_store_packed_ts(fields[SYS_VTQ_BEGIN_TS], col_begin_ts)); OK(field_store_packed_ts(fields[SYS_VTQ_COMMIT_TS], col_commit_ts)); - OK(field_store_ullong(fields[SYS_VTQ_CONCURR_TRX], col_concurr_trx)); + OK(field_store_string(fields[SYS_VTQ_CONCURR_TRX], col_concurr_trx)); OK(schema_table_store_record(thd, table_to_fill)); @@ -9736,7 +9737,7 @@ Loop through each record in SYS_VTQ, and extract the column information and fill the INFORMATION_SCHEMA.INNODB_SYS_VTQ table. @return 0 on success */ -static const int I_S_SYS_VTQ_LIMIT = 1000; // maximum number of records in I_S.INNODB_SYS_VTQ +static const int I_S_SYS_VTQ_LIMIT = 10000; // maximum number of records in I_S.INNODB_SYS_VTQ static int @@ -9764,16 +9765,16 @@ i_s_sys_vtq_fill_table( mutex_enter(&dict_sys->mutex); mtr_start(&mtr); - rec = dict_startscan_system(&pcur, &mtr, SYS_VTQ); + rec = dict_startscan_system(&pcur, &mtr, SYS_VTQ, false); for (int i = 0; rec && i < I_S_SYS_VTQ_LIMIT; ++i) { const char* err_msg; - ullong col_trx_id; + trx_id_t col_trx_id; ullong col_begin_ts; ullong col_commit_ts; - ullong col_concurr_trx; + char* col_concurr_trx; - /* Extract necessary information from a SYS_VTQ row */ + /* Extract necessary information from SYS_VTQ row */ err_msg = dict_process_sys_vtq( heap, rec, diff --git a/storage/innobase/include/btr0pcur.h b/storage/innobase/include/btr0pcur.h index e00af130479..6e85d01c19f 100644 --- a/storage/innobase/include/btr0pcur.h +++ b/storage/innobase/include/btr0pcur.h @@ -337,6 +337,17 @@ btr_pcur_move_to_next_user_rec( function may release the page latch */ mtr_t* mtr); /*!< in: mtr */ /*********************************************************//** +Moves the persistent cursor to the previous user record in the tree. If no user +records are left, the cursor ends up 'before first in tree'. +@return TRUE if the cursor moved forward, ending on a user record */ +UNIV_INLINE +ibool +btr_pcur_move_to_prev_user_rec( +/*===========================*/ + btr_pcur_t* cursor, /*!< in: persistent cursor; NOTE that the + function may release the page latch */ + mtr_t* mtr); /*!< in: mtr */ +/*********************************************************//** Moves the persistent cursor to the first record on the next page. Releases the latch on the current page, and bufferunfixes it. Note that there must not be modifications on the current page, @@ -347,6 +358,33 @@ btr_pcur_move_to_next_page( btr_pcur_t* cursor, /*!< in: persistent cursor; must be on the last record of the current page */ mtr_t* mtr); /*!< in: mtr */ +/*********************************************************//** +Moves the persistent cursor to the last record on the previous page. +Releases the latch on the current page, and bufferunfixes it. +Note that there must not be modifications on the current page, +as then the x-latch can be released only in mtr_commit. */ +void +btr_pcur_move_to_prev_page( +/*=======================*/ + btr_pcur_t* cursor, /*!< in: persistent cursor; must be on the + last record of the current page */ + mtr_t* mtr); /*!< in: mtr */ +/*********************************************************//** +Moves the persistent cursor backward if it is on the first record +of the page. Releases the latch on the current page, and bufferunfixes +it. Note that to prevent a possible deadlock, the operation first +stores the position of the cursor, releases the leaf latch, acquires +necessary latches and restores the cursor position again before returning. +The alphabetical position of the cursor is guaranteed to be sensible +on return, but it may happen that the cursor is not positioned on the +last record of any page, because the structure of the tree may have +changed while the cursor had no latches. */ +void +btr_pcur_move_backward_from_page( +/*=============================*/ + btr_pcur_t* cursor, /*!< in: persistent cursor, must be on the + first record of the current page */ + mtr_t* mtr); /*!< in: mtr */ #ifdef UNIV_DEBUG /*********************************************************//** Returns the btr cursor component of a persistent cursor. diff --git a/storage/innobase/include/btr0pcur.ic b/storage/innobase/include/btr0pcur.ic index 425593631d3..51b6adf8420 100644 --- a/storage/innobase/include/btr0pcur.ic +++ b/storage/innobase/include/btr0pcur.ic @@ -334,6 +334,42 @@ loop: goto loop; } +/*********************************************************//** +Moves the persistent cursor to the previous user record in the tree. If no user +records are left, the cursor ends up 'before first in tree'. +@return TRUE if the cursor moved forward, ending on a user record */ +UNIV_INLINE +ibool +btr_pcur_move_to_prev_user_rec( +/*===========================*/ + btr_pcur_t* cursor, /*!< in: persistent cursor; NOTE that the + function may release the page latch */ + mtr_t* mtr) /*!< in: mtr */ +{ + ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED); + ut_ad(cursor->latch_mode != BTR_NO_LATCHES); + cursor->old_stored = false; +loop: + if (btr_pcur_is_before_first_on_page(cursor)) { + + if (btr_pcur_is_before_first_in_tree(cursor, mtr)) { + + return(FALSE); + } + + btr_pcur_move_to_prev(cursor, mtr); + } else { + btr_pcur_move_to_prev_on_page(cursor); + } + + if (btr_pcur_is_on_user_rec(cursor)) { + + return(TRUE); + } + + goto loop; +} + /*********************************************************//** Moves the persistent cursor to the next record in the tree. If no records are left, the cursor stays 'after last in tree'. diff --git a/storage/innobase/include/dict0load.h b/storage/innobase/include/dict0load.h index 197a61b4ebe..6c0c1ddc267 100644 --- a/storage/innobase/include/dict0load.h +++ b/storage/innobase/include/dict0load.h @@ -182,7 +182,8 @@ dict_startscan_system( btr_pcur_t* pcur, /*!< out: persistent cursor to the record */ mtr_t* mtr, /*!< in: the mini-transaction */ - dict_system_id_t system_id); /*!< in: which system table to open */ + dict_system_id_t system_id, /*!< in: which system table to open */ + bool from_left = true); /********************************************************************//** This function get the next system table record as we scan the table. @return the record if found, NULL if end of scan. */ @@ -319,6 +320,7 @@ dict_process_sys_datafiles( This function parses a SYS_VTQ record, extracts necessary information from the record and returns it to the caller. @return error message, or NULL on success */ +#define I_S_MAX_CONCURR_TRX 100 UNIV_INTERN const char* dict_process_sys_vtq( @@ -328,7 +330,7 @@ const rec_t* rec, /*!< in: current rec */ ullong* col_trx_id, /*!< out: field values */ ullong* col_begin_ts, ullong* col_commit_ts, -ullong* col_concurr_trx); +char** col_concurr_trx); /** Update the record for space_id in SYS_TABLESPACES to this filepath. @param[in] space_id Tablespace ID diff --git a/storage/innobase/include/row0ins.h b/storage/innobase/include/row0ins.h index 541a3b4e70e..dc6ad2d34ad 100644 --- a/storage/innobase/include/row0ins.h +++ b/storage/innobase/include/row0ins.h @@ -95,9 +95,10 @@ row_ins_clust_index_entry_low( dtuple_t* entry, /*!< in/out: index entry to insert */ ulint n_ext, /*!< in: number of externally stored columns */ que_thr_t* thr, /*!< in: query thread or NULL */ - bool dup_chk_only) + bool dup_chk_only, /*!< in: if true, just do duplicate check and return. don't execute actual insert. */ + trx_t* trx = 0) MY_ATTRIBUTE((warn_unused_result)); /***************************************************************//** @@ -123,9 +124,10 @@ row_ins_sec_index_entry_low( trx_id_t trx_id, /*!< in: PAGE_MAX_TRX_ID during row_log_table_apply(), or 0 */ que_thr_t* thr, /*!< in: query thread */ - bool dup_chk_only) + bool dup_chk_only, /*!< in: if true, just do duplicate check and return. don't execute actual insert. */ + trx_t* trx = 0) MY_ATTRIBUTE((warn_unused_result)); /** Sets the values of the dtuple fields in entry from the values of appropriate columns in row. @@ -183,7 +185,7 @@ row_ins_step( /***********************************************************//** Inserts a row to SYS_VTQ table. @return error state */ -dberr_t vers_notify_vtq(que_thr_t * thr, mem_heap_t * heap); +void vers_notify_vtq(trx_t* trx); /* Insert node structure */ diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 7cc95b28c0d..a1de49cae1f 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -1267,7 +1267,7 @@ struct trx_t { os_event_t wsrep_event; /* event waited for in srv_conc_slot */ #endif /* WITH_WSREP */ - bool vtq_notified; + bool vtq_notify_on_commit; /*!< Notify VTQ for System Versioned update */ ulint magic_n; /** @return whether any persistent undo log has been generated */ diff --git a/storage/innobase/include/trx0types.h b/storage/innobase/include/trx0types.h index 8092246c7fa..45c3356d8ec 100644 --- a/storage/innobase/include/trx0types.h +++ b/storage/innobase/include/trx0types.h @@ -146,6 +146,7 @@ typedef ib_id_t undo_no_t; /** Transaction savepoint */ struct trx_savept_t{ undo_no_t least_undo_no; /*!< least undo number to undo */ + bool vtq_notify_on_commit; /*!< Notify VTQ for System Versioned update */ }; /** File objects */ diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 4fa07aca808..d071036e947 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -50,6 +50,7 @@ Created 4/20/1996 Heikki Tuuri #include "fts0types.h" #include "m_string.h" #include "gis0geo.h" +#include "sql_time.h" /************************************************************************* IMPORTANT NOTE: Any operation that generates redo MUST check that there @@ -2042,7 +2043,8 @@ row_ins_scan_sec_index_for_duplicate( que_thr_t* thr, /*!< in: query thread */ bool s_latch,/*!< in: whether index->lock is being held */ mtr_t* mtr, /*!< in/out: mini-transaction */ - mem_heap_t* offsets_heap) + mem_heap_t* offsets_heap, + trx_t* trx = 0) /*!< in/out: memory heap that can be emptied */ { ulint n_unique; @@ -2055,6 +2057,10 @@ row_ins_scan_sec_index_for_duplicate( DBUG_ENTER("row_ins_scan_sec_index_for_duplicate"); + ut_ad(thr || (trx && flags & BTR_NO_LOCKING_FLAG)); + if (!trx) + trx = thr_get_trx(thr); + ut_ad(s_latch == rw_lock_own_flagged( &index->lock, RW_LOCK_FLAG_S | RW_LOCK_FLAG_SX)); @@ -2086,7 +2092,7 @@ row_ins_scan_sec_index_for_duplicate( : BTR_SEARCH_LEAF, &pcur, mtr); - allow_duplicates = thr_get_trx(thr)->duplicates; + allow_duplicates = trx->duplicates; /* Scan index records and check if there is a duplicate */ @@ -2142,7 +2148,7 @@ row_ins_scan_sec_index_for_duplicate( index, offsets)) { err = DB_DUPLICATE_KEY; - thr_get_trx(thr)->error_info = index; + trx->error_info = index; /* If the duplicate is on hidden FTS_DOC_ID, state so in the error log */ @@ -2528,9 +2534,10 @@ row_ins_clust_index_entry_low( dtuple_t* entry, /*!< in/out: index entry to insert */ ulint n_ext, /*!< in: number of externally stored columns */ que_thr_t* thr, /*!< in: query thread */ - bool dup_chk_only) + bool dup_chk_only, /*!< in: if true, just do duplicate check and return. don't execute actual insert. */ + trx_t* trx) { btr_pcur_t pcur; btr_cur_t* cursor; @@ -2545,11 +2552,15 @@ row_ins_clust_index_entry_low( DBUG_ENTER("row_ins_clust_index_entry_low"); + ut_ad(thr || trx); + if (!trx) + trx = thr_get_trx(thr); + ut_ad(dict_index_is_clust(index)); ut_ad(!dict_index_is_unique(index) || n_uniq == dict_index_get_n_unique(index)); ut_ad(!n_uniq || n_uniq == dict_index_get_n_unique(index)); - ut_ad(!thr_get_trx(thr)->in_rollback); + ut_ad(!trx->in_rollback); mtr_start(&mtr); @@ -2612,7 +2623,10 @@ row_ins_clust_index_entry_low( if (flags == (BTR_CREATE_FLAG | BTR_NO_LOCKING_FLAG - | BTR_NO_UNDO_LOG_FLAG | BTR_KEEP_SYS_FLAG)) { + | BTR_NO_UNDO_LOG_FLAG | BTR_KEEP_SYS_FLAG) || !thr) { + // thr == 0 for SYS_VTQ table + ut_ad(thr || flags & + (BTR_NO_LOCKING_FLAG | BTR_NO_UNDO_LOG_FLAG | BTR_KEEP_SYS_FLAG)); /* Set no locks when applying log in online table rebuild. Only check for duplicates. */ err = row_ins_duplicate_error_in_clust_online( @@ -2627,7 +2641,7 @@ row_ins_clust_index_entry_low( /* fall through */ case DB_SUCCESS_LOCKED_REC: case DB_DUPLICATE_KEY: - thr_get_trx(thr)->error_info = cursor->index; + trx->error_info = cursor->index; } } else { /* Note that the following may return also @@ -2716,7 +2730,7 @@ err_exit: LSN_MAX, TRUE);); err = row_ins_index_entry_big_rec( entry, big_rec, offsets, &offsets_heap, index, - thr_get_trx(thr)->mysql_thd); + trx->mysql_thd); dtuple_convert_back_big_rec(index, entry, big_rec); } else { if (err == DB_SUCCESS @@ -2810,9 +2824,10 @@ row_ins_sec_index_entry_low( trx_id_t trx_id, /*!< in: PAGE_MAX_TRX_ID during row_log_table_apply(), or 0 */ que_thr_t* thr, /*!< in: query thread */ - bool dup_chk_only) + bool dup_chk_only, /*!< in: if true, just do duplicate check and return. don't execute actual insert. */ + trx_t* trx) { DBUG_ENTER("row_ins_sec_index_entry_low"); @@ -2826,6 +2841,10 @@ row_ins_sec_index_entry_low( rec_offs_init(offsets_); rtr_info_t rtr_info; + ut_ad(thr || trx); + if (!trx) + trx = thr_get_trx(thr); + ut_ad(!dict_index_is_clust(index)); ut_ad(mode == BTR_MODIFY_LEAF || mode == BTR_MODIFY_TREE); @@ -2867,7 +2886,7 @@ row_ins_sec_index_entry_low( } if (row_log_online_op_try( - index, entry, thr_get_trx(thr)->id)) { + index, entry, trx->id)) { goto func_exit; } } @@ -2876,7 +2895,7 @@ row_ins_sec_index_entry_low( the function will return in both low_match and up_match of the cursor sensible values */ - if (!thr_get_trx(thr)->check_unique_secondary) { + if (!trx->check_unique_secondary) { search_mode |= BTR_IGNORE_SEC_UNIQUE; } @@ -2919,8 +2938,6 @@ row_ins_sec_index_entry_low( } if (err != DB_SUCCESS) { - trx_t* trx = thr_get_trx(thr); - if (err == DB_DECRYPTION_FAILED) { ib_push_warning(trx->mysql_thd, DB_DECRYPTION_FAILED, @@ -2964,7 +2981,7 @@ row_ins_sec_index_entry_low( } err = row_ins_scan_sec_index_for_duplicate( - flags, index, entry, thr, check, &mtr, offsets_heap); + flags, index, entry, thr, check, &mtr, offsets_heap, trx); mtr_commit(&mtr); @@ -2973,7 +2990,7 @@ row_ins_sec_index_entry_low( break; case DB_DUPLICATE_KEY: if (!index->is_committed()) { - ut_ad(!thr_get_trx(thr) + ut_ad(!trx ->dict_operation_lock_mode); mutex_enter(&dict_sys->mutex); dict_set_corrupted_index_cache_only(index); @@ -3016,8 +3033,8 @@ row_ins_sec_index_entry_low( if (!(flags & BTR_NO_LOCKING_FLAG) && dict_index_is_unique(index) - && thr_get_trx(thr)->duplicates - && thr_get_trx(thr)->isolation_level >= TRX_ISO_REPEATABLE_READ) { + && trx->duplicates + && trx->isolation_level >= TRX_ISO_REPEATABLE_READ) { /* When using the REPLACE statement or ON DUPLICATE clause, a gap lock is taken on the position of the to-be-inserted record, @@ -3040,7 +3057,7 @@ row_ins_sec_index_entry_low( switch (err) { case DB_SUCCESS: case DB_SUCCESS_LOCKED_REC: - if (thr_get_trx(thr)->error_state != DB_DUPLICATE_KEY) { + if (trx->error_state != DB_DUPLICATE_KEY) { break; } /* Fall through (skip actual insert) after we have @@ -3050,7 +3067,7 @@ row_ins_sec_index_entry_low( } } - ut_ad(thr_get_trx(thr)->error_state == DB_SUCCESS); + ut_ad(trx->error_state == DB_SUCCESS); if (dup_chk_only) { goto func_exit; @@ -3802,63 +3819,134 @@ error_handling: inline void set_row_field_8(dtuple_t* row, int field_num, ib_uint64_t data, mem_heap_t* heap) { + static const ulint fsize = 8; dfield_t* dfield = dtuple_get_nth_field(row, field_num); - byte* buf = static_cast(mem_heap_alloc(heap, 8)); + ut_ad(dfield->type.len == fsize); + byte* buf = static_cast(mem_heap_alloc(heap, fsize)); mach_write_to_8(buf, data); - dfield_set_data(dfield, buf, 8); + dfield_set_data(dfield, buf, fsize); } -#include "my_time.h" -#include "sql_time.h" - /***********************************************************//** -Inserts a row to SYS_VTQ table. -@return error state */ -UNIV_INTERN +Inserts a row to SYS_VTQ, low level. +@return DB_SUCCESS if operation successfully completed, else error +code */ +static __attribute__((nonnull, warn_unused_result)) dberr_t -vers_notify_vtq(que_thr_t* thr, mem_heap_t* heap) +vers_row_ins_vtq_low(trx_t* trx, mem_heap_t* heap, dtuple_t* row) { dberr_t err; - trx_t* trx = thr_get_trx(thr); - dict_table_t* sys_vtq = dict_sys->sys_vtq; - ins_node_t* node = ins_node_create(INS_DIRECT, sys_vtq, heap); + dtuple_t* entry; + ulint n_index = 0; + dict_index_t* index = dict_table_get_first_index(dict_sys->sys_vtq); + static const ulint flags + = (BTR_KEEP_SYS_FLAG + | BTR_NO_LOCKING_FLAG + | BTR_NO_UNDO_LOG_FLAG); - node->select = NULL; - node->values_list = NULL; // for INS_VALUES + entry = row_build_index_entry(row, NULL, index, heap); - dtuple_t* row = dtuple_create(heap, dict_table_get_n_cols(sys_vtq)); - dict_table_copy_types(row, sys_vtq); + dfield_t* dfield = dtuple_get_nth_field(entry, DATA_TRX_ID); + ut_ad(dfield->type.len == DATA_TRX_ID_LEN); + dfield_set_data(dfield, mem_heap_alloc(heap, DATA_TRX_ID_LEN), DATA_TRX_ID_LEN); + row_upd_index_entry_sys_field(entry, index, DATA_TRX_ID, trx->id); - struct tm unix_time; - MYSQL_TIME mysql_time; - localtime_r(&trx->start_time, &unix_time); - localtime_to_TIME(&mysql_time, &unix_time); - mysql_time.second_part = trx->start_time_micro; - ullong start_time = pack_time(&mysql_time); + err = row_ins_clust_index_entry_low( + flags, BTR_MODIFY_TREE, index, index->n_uniq, entry, 0, NULL, false, trx); - set_row_field_8(row, DICT_FLD__SYS_VTQ__TRX_ID, trx->id, heap); - set_row_field_8(row, DICT_FLD__SYS_VTQ__BEGIN_TS - 2, start_time, heap); - set_row_field_8(row, DICT_FLD__SYS_VTQ__COMMIT_TS - 2, start_time, heap); - set_row_field_8(row, DICT_FLD__SYS_VTQ__CONCURR_TRX - 2, 3, heap); + switch (err) { + case DB_SUCCESS: + break; + case DB_SUCCESS_LOCKED_REC: + /* The row had already been copied to the table. */ + fprintf(stderr, "InnoDB: duplicate VTQ record!\n"); + return DB_SUCCESS; + default: + return err; + } - ins_node_set_new_row(node, row); + mem_heap_t* offsets_heap = mem_heap_create(1024); - trx_write_trx_id(node->trx_id_buf, trx->id); - err = lock_table(0, node->table, LOCK_IX, thr); - DBUG_EXECUTE_IF("ib_row_ins_ix_lock_wait", - err = DB_LOCK_WAIT;); + do { + n_index++; - if (err != DB_SUCCESS) { - goto end_func; - } + if (!(index = dict_table_get_next_index(index))) { + break; + } - node->trx_id = trx->id; - node->state = INS_NODE_ALLOC_ROW_ID; - err = row_ins(node, thr); + if (index->type & DICT_FTS) { + continue; + } -end_func: - trx->error_state = err; - if (err != DB_SUCCESS) - fprintf(stderr, "InnoDB: failed to insert VTQ record (see SQL error message)\n"); + entry = row_build_index_entry(row, NULL, index, heap); + err = row_ins_sec_index_entry_low( + flags, BTR_MODIFY_TREE, + index, offsets_heap, heap, entry, trx->id, NULL, false, trx); + + ///* Report correct index name for duplicate key error. */ + // No need to report on commit phase? + //if (err == DB_DUPLICATE_KEY) { + // trx->error_key_num = n_index; + //} + } while (err == DB_SUCCESS); + + mem_heap_free(offsets_heap); return err; } + +/***********************************************************//** +Inserts a row to SYS_VTQ table. +@return error state */ +void vers_notify_vtq(trx_t* trx) +{ + dberr_t err; + mem_heap_t* heap = mem_heap_create(1024); + dtuple_t* row = dtuple_create(heap, dict_table_get_n_cols(dict_sys->sys_vtq)); + + ulint now_secs, now_usecs; + ut_usectime(&now_secs, &now_usecs); + ullong begin_ts = unix_time_to_packed(trx->start_time, trx->start_time_micro); + ullong commit_ts = unix_time_to_packed(now_secs, now_usecs); + + dict_table_copy_types(row, dict_sys->sys_vtq); + set_row_field_8(row, DICT_FLD__SYS_VTQ__TRX_ID, trx->id, heap); + set_row_field_8(row, DICT_FLD__SYS_VTQ__BEGIN_TS - 2, begin_ts, heap); + set_row_field_8(row, DICT_FLD__SYS_VTQ__COMMIT_TS - 2, commit_ts, heap); + + dfield_t* dfield = dtuple_get_nth_field(row, DICT_FLD__SYS_VTQ__CONCURR_TRX - 2); + mutex_enter(&trx_sys->mutex); + trx_ut_list_t &rw_list = trx_sys->rw_trx_list; + if (rw_list.count > 1) { + byte* buf = static_cast(mem_heap_alloc(heap, rw_list.count * 8)); + byte* ptr = buf; + ulint count = 0; + + for (trx_t* ctrx = UT_LIST_GET_FIRST(rw_list); + ctrx != NULL; + ctrx = UT_LIST_GET_NEXT(trx_list, ctrx)) + { + if (ctrx == trx || ctrx->state == TRX_STATE_NOT_STARTED) + continue; + + mach_write_to_8(ptr, ctrx->id); + ++count; + ptr += 8; + } + + if (count) + dfield_set_data(dfield, buf, count * 8); + else + dfield_set_data(dfield, NULL, 0); + } else { + // there must be at least current transaction + ut_ad(rw_list.count == 1 && UT_LIST_GET_FIRST(rw_list) == trx); + dfield_set_data(dfield, NULL, 0); + } + mutex_exit(&trx_sys->mutex); + + err = vers_row_ins_vtq_low(trx, heap, row); + if (DB_SUCCESS != err) + fprintf(stderr, "InnoDB: failed to insert VTQ record (error %d)\n", err); + + mem_heap_free(heap); +} diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 68cc4372bef..c08b608e006 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -1537,12 +1537,8 @@ error_exit: node->duplicate = NULL; - if (!trx->vtq_notified && DICT_TF2_FLAG_IS_SET(node->table, DICT_TF2_VERSIONED)) { - trx->vtq_notified = true; - err = vers_notify_vtq(thr, node->table->heap); - if (err != DB_SUCCESS) { - goto error_exit; - } + if (!trx->vtq_notify_on_commit && DICT_TF2_FLAG_IS_SET(node->table, DICT_TF2_VERSIONED)) { + trx->vtq_notify_on_commit = true; } if (dict_table_has_fts_index(table)) { @@ -1989,7 +1985,6 @@ run_again: err = trx->error_state; if (err != DB_SUCCESS) { - error_exit: que_thr_stop_for_mysql(thr); if (err == DB_RECORD_NOT_FOUND) { @@ -2137,12 +2132,8 @@ run_again: } } - if (!trx->vtq_notified && DICT_TF2_FLAG_IS_SET(node->table, DICT_TF2_VERSIONED)) { - trx->vtq_notified = true; - err = vers_notify_vtq(thr, node->table->heap); - if (err != DB_SUCCESS) { - goto error; - } + if (!trx->vtq_notify_on_commit && DICT_TF2_FLAG_IS_SET(node->table, DICT_TF2_VERSIONED)) { + trx->vtq_notify_on_commit = true; } trx->op_info = ""; diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc index ec723375fe9..b695d271051 100644 --- a/storage/innobase/trx/trx0roll.cc +++ b/storage/innobase/trx/trx0roll.cc @@ -128,6 +128,7 @@ trx_rollback_to_savepoint_low( } else { trx->lock.que_state = TRX_QUE_RUNNING; MONITOR_INC(MONITOR_TRX_ROLLBACK_SAVEPOINT); + trx->vtq_notify_on_commit = savept->vtq_notify_on_commit; } ut_a(trx->error_state == DB_SUCCESS); @@ -614,6 +615,7 @@ trx_savept_take( trx_savept_t savept; savept.least_undo_no = trx->undo_no; + savept.vtq_notify_on_commit = trx->vtq_notify_on_commit; return(savept); } diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index e934d1501e9..9b6159fc81e 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -470,6 +470,8 @@ trx_create_low() trx_free(). */ ut_a(trx->mod_tables.size() == 0); + trx->vtq_notify_on_commit = false; + #ifdef WITH_WSREP trx->wsrep_event = NULL; #endif /* WITH_WSREP */ @@ -1363,8 +1365,7 @@ trx_start_low( } } - trx->vtq_notified = false; - + trx->vtq_notify_on_commit = false; ut_a(trx->error_state == DB_SUCCESS); MONITOR_INC(MONITOR_TRX_ACTIVE); -- cgit v1.2.1 From 3b64fed50401a461101b7d3d603b5cce846e3698 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 28 Sep 2016 08:56:02 +0000 Subject: Style: renamed prepare_keys_for_sys_ver() --- sql/sql_table.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 3913b14ccc8..620f580d688 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4341,14 +4341,13 @@ bool Column_definition::sp_prepare_create_field(THD *thd, MEM_ROOT *mem_root) static bool -prepare_keys_for_sys_ver(THD *thd, +vers_prepare_keys(THD *thd, HA_CREATE_INFO *create_info, Alter_info *alter_info, KEY **key_info, uint key_count) { - if (!create_info->versioned()) - return false; + DBUG_ASSERT(create_info->versioned()); const System_versioning_info *versioning_info= create_info->get_system_versioning_info(); @@ -4645,7 +4644,7 @@ handler *mysql_create_frm_image(THD *thd, goto err; } } - if(prepare_keys_for_sys_ver(thd, create_info, alter_info, key_info, + if(vers_prepare_keys(thd, create_info, alter_info, key_info, *key_count)) goto err; } -- cgit v1.2.1 From 23f4e40839bd80d4309a41b21245f3d9c27a660b Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 26 Sep 2016 08:24:39 +0000 Subject: Tests: insert, update, delete for VTQ --- mysql-test/r/delete.result | 100 +++++++++++++++++++++++++++++++++++++++++++++ mysql-test/r/insert.result | 36 ++++++++++++++++ mysql-test/r/update.result | 6 +++ mysql-test/t/delete.opt | 1 + mysql-test/t/delete.test | 41 +++++++++++++++++++ mysql-test/t/insert.opt | 1 + mysql-test/t/insert.test | 23 +++++++++++ mysql-test/t/update.opt | 1 + mysql-test/t/update.test | 5 +++ 9 files changed, 214 insertions(+) create mode 100644 mysql-test/t/delete.opt create mode 100644 mysql-test/t/insert.opt create mode 100644 mysql-test/t/update.opt diff --git a/mysql-test/r/delete.result b/mysql-test/r/delete.result index 1ee160b6864..ee1d7524541 100644 --- a/mysql-test/r/delete.result +++ b/mysql-test/r/delete.result @@ -611,3 +611,103 @@ XNo Sys_end < '2038-01-19 03:14:07' 9 1 DROP VIEW vt1; DROP TABLE t1; +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +create table t1 ( +XNo INT UNSIGNED, +Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, +Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, +PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) +) WITH SYSTEM VERSIONING ENGINE InnoDB; +INSERT INTO t1(XNo) VALUES(0); +INSERT INTO t1(XNo) VALUES(1); +INSERT INTO t1(XNo) VALUES(2); +INSERT INTO t1(XNo) VALUES(3); +INSERT INTO t1(XNo) VALUES(4); +INSERT INTO t1(XNo) VALUES(5); +INSERT INTO t1(XNo) VALUES(6); +INSERT INTO t1(XNo) VALUES(7); +INSERT INTO t1(XNo) VALUES(8); +INSERT INTO t1(XNo) VALUES(9); +SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; +XNo Sys_end < '2038-01-19 03:14:07' +0 0 +1 0 +2 0 +3 0 +4 0 +5 0 +6 0 +7 0 +8 0 +9 0 +DELETE FROM t1 WHERE XNo = 0; +SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; +XNo Sys_end < '2038-01-19 03:14:07' +0 1 +1 0 +2 0 +3 0 +4 0 +5 0 +6 0 +7 0 +8 0 +9 0 +DELETE FROM t1 WHERE XNo = 1; +SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; +XNo Sys_end < '2038-01-19 03:14:07' +0 1 +1 1 +2 0 +3 0 +4 0 +5 0 +6 0 +7 0 +8 0 +9 0 +DELETE FROM t1 WHERE XNo > 5; +CREATE VIEW vt1 AS SELECT XNo FROM t1; +SELECT XNo FROM vt1; +XNo +2 +3 +4 +5 +DELETE FROM vt1 WHERE XNo = 3; +SELECT XNo FROM vt1; +XNo +2 +4 +5 +SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; +XNo Sys_end < '2038-01-19 03:14:07' +0 1 +1 1 +2 0 +3 1 +4 0 +5 0 +6 1 +7 1 +8 1 +9 1 +DROP VIEW vt1; +DROP TABLE t1; +SET @i = 0; +SELECT @i:=@i+1 AS No, trx_id > 0 AS A, begin_ts > '2015-1-1 0:0:0' AS B, commit_ts > begin_ts AS C, concurr_trx IS NULL AS D FROM INFORMATION_SCHEMA.INNODB_VTQ WHERE trx_id > @start_trx_id; +No A B C D +1 1 1 1 1 +2 1 1 1 1 +3 1 1 1 1 +4 1 1 1 1 +5 1 1 1 1 +6 1 1 1 1 +7 1 1 1 1 +8 1 1 1 1 +9 1 1 1 1 +10 1 1 1 1 +11 1 1 1 1 +12 1 1 1 1 +13 1 1 1 1 +14 1 1 1 1 diff --git a/mysql-test/r/insert.result b/mysql-test/r/insert.result index 5837e1faa44..7c9776732c9 100644 --- a/mysql-test/r/insert.result +++ b/mysql-test/r/insert.result @@ -722,6 +722,7 @@ DROP TABLE t1; # # SET @@session.time_zone='+00:00'; +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; INSERT INTO t1(x, y) VALUES(3, 4); INSERT INTO t1(x, y) VALUES(2, 3); @@ -826,3 +827,38 @@ x y Sys_end DROP TABLE t1; DROP VIEW vt1_1; DROP VIEW vt1_2; +SET @i = 0; +SELECT @i:=@i+1 AS No, trx_id > 0 AS A, begin_ts > '2015-1-1 0:0:0' AS B, commit_ts > begin_ts AS C, concurr_trx IS NULL AS D FROM INFORMATION_SCHEMA.INNODB_VTQ WHERE trx_id > @start_trx_id; +No A B C D +1 1 1 1 1 +2 1 1 1 1 +3 1 1 1 1 +4 1 1 1 1 +5 1 1 1 1 +6 1 1 1 1 +7 1 1 1 1 +8 1 1 1 1 +9 1 1 1 1 +10 1 1 1 1 +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +CREATE TABLE t1(x INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; +CREATE TABLE t2(x INT UNSIGNED) ENGINE=InnoDB; +START TRANSACTION; +INSERT INTO t1(x) VALUES(1); +COMMIT; +SET @i = 0; +SELECT @i:=@i+1 AS No, trx_id > 0 AS A, begin_ts > '2015-1-1 0:0:0' AS B, commit_ts > begin_ts AS C, concurr_trx IS NULL AS D FROM INFORMATION_SCHEMA.INNODB_VTQ WHERE trx_id > @start_trx_id; +No A B C D +1 1 1 1 1 +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +START TRANSACTION; +INSERT INTO t2(x) VALUES(1); +SAVEPOINT a; +INSERT INTO t1(x) VALUES(1); +ROLLBACK TO a; +COMMIT; +SET @i = 0; +SELECT @i:=@i+1 AS No, trx_id > 0 AS A, begin_ts > '2015-1-1 0:0:0' AS B, commit_ts > begin_ts AS C, concurr_trx IS NULL AS D FROM INFORMATION_SCHEMA.INNODB_VTQ WHERE trx_id > @start_trx_id; +No A B C D +DROP TABLE t1; +DROP TABLE t2; diff --git a/mysql-test/r/update.result b/mysql-test/r/update.result index cab57d4ef3d..2933bb3b3ce 100644 --- a/mysql-test/r/update.result +++ b/mysql-test/r/update.result @@ -771,6 +771,7 @@ x y 8 8000 9 9000 DROP TABLE t1; +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; INSERT INTO t1(x, y) VALUES (1, 1000), @@ -819,3 +820,8 @@ x y 8 8000 9 9000 DROP TABLE t1; +SET @i = 0; +SELECT @i:=@i+1 AS No, trx_id > 0 AS A, begin_ts > '2015-1-1 0:0:0' AS B, commit_ts > begin_ts AS C, concurr_trx IS NULL AS D FROM INFORMATION_SCHEMA.INNODB_VTQ WHERE trx_id > @start_trx_id; +No A B C D +1 1 1 1 1 +2 1 1 1 1 diff --git a/mysql-test/t/delete.opt b/mysql-test/t/delete.opt new file mode 100644 index 00000000000..32a25eea24f --- /dev/null +++ b/mysql-test/t/delete.opt @@ -0,0 +1 @@ +--loose-innodb-vtq diff --git a/mysql-test/t/delete.test b/mysql-test/t/delete.test index a91e6ddf82e..1832067e75c 100644 --- a/mysql-test/t/delete.test +++ b/mysql-test/t/delete.test @@ -626,3 +626,44 @@ SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIME DROP VIEW vt1; DROP TABLE t1; + +-- source include/have_innodb.inc + +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; + +create table t1 ( + XNo INT UNSIGNED, + Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, + Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) +) WITH SYSTEM VERSIONING ENGINE InnoDB; + +INSERT INTO t1(XNo) VALUES(0); +INSERT INTO t1(XNo) VALUES(1); +INSERT INTO t1(XNo) VALUES(2); +INSERT INTO t1(XNo) VALUES(3); +INSERT INTO t1(XNo) VALUES(4); +INSERT INTO t1(XNo) VALUES(5); +INSERT INTO t1(XNo) VALUES(6); +INSERT INTO t1(XNo) VALUES(7); +INSERT INTO t1(XNo) VALUES(8); +INSERT INTO t1(XNo) VALUES(9); + +SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; +DELETE FROM t1 WHERE XNo = 0; +SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; +DELETE FROM t1 WHERE XNo = 1; +SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; +DELETE FROM t1 WHERE XNo > 5; + +CREATE VIEW vt1 AS SELECT XNo FROM t1; + +SELECT XNo FROM vt1; +DELETE FROM vt1 WHERE XNo = 3; +SELECT XNo FROM vt1; +SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; + +DROP VIEW vt1; +DROP TABLE t1; + +SET @i = 0; SELECT @i:=@i+1 AS No, trx_id > 0 AS A, begin_ts > '2015-1-1 0:0:0' AS B, commit_ts > begin_ts AS C, concurr_trx IS NULL AS D FROM INFORMATION_SCHEMA.INNODB_VTQ WHERE trx_id > @start_trx_id; diff --git a/mysql-test/t/insert.opt b/mysql-test/t/insert.opt new file mode 100644 index 00000000000..32a25eea24f --- /dev/null +++ b/mysql-test/t/insert.opt @@ -0,0 +1 @@ +--loose-innodb-vtq diff --git a/mysql-test/t/insert.test b/mysql-test/t/insert.test index 7a4523a3f49..f806d450bcd 100644 --- a/mysql-test/t/insert.test +++ b/mysql-test/t/insert.test @@ -583,6 +583,7 @@ DROP TABLE t1; SET @@session.time_zone='+00:00'; +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; INSERT INTO t1(x, y) VALUES(3, 4); INSERT INTO t1(x, y) VALUES(2, 3); @@ -646,3 +647,25 @@ SELECT x, y, Sys_end FROM vt1_2; DROP TABLE t1; DROP VIEW vt1_1; DROP VIEW vt1_2; + +SET @i = 0; SELECT @i:=@i+1 AS No, trx_id > 0 AS A, begin_ts > '2015-1-1 0:0:0' AS B, commit_ts > begin_ts AS C, concurr_trx IS NULL AS D FROM INFORMATION_SCHEMA.INNODB_VTQ WHERE trx_id > @start_trx_id; + +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +CREATE TABLE t1(x INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; +CREATE TABLE t2(x INT UNSIGNED) ENGINE=InnoDB; +START TRANSACTION; +INSERT INTO t1(x) VALUES(1); +COMMIT; + +SET @i = 0; SELECT @i:=@i+1 AS No, trx_id > 0 AS A, begin_ts > '2015-1-1 0:0:0' AS B, commit_ts > begin_ts AS C, concurr_trx IS NULL AS D FROM INFORMATION_SCHEMA.INNODB_VTQ WHERE trx_id > @start_trx_id; + +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +START TRANSACTION; +INSERT INTO t2(x) VALUES(1); +SAVEPOINT a; +INSERT INTO t1(x) VALUES(1); +ROLLBACK TO a; +COMMIT; +SET @i = 0; SELECT @i:=@i+1 AS No, trx_id > 0 AS A, begin_ts > '2015-1-1 0:0:0' AS B, commit_ts > begin_ts AS C, concurr_trx IS NULL AS D FROM INFORMATION_SCHEMA.INNODB_VTQ WHERE trx_id > @start_trx_id; +DROP TABLE t1; +DROP TABLE t2; diff --git a/mysql-test/t/update.opt b/mysql-test/t/update.opt new file mode 100644 index 00000000000..32a25eea24f --- /dev/null +++ b/mysql-test/t/update.opt @@ -0,0 +1 @@ +--loose-innodb-vtq diff --git a/mysql-test/t/update.test b/mysql-test/t/update.test index 5dfc623acc8..a1e96c88a6b 100644 --- a/mysql-test/t/update.test +++ b/mysql-test/t/update.test @@ -677,6 +677,9 @@ SELECT x, y FROM t1; SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; DROP TABLE t1; +-- source include/have_innodb.inc + +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; INSERT INTO t1(x, y) VALUES (1, 1000), @@ -693,3 +696,5 @@ UPDATE t1 SET y = y + 1 WHERE x > 7; SELECT x, y FROM t1; SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; DROP TABLE t1; + +SET @i = 0; SELECT @i:=@i+1 AS No, trx_id > 0 AS A, begin_ts > '2015-1-1 0:0:0' AS B, commit_ts > begin_ts AS C, concurr_trx IS NULL AS D FROM INFORMATION_SCHEMA.INNODB_VTQ WHERE trx_id > @start_trx_id; -- cgit v1.2.1 From 1ec7dbe1766f00c542971784b967cb6a738e3a57 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Thu, 29 Sep 2016 11:12:46 +0000 Subject: IB: 0.2 part III * versioned DML: INSERT, UPDATE, DELETE; * general refactoring and fixes. Warning: breaks 'insert' and 'update' tests since they require part IV. --- sql/field.cc | 24 +++++++-- sql/field.h | 22 +++++---- sql/handler.h | 12 +++++ sql/share/errmsg-utf8.txt | 6 +++ sql/sql_base.cc | 4 +- sql/sql_delete.cc | 10 ++-- sql/sql_insert.cc | 49 +++++++++++-------- sql/sql_insert.h | 2 +- sql/sql_select.cc | 4 +- sql/sql_show.cc | 4 +- sql/sql_update.cc | 71 ++++++++++++++------------- sql/table.cc | 92 ++++++++++++++++++++++------------- sql/table.h | 17 +++++-- storage/innobase/dict/dict0mem.cc | 10 ++++ storage/innobase/handler/ha_innodb.cc | 22 +++++++-- storage/innobase/include/data0type.h | 2 + storage/innobase/include/dict0mem.h | 8 ++- storage/innobase/include/row0ins.h | 4 ++ storage/innobase/include/row0ins.ic | 44 +++++++++++++++++ storage/innobase/include/row0mysql.h | 5 +- storage/innobase/row/row0ins.cc | 16 ++---- storage/innobase/row/row0mysql.cc | 49 +++++++++++++++++-- storage/xtradb/include/row0ins.ic | 18 +++++++ 23 files changed, 353 insertions(+), 142 deletions(-) create mode 100644 storage/innobase/include/row0ins.ic diff --git a/sql/field.cc b/sql/field.cc index cb91e93ec5e..604965be254 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4356,6 +4356,20 @@ void Field_longlong::sql_type(String &res) const add_zerofill_and_unsigned(res); } +bool Field_longlong::set_max() +{ + ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + int8store(ptr, ULONGLONG_MAX); + return FALSE; +} + +bool Field_longlong::is_max() +{ + ASSERT_COLUMN_MARKED_FOR_READ; + ulonglong j; + j = sint8korr(ptr); + return j == ULONGLONG_MAX; +} /* Floating-point numbers @@ -5423,9 +5437,10 @@ void Field_timestampf::store_TIME(my_time_t timestamp, ulong sec_part) my_timestamp_to_binary(&tm, ptr, dec); } -bool Field_timestampf::set_max_timestamp() +bool Field_timestampf::set_max() { - DBUG_ENTER("Field_timestampf::set_max_timestamp"); + DBUG_ENTER("Field_timestampf::set_max"); + ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; mi_int4store(ptr, 0x7fffffff); memset(ptr + 4, 0x0, value_length() - 4); @@ -5433,9 +5448,10 @@ bool Field_timestampf::set_max_timestamp() DBUG_RETURN(FALSE); } -bool Field_timestampf::is_max_timestamp() +bool Field_timestampf::is_max() { - DBUG_ENTER("Field_timestampf::is_max_timestamp"); + DBUG_ENTER("Field_timestampf::is_max"); + ASSERT_COLUMN_MARKED_FOR_READ; DBUG_RETURN(mi_sint4korr(ptr) == 0x7fffffff); } diff --git a/sql/field.h b/sql/field.h index 3513a773ef4..4b6607fa099 100644 --- a/sql/field.h +++ b/sql/field.h @@ -677,17 +677,16 @@ public: { DBUG_ASSERT(0); } /** - Is used by System Versioning. + Used by System Versioning. */ - virtual bool set_max_timestamp() { - return true; - } + virtual bool set_max() + { DBUG_ASSERT(0); return false; } + /** - Is used by System Versioning. + Used by System Versioning. */ - virtual bool is_max_timestamp() { - return false; - } + virtual bool is_max() + { DBUG_ASSERT(0); return false; } uchar *ptr; // Position to field in record /** @@ -2173,6 +2172,9 @@ public: { return unpack_int64(to, from, from_end); } + + bool set_max(); + bool is_max(); }; @@ -2582,8 +2584,8 @@ public: { return memcmp(a_ptr, b_ptr, pack_length()); } - virtual bool set_max_timestamp(); - virtual bool is_max_timestamp(); + bool set_max(); + bool is_max(); void store_TIME(my_time_t timestamp, ulong sec_part); my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const; uint size_of() const { return sizeof(*this); } diff --git a/sql/handler.h b/sql/handler.h index 986896cc48b..b50e1b82ed2 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1385,6 +1385,11 @@ struct handlerton */ int (*discover_table_structure)(handlerton *hton, THD* thd, TABLE_SHARE *share, HA_CREATE_INFO *info); + + /* + Engine supports System Versioning + */ + bool versioned(); }; @@ -1432,6 +1437,7 @@ handlerton *ha_default_tmp_handlerton(THD *thd); */ #define HTON_NO_BINLOG_ROW_OPT (1 << 9) #define HTON_SUPPORTS_EXTENDED_KEYS (1 <<10) //supports extended keys +#define HTON_SUPPORTS_SYS_VERSIONING (1 << 11) //Engine supports System Versioning // MySQL compatibility. Unused. #define HTON_SUPPORTS_FOREIGN_KEYS (1 << 0) //Foreign key constraint supported. @@ -4485,4 +4491,10 @@ void print_keydup_error(TABLE *table, KEY *key, myf errflag); int del_global_index_stat(THD *thd, TABLE* table, KEY* key_info); int del_global_table_stat(THD *thd, LEX_STRING *db, LEX_STRING *table); + +inline +bool handlerton::versioned() +{ + return flags & HTON_SUPPORTS_SYS_VERSIONING; +} #endif /* HANDLER_INCLUDED */ diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 380d992a89b..f3859b5ba4a 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7531,3 +7531,9 @@ ER_SYS_START_FIELD_MUST_BE_TIMESTAMP ER_SYS_END_FIELD_MUST_BE_TIMESTAMP eng "System end field must be of type TIMESTAMP" + +ER_SYS_START_FIELD_MUST_BE_BIGINT + eng "System start field must be of type BIGINT UNSIGNED" + +ER_SYS_END_FIELD_MUST_BE_BIGINT + eng "System end field must be of type BIGINT UNSIGNED" diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 1af45c12331..89f1798d36d 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7962,7 +7962,7 @@ fill_record(THD *thd, TABLE *table_arg, List &fields, List &values, ER_THD(thd, ER_WARNING_NON_DEFAULT_VALUE_FOR_VIRTUAL_COLUMN), rfield->field_name, table->s->table_name.str); } - if (table->versioned() && rfield->is_generated() && + if (table->versioned_by_sql() && rfield->is_generated() && !ignore_errors) { my_error(ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER, MYF(0)); @@ -8216,7 +8216,7 @@ fill_record(THD *thd, TABLE *table, Field **ptr, List &values, } } - if (table->versioned() && field->is_generated() && + if (table->versioned_by_sql() && field->is_generated() && !ignore_errors) { my_error(ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER, MYF(0)); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index b739197ca45..5af9b326eba 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -216,7 +216,7 @@ inline int TABLE::delete_row() { int error; - if (!versioned()) + if (!versioned_by_sql()) error= file->ha_delete_row(record[0]); else { @@ -360,7 +360,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, if (!with_select && !using_limit && const_cond_result && (!thd->is_current_stmt_binlog_format_row() && !(table->triggers && table->triggers->has_delete_triggers())) - && !table->versioned()) + && !table->versioned_by_sql()) { /* Update the table->file->stats.records number */ table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); @@ -576,8 +576,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, while (!(error=info.read_record(&info)) && !thd->killed && ! thd->is_error()) { - if (table->versioned() && - !table->vers_end_field()->is_max_timestamp()) + if (table->versioned() && !table->vers_end_field()->is_max()) { continue; } @@ -1076,8 +1075,7 @@ int multi_delete::send_data(List &values) if (table->status & (STATUS_NULL_ROW | STATUS_DELETED)) continue; - if (table->versioned() && - !table->vers_end_field()->is_max_timestamp()) + if (table->versioned() && !table->vers_end_field()->is_max()) { continue; } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 39a8c61c231..4a588ea0cc2 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -222,7 +222,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, table_list->view_db.str, table_list->view_name.str); DBUG_RETURN(-1); } - if (values.elements != table->user_fields()) + if (values.elements != table->vers_user_fields()) { my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), 1L); DBUG_RETURN(-1); @@ -1029,7 +1029,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, } } - if (table->versioned()) + if (table->versioned_by_sql()) table->vers_update_fields(); if ((res= table_list->view_check_option(thd, @@ -1558,7 +1558,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, if (!table) table= table_list->table; - if (table->versioned() && duplic == DUP_REPLACE) + if (table->versioned_by_sql() && duplic == DUP_REPLACE) { // Additional memory may be required to create historical items. if (table_list->set_insert_values(thd->mem_root)) @@ -1622,22 +1622,16 @@ static int last_uniq_key(TABLE *table,uint keynr) sets Sys_end to now() and calls ha_write_row() . */ -int vers_insert_history_row(TABLE *table, ha_rows *inserted) +int vers_insert_history_row(TABLE *table) { - DBUG_ASSERT(table->versioned()); + DBUG_ASSERT(table->versioned_by_sql()); restore_record(table,record[1]); // Set Sys_end to now() if (table->vers_end_field()->set_time()) - { - return 1; - } - - const int error= table->file->ha_write_row(table->record[0]); - if (!error) - ++*inserted; + DBUG_ASSERT(0); - return error; + return table->file->ha_write_row(table->record[0]); } /* @@ -1846,9 +1840,20 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) if (error != HA_ERR_RECORD_IS_THE_SAME) { info->updated++; - if (table->versioned() && - (error=vers_insert_history_row(table, &info->copied))) - goto err; + if (table->versioned()) + { + if (table->versioned_by_sql()) + { + store_record(table, record[2]); + if ((error= vers_insert_history_row(table))) + { + restore_record(table, record[2]); + goto err; + } + restore_record(table, record[2]); + } + info->copied++; + } } else error= 0; @@ -1907,7 +1912,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) if (last_uniq_key(table,key_nr) && !table->file->referenced_by_foreign_key() && (!table->triggers || !table->triggers->has_delete_triggers()) && - !table->versioned()) + !table->versioned_by_sql()) { if ((error=table->file->ha_update_row(table->record[1], table->record[0])) && @@ -1931,7 +1936,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) TRG_ACTION_BEFORE, TRUE)) goto before_trg_err; - if (!table->versioned()) + if (!table->versioned_by_sql()) error= table->file->ha_delete_row(table->record[1]); else { @@ -1949,7 +1954,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) } if (error) goto err; - if (!table->versioned()) + if (!table->versioned_by_sql()) info->deleted++; else info->updated++; @@ -2040,7 +2045,9 @@ int check_that_all_fields_are_given_values(THD *thd, TABLE *entry, TABLE_LIST *t for (Field **field=entry->field ; *field ; field++) { if (!bitmap_is_set(write_set, (*field)->field_index) && - has_no_default_value(thd, *field, table_list)) + has_no_default_value(thd, *field, table_list) && + !((*field)->flags & (GENERATED_ROW_START_FLAG | GENERATED_ROW_END_FLAG)) && + ((*field)->real_type() != MYSQL_TYPE_ENUM)) err=1; } return thd->abort_on_warning ? err : 0; @@ -3795,7 +3802,7 @@ int select_insert::send_data(List &values) DBUG_RETURN(0); thd->count_cuted_fields= CHECK_FIELD_WARN; // Calculate cuted fields - if (table->versioned()) + if (table->versioned_by_sql()) table->vers_update_fields(); store_values(values); if (table->default_field && table->update_default_fields(0, info.ignore)) diff --git a/sql/sql_insert.h b/sql/sql_insert.h index a8794e7414b..6efd680d188 100644 --- a/sql/sql_insert.h +++ b/sql/sql_insert.h @@ -37,7 +37,7 @@ void upgrade_lock_type_for_insert(THD *thd, thr_lock_type *lock_type, bool is_multi_insert); int check_that_all_fields_are_given_values(THD *thd, TABLE *entry, TABLE_LIST *table_list); -int vers_insert_history_row(TABLE *table, ha_rows *inserted); +int vers_insert_history_row(TABLE *table); int write_record(THD *thd, TABLE *table, COPY_INFO *info); void kill_delayed_threads(void); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 17e36390146..94f8d78fa74 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -676,7 +676,7 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **conds, SELECT_LEX *se for (table= tables; table; table= table->next_local) { - if (table->table && table->table->versioned()) + if (table->table && table->table->versioned_by_sql()) versioned_tables++; else if (table->system_versioning.type != FOR_SYSTEM_TIME_UNSPECIFIED) { @@ -690,7 +690,7 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **conds, SELECT_LEX *se for (table= tables; table; table= table->next_local) { - if (table->table && table->table->versioned()) + if (table->table && table->table->versioned_by_sql()) { Field *fstart= table->table->vers_start_field(); Field *fend= table->table->vers_end_field(); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 084e98b143f..2bcf0199429 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2224,7 +2224,7 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, hton->index_options); } - if (table->versioned()) + if (table->versioned_by_sql()) { const Field *fs = table->vers_start_field(); const Field *fe = table->vers_end_field(); @@ -2273,7 +2273,7 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, add_table_options(thd, table, create_info_arg, table_list->schema_table != 0, 0, packet); - if (table->versioned()) + if (table->versioned_by_sql()) { packet->append(STRING_WITH_LEN(" WITH SYSTEM VERSIONING")); } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index da01bd26873..acbbf559c63 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -744,7 +744,7 @@ int mysql_update(THD *thd, while (!(error=info.read_record(&info)) && !thd->killed) { - if (table->versioned() && !table->vers_end_field()->is_max_timestamp()) + if (table->versioned() && !table->vers_end_field()->is_max()) { continue; } @@ -763,7 +763,7 @@ int mysql_update(THD *thd, TRG_EVENT_UPDATE)) break; /* purecov: inspected */ - if (table->versioned()) + if (table->versioned_by_sql()) table->vers_update_fields(); found++; @@ -837,11 +837,17 @@ int mysql_update(THD *thd, if (table->versioned()) { - store_record(table, record[2]); - if ((error = vers_insert_history_row(table, &updated_sys_ver))) - break; - - restore_record(table, record[2]); + if (table->versioned_by_sql()) + { + store_record(table, record[2]); + if ((error = vers_insert_history_row(table))) + { + restore_record(table, record[2]); + break; + } + restore_record(table, record[2]); + } + updated_sys_ver++; } } else if (!ignore || @@ -1036,7 +1042,7 @@ int mysql_update(THD *thd, if (error < 0 && !thd->lex->analyze_stmt) { char buff[MYSQL_ERRMSG_SIZE]; - if (!table->versioned()) + if (!table->versioned_by_sql()) my_snprintf(buff, sizeof(buff), ER_THD(thd, ER_UPDATE_INFO), (ulong) found, (ulong) updated, (ulong) thd->get_stmt_da()->current_statement_warn_count()); @@ -2134,7 +2140,7 @@ int multi_update::send_data(List ¬_used_values) if (table->status & (STATUS_NULL_ROW | STATUS_UPDATED)) continue; - if (table->versioned() && !table->vers_end_field()->is_max_timestamp()) + if (table->versioned() && !table->vers_end_field()->is_max()) { continue; } @@ -2170,7 +2176,7 @@ int multi_update::send_data(List ¬_used_values) if (table->default_field && table->update_default_fields(1, ignore)) DBUG_RETURN(1); - if (table->versioned()) + if (table->versioned_by_sql()) table->vers_update_fields(); if ((error= cur_table->view_check_option(thd, ignore)) != @@ -2222,20 +2228,18 @@ int multi_update::send_data(List ¬_used_values) } else if (table->versioned()) { - restore_record(table,record[1]); - - // Set end time to now() - if (table->vers_end_field()->set_time()) - { - error= 1; - break; - } - - if ( (error= vers_insert_history_row(table, &updated_sys_ver)) ) + if (table->versioned_by_sql()) { - error= 1; - break; + store_record(table, record[2]); + if (vers_insert_history_row(table)) + { + restore_record(table, record[2]); + error= 1; + break; + } + restore_record(table, record[2]); } + updated_sys_ver++; } /* non-transactional or transactional table got modified */ /* either multi_update class' flag is raised in its branch */ @@ -2507,7 +2511,7 @@ int multi_update::do_updates() goto err2; } } - if (table->versioned()) + if (table->versioned_by_sql()) table->vers_update_fields(); if ((local_error=table->file->ha_update_row(table->record[1], @@ -2527,19 +2531,18 @@ int multi_update::do_updates() if (table->versioned()) { - restore_record(table,record[1]); - - // Set end time to now() - if (table->vers_end_field()->set_time()) - { - goto err2; - } - - if ( (local_error= vers_insert_history_row(table, &updated_sys_ver)) ) + if (table->versioned_by_sql()) { - err_table = table; - goto err; + store_record(table, record[2]); + if ((local_error= vers_insert_history_row(table))) + { + restore_record(table, record[2]); + err_table = table; + goto err; + } + restore_record(table, record[2]); } + updated_sys_ver++; } } else diff --git a/sql/table.cc b/sql/table.cc index c9729d17d9c..80a7046be1a 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2477,35 +2477,6 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, } } - /* Set system versioning information. */ - if (system_period == NULL) - { - share->disable_system_versioning(); - } - else - { - DBUG_PRINT("info", ("Setting system versioning informations")); - uint16 row_start = uint2korr(system_period); - uint16 row_end = uint2korr(system_period + sizeof(uint16)); - if (row_start >= share->fields || row_end >= share->fields) - goto err; - DBUG_PRINT("info", ("Columns with system versioning: [%d, %d]", row_start, row_end)); - share->enable_system_versioning(row_start, row_end); - vers_start_field()->set_generated_row_start(); - vers_end_field()->set_generated_row_end(); - - if (vers_start_field()->type() != MYSQL_TYPE_TIMESTAMP) - { - my_error(ER_SYS_START_FIELD_MUST_BE_TIMESTAMP, MYF(0), share->table_name); - goto err; - } - if (vers_end_field()->type() != MYSQL_TYPE_TIMESTAMP) - { - my_error(ER_SYS_END_FIELD_MUST_BE_TIMESTAMP, MYF(0), share->table_name); - goto err; - } - } - /* the correct null_bytes can now be set, since bitfields have been taken into account @@ -2547,19 +2518,70 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, bitmap_clear_all(share->check_set); } - delete handler_file; #ifndef DBUG_OFF if (use_hash) (void) my_hash_check(&share->name_hash); #endif share->db_plugin= se_plugin; + + /* Set system versioning information. */ + if (system_period == NULL) + { + share->disable_system_versioning(); + } + else + { + DBUG_PRINT("info", ("Setting system versioning informations")); + uint16 row_start = uint2korr(system_period); + uint16 row_end = uint2korr(system_period + sizeof(uint16)); + if (row_start >= share->fields || row_end >= share->fields) + goto err; + DBUG_PRINT("info", ("Columns with system versioning: [%d, %d]", row_start, row_end)); + share->enable_system_versioning(row_start, row_end); + vers_start_field()->set_generated_row_start(); + vers_end_field()->set_generated_row_end(); + + DBUG_ASSERT(db_type()); + if (db_type()->versioned()) + { + if (vers_start_field()->type() != MYSQL_TYPE_LONGLONG + || !(vers_start_field()->flags & UNSIGNED_FLAG)) + { + my_error(ER_SYS_START_FIELD_MUST_BE_BIGINT, MYF(0), share->table_name); + goto err; + } + if (vers_end_field()->type() != MYSQL_TYPE_LONGLONG + || !(vers_end_field()->flags & UNSIGNED_FLAG)) + { + my_error(ER_SYS_END_FIELD_MUST_BE_BIGINT, MYF(0), share->table_name); + goto err; + } + } + else + { + if (vers_start_field()->type() != MYSQL_TYPE_TIMESTAMP) + { + my_error(ER_SYS_START_FIELD_MUST_BE_TIMESTAMP, MYF(0), share->table_name); + goto err; + } + if (vers_end_field()->type() != MYSQL_TYPE_TIMESTAMP) + { + my_error(ER_SYS_END_FIELD_MUST_BE_TIMESTAMP, MYF(0), share->table_name); + goto err; + } + } // if (db_type()->versioned()) + } // if (system_period == NULL) + + delete handler_file; + share->error= OPEN_FRM_OK; thd->status_var.opened_shares++; thd->mem_root= old_root; DBUG_RETURN(0); - err: +err: + share->db_plugin= NULL; share->error= OPEN_FRM_CORRUPTED; share->open_errno= my_errno; delete handler_file; @@ -7568,14 +7590,14 @@ void TABLE::vers_update_fields() { DBUG_ENTER("vers_update_fields"); + bitmap_set_bit(write_set, vers_start_field()->field_index); + bitmap_set_bit(write_set, vers_end_field()->field_index); + if (vers_start_field()->set_time()) DBUG_ASSERT(0); - if (vers_end_field()->set_max_timestamp()) + if (vers_end_field()->set_max()) DBUG_ASSERT(0); - bitmap_set_bit(write_set, vers_start_field()->field_index); - bitmap_set_bit(write_set, vers_end_field()->field_index); - DBUG_VOID_RETURN; } diff --git a/sql/table.h b/sql/table.h index 7416f27756d..ad62c06838b 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1484,7 +1484,7 @@ public: bool export_structure(THD *thd, class Row_definition_list *defs); /** - System versioning support. + System Versioning support */ bool versioned() const @@ -1492,15 +1492,22 @@ public: return s->versioned; } + /* Versioned by SQL layer */ + bool versioned_by_sql() const + { + DBUG_ASSERT(s->db_type()); + return s->versioned && !s->db_type()->versioned(); + } + Field *vers_start_field() const { - DBUG_ASSERT(versioned()); + DBUG_ASSERT(s->versioned); return field[s->row_start_field]; } Field *vers_end_field() const { - DBUG_ASSERT(versioned()); + DBUG_ASSERT(s->versioned); return field[s->row_end_field]; } @@ -1509,9 +1516,9 @@ public: /** Number of additional fields used in versioned tables */ #define VERSIONING_FIELDS 2 - uint user_fields() const + uint vers_user_fields() const { - return versioned() ? + return s->versioned ? s->fields - VERSIONING_FIELDS : s->fields; } diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc index 13db213259c..304a4ae89eb 100644 --- a/storage/innobase/dict/dict0mem.cc +++ b/storage/innobase/dict/dict0mem.cc @@ -304,6 +304,16 @@ dict_mem_table_add_col( col = dict_table_get_nth_col(table, i); dict_mem_fill_column_struct(col, i, mtype, prtype, len); + + if (prtype & DATA_VERS_ROW_START) { + ut_ad(table->flags2 & DICT_TF2_VERSIONED + && !(prtype & DATA_VERS_ROW_END)); + table->vers_row_start = i; + } else if (prtype & DATA_VERS_ROW_END) { + ut_ad(table->flags2 & DICT_TF2_VERSIONED + && !(prtype & DATA_VERS_ROW_START)); + table->vers_row_end = i; + } } /** Adds a virtual column definition to a table. diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index acba2461f55..2899654e49d 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -3848,7 +3848,7 @@ innobase_init( innobase_hton->flush_logs = innobase_flush_logs; innobase_hton->show_status = innobase_show_status; innobase_hton->flags = - HTON_SUPPORTS_EXTENDED_KEYS | HTON_SUPPORTS_FOREIGN_KEYS; + HTON_SUPPORTS_EXTENDED_KEYS | HTON_SUPPORTS_FOREIGN_KEYS | HTON_SUPPORTS_SYS_VERSIONING; innobase_hton->release_temporary_latches = innobase_release_temporary_latches; @@ -9478,6 +9478,11 @@ ha_innobase::update_row( error = row_update_for_mysql((byte*) old_row, m_prebuilt); + if (error == DB_SUCCESS && DICT_TF2_FLAG_IS_SET(m_prebuilt->table, DICT_TF2_VERSIONED)) { + if (trx->id != static_cast(table->vers_start_field()->val_int())) + error = row_insert_for_mysql((byte*) old_row, m_prebuilt, true); + } + if (error == DB_SUCCESS && autoinc) { /* A value for an AUTO_INCREMENT column was specified in the UPDATE statement. */ @@ -11677,8 +11682,17 @@ create_table_info_t::create_table_def() for (i = 0; i < n_cols; i++) { ulint is_virtual; bool is_stored = false; - Field* field = m_form->field[i]; + ulint vers_row_start = 0; + ulint vers_row_end = 0; + + if (m_flags2 & DICT_TF2_VERSIONED) { + if (i == m_form->s->row_start_field) { + vers_row_start = DATA_VERS_ROW_START; + } else if (i == m_form->s->row_end_field) { + vers_row_end = DATA_VERS_ROW_END; + } + } col_type = get_innobase_type_from_mysql_type( &unsigned_type, field); @@ -11773,7 +11787,8 @@ err_col: dtype_form_prtype( (ulint) field->type() | nulls_allowed | unsigned_type - | binary_type | long_true_varchar, + | binary_type | long_true_varchar + | vers_row_start | vers_row_end, charset_no), col_len); } else { @@ -11783,6 +11798,7 @@ err_col: (ulint) field->type() | nulls_allowed | unsigned_type | binary_type | long_true_varchar + | vers_row_start | vers_row_end | is_virtual, charset_no), col_len, i, 0); diff --git a/storage/innobase/include/data0type.h b/storage/innobase/include/data0type.h index 3fa8320b5aa..353fe63cf02 100644 --- a/storage/innobase/include/data0type.h +++ b/storage/innobase/include/data0type.h @@ -198,6 +198,8 @@ be less than 256 */ /** Check whether locking is disabled (never). */ #define dict_table_is_locking_disabled(table) false +#define DATA_VERS_ROW_START 0x4000 /* System Versioning row start */ +#define DATA_VERS_ROW_END 0x8000 /* System Versioning row end */ /*-------------------------------------------*/ /* This many bytes we need to store the type information affecting the diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index f1193d314f8..ae5bb0d0e4d 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -329,8 +329,9 @@ use its own tablespace instead of the system tablespace. */ index tables) of a FTS table are in HEX format. */ #define DICT_TF2_FTS_AUX_HEX_NAME 64U - +/** System Versioning bit. */ #define DICT_TF2_VERSIONED 512 + /* @} */ #define DICT_TF2_FLAG_SET(table, flag) \ @@ -1487,7 +1488,10 @@ struct dict_table_t { /** Virtual column names */ const char* v_col_names; - + unsigned vers_row_start:10; + /*!< System Versioning: row start col index */ + unsigned vers_row_end:10; + /*!< System Versioning: row end col index */ bool is_system_db; /*!< True if the table belongs to a system database (mysql, information_schema or diff --git a/storage/innobase/include/row0ins.h b/storage/innobase/include/row0ins.h index dc6ad2d34ad..561f6f2d8fe 100644 --- a/storage/innobase/include/row0ins.h +++ b/storage/innobase/include/row0ins.h @@ -235,4 +235,8 @@ struct ins_node_t{ #define INS_NODE_INSERT_ENTRIES 3 /* index entries should be built and inserted */ +#ifndef UNIV_NONINL +#include "row0ins.ic" +#endif + #endif diff --git a/storage/innobase/include/row0ins.ic b/storage/innobase/include/row0ins.ic new file mode 100644 index 00000000000..3192affc327 --- /dev/null +++ b/storage/innobase/include/row0ins.ic @@ -0,0 +1,44 @@ +/***************************************************************************** + +Copyright (c) 1996, 2009, Oracle and/or its affiliates. All Rights Reserved. + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA + +*****************************************************************************/ + +/**************************************************//** +@file include/row0ins.ic +Insert into a table + +Created 4/20/1996 Heikki Tuuri +*******************************************************/ + + +UNIV_INLINE +void set_row_field_8( + dtuple_t* row, + int field_num, + ib_uint64_t data, + mem_heap_t* heap) +{ + static const ulint fsize = sizeof(data); + dfield_t* dfield = dtuple_get_nth_field(row, field_num); + ut_ad(dfield->type.len == fsize); + if (dfield->len == UNIV_SQL_NULL) { + byte* buf = static_cast(mem_heap_alloc(heap, fsize)); + mach_write_to_8(buf, data); + dfield_set_data(dfield, buf, fsize); + } else { + mach_write_to_8(dfield->data, data); + } +} diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index 59bd786d25c..6fa0a926e3f 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -241,7 +241,10 @@ row_lock_table_for_mysql( dberr_t row_insert_for_mysql( const byte* mysql_rec, - row_prebuilt_t* prebuilt) + row_prebuilt_t* prebuilt, + bool historical + /*!< in: System Versioning, row is */ + = false) /* historical */ MY_ATTRIBUTE((warn_unused_result)); /*********************************************************************//** diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index d071036e947..4ee2be787ec 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -27,6 +27,11 @@ Created 4/20/1996 Heikki Tuuri #include "ha_prototypes.h" #include "row0ins.h" + +#ifdef UNIV_NONINL +#include "row0ins.ic" +#endif + #include "dict0dict.h" #include "dict0boot.h" #include "trx0rec.h" @@ -3816,17 +3821,6 @@ error_handling: return(thr); } -inline -void set_row_field_8(dtuple_t* row, int field_num, ib_uint64_t data, mem_heap_t* heap) -{ - static const ulint fsize = 8; - dfield_t* dfield = dtuple_get_nth_field(row, field_num); - ut_ad(dfield->type.len == fsize); - byte* buf = static_cast(mem_heap_alloc(heap, fsize)); - mach_write_to_8(buf, data); - dfield_set_data(dfield, buf, fsize); -} - /***********************************************************//** Inserts a row to SYS_VTQ, low level. @return DB_SUCCESS if operation successfully completed, else error diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index c08b608e006..2bf26f242ca 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -1406,7 +1406,8 @@ run_again: dberr_t row_insert_for_mysql( const byte* mysql_rec, - row_prebuilt_t* prebuilt) + row_prebuilt_t* prebuilt, + bool historical) { trx_savept_t savept; que_thr_t* thr; @@ -1486,6 +1487,16 @@ row_insert_for_mysql( row_mysql_convert_row_to_innobase(node->row, prebuilt, mysql_rec, &blob_heap); + if (DICT_TF2_FLAG_IS_SET(node->table, DICT_TF2_VERSIONED)) { + ut_ad(table->vers_row_start != table->vers_row_end); + if (historical) { + set_row_field_8(node->row, table->vers_row_end, trx->id, node->entry_sys_heap); + } else { + set_row_field_8(node->row, table->vers_row_start, trx->id, node->entry_sys_heap); + set_row_field_8(node->row, table->vers_row_end, IB_UINT64_MAX, node->entry_sys_heap); + } + } + savept = trx_savept_take(trx); thr = que_fork_get_first_thr(prebuilt->ins_graph); @@ -1537,7 +1548,7 @@ error_exit: node->duplicate = NULL; - if (!trx->vtq_notify_on_commit && DICT_TF2_FLAG_IS_SET(node->table, DICT_TF2_VERSIONED)) { + if (DICT_TF2_FLAG_IS_SET(node->table, DICT_TF2_VERSIONED)) { trx->vtq_notify_on_commit = true; } @@ -1935,6 +1946,38 @@ row_update_for_mysql_using_upd_graph( prebuilt->clust_pcur); } + if (DICT_TF2_FLAG_IS_SET(node->table, DICT_TF2_VERSIONED)) + { + /* System Versioning: update sys_trx_start to current trx_id */ + upd_t* uvect = node->update; + upd_field_t* ufield; + dict_col_t* col; + if (node->is_delete) { + ufield = &uvect->fields[0]; + uvect->n_fields = 0; + node->is_delete = false; + col = &table->cols[table->vers_row_end]; + } else { + ut_ad(uvect->n_fields < node->table->n_cols); + ufield = &uvect->fields[uvect->n_fields]; + col = &table->cols[table->vers_row_start]; + } + UNIV_MEM_INVALID(ufield, sizeof *ufield); + ufield->field_no = dict_col_get_clust_pos(col, clust_index); + ufield->orig_len = 0; + ufield->exp = NULL; + + static const ulint fsize = sizeof(trx_id_t); + byte* buf = static_cast(mem_heap_alloc(node->heap, fsize)); + mach_write_to_8(buf, trx->id); + dfield_t* dfield = &ufield->new_val; + dfield_set_data(dfield, buf, fsize); + dict_col_copy_type(col, &dfield->type); + + uvect->n_fields++; + ut_ad(node->in_mysql_interface); // otherwise needs to recalculate node->cmpl_info + } + ut_a(node->pcur->rel_pos == BTR_PCUR_ON); /* MySQL seems to call rnd_pos before updating each row it @@ -2132,7 +2175,7 @@ run_again: } } - if (!trx->vtq_notify_on_commit && DICT_TF2_FLAG_IS_SET(node->table, DICT_TF2_VERSIONED)) { + if (DICT_TF2_FLAG_IS_SET(node->table, DICT_TF2_VERSIONED)) { trx->vtq_notify_on_commit = true; } diff --git a/storage/xtradb/include/row0ins.ic b/storage/xtradb/include/row0ins.ic index 9c191d869a2..3192affc327 100644 --- a/storage/xtradb/include/row0ins.ic +++ b/storage/xtradb/include/row0ins.ic @@ -24,3 +24,21 @@ Created 4/20/1996 Heikki Tuuri *******************************************************/ +UNIV_INLINE +void set_row_field_8( + dtuple_t* row, + int field_num, + ib_uint64_t data, + mem_heap_t* heap) +{ + static const ulint fsize = sizeof(data); + dfield_t* dfield = dtuple_get_nth_field(row, field_num); + ut_ad(dfield->type.len == fsize); + if (dfield->len == UNIV_SQL_NULL) { + byte* buf = static_cast(mem_heap_alloc(heap, fsize)); + mach_write_to_8(buf, data); + dfield_set_data(dfield, buf, fsize); + } else { + mach_write_to_8(dfield->data, data); + } +} -- cgit v1.2.1 From a72259353a1520dab2b5fdda84224e7ff21c0993 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 3 Oct 2016 02:48:08 +0000 Subject: Cleanup: garbage hunk --- sql/sql_select.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 94f8d78fa74..db50d471183 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -588,7 +588,7 @@ void remove_redundant_subquery_clauses(st_select_lex *subq_select_lex) subq_select_lex->group_list.empty(); DBUG_PRINT("info", ("GROUP BY removed")); } - + /* TODO: This would prevent processing quries with ORDER BY ... LIMIT therefore we disable this optimization for now. -- cgit v1.2.1 From 78c5d1d79c1ea155189b1ed6a59aab8d635d1535 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 3 Oct 2016 07:03:04 +0000 Subject: SQL: respect signed in set_max(), is_max() --- sql/field.cc | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index 604965be254..78ff1fded5e 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4359,16 +4359,22 @@ void Field_longlong::sql_type(String &res) const bool Field_longlong::set_max() { ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; - int8store(ptr, ULONGLONG_MAX); + int8store(ptr, unsigned_flag ? ULONGLONG_MAX : LONGLONG_MAX); return FALSE; } bool Field_longlong::is_max() { ASSERT_COLUMN_MARKED_FOR_READ; - ulonglong j; - j = sint8korr(ptr); - return j == ULONGLONG_MAX; + if (unsigned_flag) + { + ulonglong j; + j= uint8korr(ptr); + return j == ULONGLONG_MAX; + } + longlong j; + j= sint8korr(ptr); + return j == LONGLONG_MAX; } /* -- cgit v1.2.1 From a7df73063642ab5a788b36f175a748a17f63670b Mon Sep 17 00:00:00 2001 From: Kosov Eugene Date: Tue, 4 Oct 2016 15:56:06 +0300 Subject: SQL: fix timestamp type for generated fields --- sql/handler.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/handler.cc b/sql/handler.cc index b27dc224c48..0c2dea8b00e 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6568,7 +6568,7 @@ static bool create_sys_trx_field_if_missing(THD *thd, const char *field_name, f->field_name= field_name; f->charset= system_charset_info; - f->sql_type= MYSQL_TYPE_TIMESTAMP; + f->sql_type= MYSQL_TYPE_TIMESTAMP2; f->length= 6; f->decimals= 0; -- cgit v1.2.1 From c6b029d7cdd73b099503a79c55660dfc01ac40d4 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Sun, 9 Oct 2016 15:34:42 +0000 Subject: Tests: dependency on xtradb for some tests These features are defined only in XtraDB: chaged_page_bitmaps, innodb_changed_pages --- mysql-test/suite/innodb/t/innodb_skip_innodb_is_tables.test | 1 + mysql-test/t/mysqld--help.test | 1 + 2 files changed, 2 insertions(+) diff --git a/mysql-test/suite/innodb/t/innodb_skip_innodb_is_tables.test b/mysql-test/suite/innodb/t/innodb_skip_innodb_is_tables.test index 01ced047302..4954191d74a 100644 --- a/mysql-test/suite/innodb/t/innodb_skip_innodb_is_tables.test +++ b/mysql-test/suite/innodb/t/innodb_skip_innodb_is_tables.test @@ -1,4 +1,5 @@ --source include/not_embedded.inc +--source include/have_xtradb.inc select * from information_schema.innodb_trx; select * from information_schema.innodb_locks; diff --git a/mysql-test/t/mysqld--help.test b/mysql-test/t/mysqld--help.test index e6499957cd2..a5f66e72900 100644 --- a/mysql-test/t/mysqld--help.test +++ b/mysql-test/t/mysqld--help.test @@ -4,6 +4,7 @@ --source include/not_embedded.inc --source include/have_perfschema.inc --source include/platform.inc +--source include/have_xtradb.inc # # force lower-case-table-names=1 (linux/macosx have different defaults) -- cgit v1.2.1 From f13bf7178d9d924634762d0bb52d658e5d341451 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 11 Oct 2016 06:14:45 +0000 Subject: Parser: expressions instead string literals in TIMESTAMP clauses --- sql/sql_yacc.yy | 32 ++++++++------------------------ 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 7e8ef6ec8fb..f681ed25596 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -8669,13 +8669,9 @@ opt_for_system_time_clause: } | FOR_SYSTEM_TIME_SYM AS OF_SYM - TIMESTAMP TEXT_STRING + TIMESTAMP simple_expr { - Item *item= create_temporal_literal(thd, $5.str, $5.length, YYCSCL, - MYSQL_TYPE_DATETIME, true); - if (item == NULL) - MYSQL_YYABORT; - $$.init(FOR_SYSTEM_TIME_AS_OF, item); + $$.init(FOR_SYSTEM_TIME_AS_OF, $5); } | FOR_SYSTEM_TIME_SYM AS OF_SYM @@ -8688,31 +8684,19 @@ opt_for_system_time_clause: } | FOR_SYSTEM_TIME_SYM FROM - TIMESTAMP TEXT_STRING + TIMESTAMP simple_expr TO_SYM - TIMESTAMP TEXT_STRING + TIMESTAMP simple_expr { - Item *item1= create_temporal_literal(thd, $4.str, $4.length, YYCSCL, - MYSQL_TYPE_DATETIME, true); - Item *item2= create_temporal_literal(thd, $7.str, $7.length, YYCSCL, - MYSQL_TYPE_DATETIME, true); - if (item1 == NULL || item2 == NULL) - MYSQL_YYABORT; - $$.init(FOR_SYSTEM_TIME_FROM_TO, item1, item2); + $$.init(FOR_SYSTEM_TIME_FROM_TO, $4, $7); } | FOR_SYSTEM_TIME_SYM BETWEEN_SYM - TIMESTAMP TEXT_STRING + TIMESTAMP simple_expr AND_SYM - TIMESTAMP TEXT_STRING + TIMESTAMP simple_expr { - Item *item1= create_temporal_literal(thd, $4.str, $4.length, YYCSCL, - MYSQL_TYPE_DATETIME, true); - Item *item2= create_temporal_literal(thd, $7.str, $7.length, YYCSCL, - MYSQL_TYPE_DATETIME, true); - if (item1 == NULL || item2 == NULL) - MYSQL_YYABORT; - $$.init(FOR_SYSTEM_TIME_BETWEEN, item1, item2); + $$.init(FOR_SYSTEM_TIME_BETWEEN, $4, $7); } ; -- cgit v1.2.1 From 53a892fcfd5aa1551f0284767186632b9560d838 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Fri, 30 Sep 2016 13:15:08 +0000 Subject: IB: 0.2 part IV * BEGIN_TS(), COMMIT_TS() SQL functions; * VTQ instead of packed stores secs + usecs like my_timestamp_to_binary() does; * versioned SELECT to IB is translated with COMMIT_TS(); * SQL fixes: - FOR_SYSTEM_TIME_UNSPECIFIED condition compares to TIMESTAMP_MAX_VALUE; - segfault fix #36: multiple execute of prepared stmt; - different tables to same stored procedure fix (#39) * Fixes of previous parts: ON DUPLICATE KEY, other misc fixes. --- sql/field.cc | 2 +- sql/handler.h | 8 ++- sql/item.cc | 1 + sql/item.h | 2 +- sql/item_create.cc | 88 ++++++++++++++++++++++++++ sql/item_timefunc.cc | 68 ++++++++++++++++++++ sql/item_timefunc.h | 22 +++++++ sql/sp_head.cc | 1 + sql/sql_base.cc | 4 +- sql/sql_class.cc | 6 ++ sql/sql_class.h | 11 +++- sql/sql_lex.cc | 1 + sql/sql_lex.h | 1 + sql/sql_plugin.cc | 14 +++++ sql/sql_plugin.h | 2 + sql/sql_select.cc | 111 +++++++++++++++++++++++++++------ sql/sql_show.cc | 4 +- sql/sql_time.cc | 12 ---- sql/sql_time.h | 9 --- sql/tztime.h | 1 + sql/vtq.h | 25 ++++++++ storage/innobase/dict/dict0crea.cc | 2 +- storage/innobase/dict/dict0load.cc | 10 +-- storage/innobase/handler/ha_innodb.cc | 113 ++++++++++++++++++++++++++++++++++ storage/innobase/handler/i_s.cc | 31 +++++----- storage/innobase/include/dict0load.h | 4 +- storage/innobase/include/row0ins.ic | 23 +++++-- storage/innobase/include/trx0trx.h | 13 +++- storage/innobase/row/row0ins.cc | 48 ++++----------- storage/innobase/row/row0mysql.cc | 31 ++++++++-- storage/innobase/trx/trx0trx.cc | 40 +++++++++++- 31 files changed, 585 insertions(+), 123 deletions(-) create mode 100755 sql/vtq.h diff --git a/sql/field.cc b/sql/field.cc index 78ff1fded5e..c22ae9e2df3 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5448,7 +5448,7 @@ bool Field_timestampf::set_max() DBUG_ENTER("Field_timestampf::set_max"); ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; - mi_int4store(ptr, 0x7fffffff); + mi_int4store(ptr, TIMESTAMP_MAX_VALUE); memset(ptr + 4, 0x0, value_length() - 4); DBUG_RETURN(FALSE); diff --git a/sql/handler.h b/sql/handler.h index b50e1b82ed2..8b7b6f516a1 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -35,6 +35,7 @@ #include "structs.h" /* SHOW_COMP_OPTION */ #include "sql_array.h" /* Dynamic_array<> */ #include "mdl.h" +#include "vtq.h" #include "sql_analyze_stmt.h" // for Exec_time_tracker @@ -1387,9 +1388,10 @@ struct handlerton TABLE_SHARE *share, HA_CREATE_INFO *info); /* - Engine supports System Versioning + System Versioning */ - bool versioned(); + bool versioned() const; + bool (*vers_get_vtq_ts)(THD* thd, MYSQL_TIME *out, ulonglong trx_id, vtq_field_t field); }; @@ -4493,7 +4495,7 @@ int del_global_index_stat(THD *thd, TABLE* table, KEY* key_info); int del_global_table_stat(THD *thd, LEX_STRING *db, LEX_STRING *table); inline -bool handlerton::versioned() +bool handlerton::versioned() const { return flags & HTON_SUPPORTS_SYS_VERSIONING; } diff --git a/sql/item.cc b/sql/item.cc index fe51b2966ad..a76152c14e2 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -5621,6 +5621,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) expression to 'reference', i.e. it substitute that expression instead of this Item_field */ + DBUG_ASSERT(context); if ((from_field= find_field_in_tables(thd, this, context->first_name_resolution_table, context->last_name_resolution_table, diff --git a/sql/item.h b/sql/item.h index e5a3215d13e..35b76a3278e 100644 --- a/sql/item.h +++ b/sql/item.h @@ -3913,7 +3913,7 @@ public: class Item_datetime_literal: public Item_temporal_literal { public: - Item_datetime_literal(THD *thd, MYSQL_TIME *ltime, uint dec_arg): + Item_datetime_literal(THD *thd, MYSQL_TIME *ltime, uint dec_arg= 0): Item_temporal_literal(thd, ltime, dec_arg) { max_length= MAX_DATETIME_WIDTH + (decimals ? decimals + 1 : 0); diff --git a/sql/item_create.cc b/sql/item_create.cc index d488b5f26c0..48055ccb11e 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -6678,6 +6678,92 @@ Create_func_year_week::create_native(THD *thd, LEX_STRING name, } +/* System Versioning: BEGIN_TS(), COMMIT_TS() */ + +class Create_func_begin_ts : public Create_native_func +{ +public: + virtual Item *create_native(THD *thd, LEX_STRING name, List *item_list); + + static Create_func_begin_ts s_singleton; + +protected: + Create_func_begin_ts() {} + virtual ~Create_func_begin_ts() {} +}; + +Create_func_begin_ts Create_func_begin_ts::s_singleton; + +Item* +Create_func_begin_ts::create_native(THD *thd, LEX_STRING name, + List *item_list) +{ + Item *func= NULL; + int arg_count= 0; + + if (item_list != NULL) + arg_count= item_list->elements; + + switch (arg_count) { + case 1: + { + Item *param_1= item_list->pop(); + func= new (thd->mem_root) Item_func_vtq_ts(thd, param_1, VTQ_BEGIN_TS); + break; + } + default: + { + my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str); + break; + } + } + + return func; +} + +class Create_func_commit_ts : public Create_native_func +{ +public: + virtual Item *create_native(THD *thd, LEX_STRING name, List *item_list); + + static Create_func_commit_ts s_singleton; + +protected: + Create_func_commit_ts() {} + virtual ~Create_func_commit_ts() {} +}; + +Create_func_commit_ts Create_func_commit_ts::s_singleton; + +Item* +Create_func_commit_ts::create_native(THD *thd, LEX_STRING name, + List *item_list) +{ + Item *func= NULL; + int arg_count= 0; + + if (item_list != NULL) + arg_count= item_list->elements; + + switch (arg_count) { + case 1: + { + Item *param_1= item_list->pop(); + func= new (thd->mem_root) Item_func_vtq_ts(thd, param_1, VTQ_COMMIT_TS); + break; + } + default: + { + my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str); + break; + } + } + + return func; +} + + + struct Native_func_registry { LEX_STRING name; @@ -6718,6 +6804,7 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("ASWKT") }, GEOM_BUILDER(Create_func_as_wkt)}, { { C_STRING_WITH_LEN("ATAN") }, BUILDER(Create_func_atan)}, { { C_STRING_WITH_LEN("ATAN2") }, BUILDER(Create_func_atan)}, + { { C_STRING_WITH_LEN("BEGIN_TS") }, BUILDER(Create_func_begin_ts)}, { { C_STRING_WITH_LEN("BENCHMARK") }, BUILDER(Create_func_benchmark)}, { { C_STRING_WITH_LEN("BIN") }, BUILDER(Create_func_bin)}, { { C_STRING_WITH_LEN("BINLOG_GTID_POS") }, BUILDER(Create_func_binlog_gtid_pos)}, @@ -6735,6 +6822,7 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("COLUMN_EXISTS") }, BUILDER(Create_func_dyncol_exists)}, { { C_STRING_WITH_LEN("COLUMN_LIST") }, BUILDER(Create_func_dyncol_list)}, { { C_STRING_WITH_LEN("COLUMN_JSON") }, BUILDER(Create_func_dyncol_json)}, + { { C_STRING_WITH_LEN("COMMIT_TS") }, BUILDER(Create_func_commit_ts)}, { { C_STRING_WITH_LEN("COMPRESS") }, BUILDER(Create_func_compress)}, { { C_STRING_WITH_LEN("CONCAT") }, BUILDER(Create_func_concat)}, { { C_STRING_WITH_LEN("CONCAT_WS") }, BUILDER(Create_func_concat_ws)}, diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index a1a9ca5c8ae..3ceb87246ce 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -3273,3 +3273,71 @@ bool Item_func_last_day::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) ltime->time_type= MYSQL_TIMESTAMP_DATE; return (null_value= 0); } + +Item_func_vtq_ts::Item_func_vtq_ts( + THD *thd, + Item* a, + vtq_field_t _vtq_field, + handlerton* _hton) : + Item_datetimefunc(thd, a), + vtq_field(_vtq_field), + hton(_hton) +{ + decimals= 6; + null_value= true; + DBUG_ASSERT(arg_count == 1 && args[0]); +} + +Item_func_vtq_ts::Item_func_vtq_ts( + THD *thd, + Item* a, + vtq_field_t _vtq_field) : + Item_datetimefunc(thd, a), + vtq_field(_vtq_field), + hton(NULL) +{ + decimals= 6; + null_value= true; + DBUG_ASSERT(arg_count == 1 && args[0]); +} + +bool Item_func_vtq_ts::get_date(MYSQL_TIME *res, ulonglong fuzzy_date) +{ + THD *thd= current_thd; // can it differ from constructor's? + DBUG_ASSERT(thd); + ulonglong trx_id= args[0]->val_uint(); + if (trx_id == ULONGLONG_MAX) + { + null_value= false; + thd->variables.time_zone->gmt_sec_to_TIME(res, TIMESTAMP_MAX_VALUE); + return false; + } + + if (!hton) + { + if (args[0]->type() == Item::FIELD_ITEM) + { + Item_field *f= + static_cast(args[0]); + DBUG_ASSERT( + f->field && + f->field->table && + f->field->table->s && + f->field->table->s->db_plugin); + hton= plugin_hton(f->field->table->s->db_plugin); + DBUG_ASSERT(hton); + } + else if (innodb_plugin) + { + hton= plugin_hton(plugin_int_to_ref(innodb_plugin)); + DBUG_ASSERT(hton); + } + } + + if (!hton) + return true; + + null_value= !hton->vers_get_vtq_ts(thd, res, trx_id, vtq_field); + + return false; +} diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index f1a719fb775..a8281124b38 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -1286,4 +1286,26 @@ public: { return get_item_copy(thd, mem_root, this); } }; +#include "vtq.h" + +class Item_func_vtq_ts :public Item_datetimefunc +{ + vtq_field_t vtq_field; + handlerton *hton; +public: + Item_func_vtq_ts(THD *thd, Item* a, vtq_field_t _vtq_field, handlerton *hton); + Item_func_vtq_ts(THD *thd, Item* a, vtq_field_t _vtq_field); + const char *func_name() const + { + if (vtq_field == VTQ_BEGIN_TS) + { + return "begin_ts"; + } + return "commit_ts"; + } + bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy(thd, mem_root, this); } +}; + #endif /* ITEM_TIMEFUNC_INCLUDED */ diff --git a/sql/sp_head.cc b/sql/sp_head.cc index aeaca82649f..f470ca3f283 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2529,6 +2529,7 @@ sp_head::restore_thd_mem_root(THD *thd) Item *flist= free_list; // The old list set_query_arena(thd); // Get new free_list and mem_root state= STMT_INITIALIZED_FOR_SP; + is_stored_procedure= true; DBUG_PRINT("info", ("mem_root 0x%lx returned from thd mem root 0x%lx", (ulong) &mem_root, (ulong) &thd->mem_root)); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 89f1798d36d..1af45c12331 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7962,7 +7962,7 @@ fill_record(THD *thd, TABLE *table_arg, List &fields, List &values, ER_THD(thd, ER_WARNING_NON_DEFAULT_VALUE_FOR_VIRTUAL_COLUMN), rfield->field_name, table->s->table_name.str); } - if (table->versioned_by_sql() && rfield->is_generated() && + if (table->versioned() && rfield->is_generated() && !ignore_errors) { my_error(ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER, MYF(0)); @@ -8216,7 +8216,7 @@ fill_record(THD *thd, TABLE *table, Field **ptr, List &values, } } - if (table->versioned_by_sql() && field->is_generated() && + if (table->versioned() && field->is_generated() && !ignore_errors) { my_error(ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER, MYF(0)); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 0ed78b2dfa8..06a592b8d51 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -706,6 +706,11 @@ extern "C" void thd_kill_timeout(THD* thd) mysql_mutex_unlock(&thd->LOCK_thd_data); } +Time_zone * thd_get_timezone(THD * thd) +{ + DBUG_ASSERT(thd && thd->variables.time_zone); + return thd->variables.time_zone; +} THD::THD(my_thread_id id, bool is_wsrep_applier) :Statement(&main_lex, &main_mem_root, STMT_CONVENTIONAL_EXECUTION, @@ -3587,6 +3592,7 @@ void Query_arena::set_query_arena(Query_arena *set) mem_root= set->mem_root; free_list= set->free_list; state= set->state; + is_stored_procedure= set->is_stored_procedure; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 82d538b07fd..1b920b23a2d 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -940,6 +940,11 @@ public: enum_state state; +protected: + friend class sp_head; + bool is_stored_procedure; + +public: /* We build without RTTI, so dynamic_cast can't be used. */ enum Type { @@ -947,7 +952,8 @@ public: }; Query_arena(MEM_ROOT *mem_root_arg, enum enum_state state_arg) : - free_list(0), mem_root(mem_root_arg), state(state_arg) + free_list(0), mem_root(mem_root_arg), state(state_arg), + is_stored_procedure(state_arg == STMT_INITIALIZED_FOR_SP ? true : false) { INIT_ARENA_DBUG_INFO; } /* This constructor is used only when Query_arena is created as @@ -967,6 +973,8 @@ public: { return state == STMT_PREPARED || state == STMT_EXECUTED; } inline bool is_conventional() const { return state == STMT_CONVENTIONAL_EXECUTION; } + inline bool is_sp_execute() const + { return is_stored_procedure; } inline void* alloc(size_t size) { return alloc_root(mem_root,size); } inline void* calloc(size_t size) @@ -6021,5 +6029,4 @@ public: #endif /* MYSQL_SERVER */ - #endif /* SQL_CLASS_INCLUDED */ diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index c1281a2e022..a45fc044f55 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2200,6 +2200,7 @@ void st_select_lex::init_query() join= 0; having= prep_having= where= prep_where= 0; cond_pushed_into_where= cond_pushed_into_having= 0; + saved_conds= 0; olap= UNSPECIFIED_OLAP_TYPE; having_fix_field= 0; context.select_lex= this; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 9b625d3b7b3..d3665844a69 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -810,6 +810,7 @@ public: Item *prep_having;/* saved HAVING clause for prepared statement processing */ Item *cond_pushed_into_where; /* condition pushed into the select's WHERE */ Item *cond_pushed_into_having; /* condition pushed into the select's HAVING */ + Item *saved_conds; /* Saved values of the WHERE and HAVING clauses*/ Item::cond_result cond_value, having_value; /* point on lex in which it was created, used in view subquery detection */ diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index c307bc4f425..82fbb7c62cc 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -233,6 +233,8 @@ static int plugin_array_version=0; static bool initialized= 0; ulong dlopen_count; +st_plugin_int* innodb_plugin= NULL; + /* write-lock on LOCK_system_variables_hash is required before modifying @@ -1422,6 +1424,18 @@ static int plugin_initialize(MEM_ROOT *tmp_root, struct st_plugin_int *plugin, } state= PLUGIN_IS_READY; // plugin->init() succeeded + { + static const char * INNODB= "InnoDB"; + static const uint INNODB_LEN= strlen(INNODB); + + if (!my_strnncoll(&my_charset_latin1, + (const uchar *) plugin->name.str, plugin->name.length, + (const uchar *) INNODB, INNODB_LEN)) + { + innodb_plugin= plugin; + } + } + if (plugin->plugin->status_vars) { /* diff --git a/sql/sql_plugin.h b/sql/sql_plugin.h index 7b89246a9f9..e399fec8339 100644 --- a/sql/sql_plugin.h +++ b/sql/sql_plugin.h @@ -160,6 +160,8 @@ extern ulong plugin_maturity; extern TYPELIB plugin_maturity_values; extern const char *plugin_maturity_names[]; +extern st_plugin_int* innodb_plugin; + extern int plugin_init(int *argc, char **argv, int init_flags); extern void plugin_shutdown(void); void add_plugin_options(DYNAMIC_ARRAY *options, MEM_ROOT *mem_root); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index db50d471183..207ce5c0139 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -55,6 +55,7 @@ #include "sql_statistics.h" #include "sql_cte.h" #include "sql_window.h" +#include "tztime.h" #include "debug_sync.h" // DEBUG_SYNC #include @@ -673,10 +674,19 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **conds, SELECT_LEX *se TABLE_LIST *table; int versioned_tables= 0; + Query_arena *arena= 0, backup; + bool is_prepare= thd->stmt_arena->is_stmt_prepare(); + + if (!thd->stmt_arena->is_conventional() + && !is_prepare + && !thd->stmt_arena->is_sp_execute()) + { + DBUG_RETURN(0); + } for (table= tables; table; table= table->next_local) { - if (table->table && table->table->versioned_by_sql()) + if (table->table && table->table->versioned()) versioned_tables++; else if (table->system_versioning.type != FOR_SYSTEM_TIME_UNSPECIFIED) { @@ -688,52 +698,115 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **conds, SELECT_LEX *se if (versioned_tables == 0) DBUG_RETURN(0); + /* For prepared statements we create items on statement arena, + because they must outlive execution phase for multiple executions. */ + arena= thd->activate_stmt_arena_if_needed(&backup); + + if (select_lex->saved_conds) + { + DBUG_ASSERT(thd->stmt_arena->is_sp_execute()); + *conds= select_lex->saved_conds; + } + else if (thd->stmt_arena->is_sp_execute()) + { + if (thd->stmt_arena->is_stmt_execute()) + *conds= 0; + else if (*conds) + select_lex->saved_conds= (*conds)->copy_andor_structure(thd); + } + for (table= tables; table; table= table->next_local) { - if (table->table && table->table->versioned_by_sql()) + if (table->table && table->table->versioned()) { Field *fstart= table->table->vers_start_field(); Field *fend= table->table->vers_end_field(); - Item *istart= new (thd->mem_root) Item_field(thd, fstart); - Item *iend= new (thd->mem_root) Item_field(thd, fend); - Item *cond1= 0, *cond2= 0, *curr = 0; + + DBUG_ASSERT(select_lex->parent_lex); + Name_resolution_context *context= select_lex->parent_lex->current_context(); + DBUG_ASSERT(context); + + Item *row_start= new (thd->mem_root) Item_field(thd, context, fstart); + Item *row_end= new (thd->mem_root) Item_field(thd, context, fend); + Item *row_end2= row_end; + + if (!table->table->versioned_by_sql()) + { + DBUG_ASSERT(table->table->s && table->table->s->db_plugin); + row_start= new (thd->mem_root) Item_func_vtq_ts( + thd, + row_start, + VTQ_COMMIT_TS, + plugin_hton(table->table->s->db_plugin)); + row_end= new (thd->mem_root) Item_func_vtq_ts( + thd, + row_end, + VTQ_COMMIT_TS, + plugin_hton(table->table->s->db_plugin)); + } + + Item *cond1= 0, *cond2= 0, *curr= 0; switch (table->system_versioning.type) { case FOR_SYSTEM_TIME_UNSPECIFIED: - curr= new (thd->mem_root) Item_func_now_local(thd, 6); - cond1= new (thd->mem_root) Item_func_le(thd, istart, curr); - cond2= new (thd->mem_root) Item_func_gt(thd, iend, curr); + if (table->table->versioned_by_sql()) + { + MYSQL_TIME max_time; + thd->variables.time_zone->gmt_sec_to_TIME(&max_time, TIMESTAMP_MAX_VALUE); + curr= new (thd->mem_root) Item_datetime_literal(thd, &max_time); + cond1= new (thd->mem_root) Item_func_eq(thd, row_end, curr); + } + else + { + curr= new (thd->mem_root) Item_int(thd, ULONGLONG_MAX); + cond1= new (thd->mem_root) Item_func_eq(thd, row_end2, curr); + } break; case FOR_SYSTEM_TIME_AS_OF: - cond1= new (thd->mem_root) Item_func_le(thd, istart, - table->system_versioning.start); - cond2= new (thd->mem_root) Item_func_gt(thd, iend, - table->system_versioning.start); + cond1= new (thd->mem_root) Item_func_le(thd, row_start, + table->system_versioning.start); + cond2= new (thd->mem_root) Item_func_gt(thd, row_end, + table->system_versioning.start); break; case FOR_SYSTEM_TIME_FROM_TO: - cond1= new (thd->mem_root) Item_func_lt(thd, istart, + cond1= new (thd->mem_root) Item_func_lt(thd, row_start, table->system_versioning.end); - cond2= new (thd->mem_root) Item_func_ge(thd, iend, + cond2= new (thd->mem_root) Item_func_ge(thd, row_end, table->system_versioning.start); break; case FOR_SYSTEM_TIME_BETWEEN: - cond1= new (thd->mem_root) Item_func_le(thd, istart, + cond1= new (thd->mem_root) Item_func_le(thd, row_start, table->system_versioning.end); - cond2= new (thd->mem_root) Item_func_ge(thd, iend, + cond2= new (thd->mem_root) Item_func_ge(thd, row_end, table->system_versioning.start); break; default: DBUG_ASSERT(0); } - if (cond1 && cond2) + + if (cond1) { - COND *system_time_cond= new (thd->mem_root) Item_cond_and(thd, cond1, cond2); - thd->change_item_tree(conds, and_items(thd, *conds, system_time_cond)); + cond1= and_items(thd, + *conds, + and_items(thd, + cond2, + cond1)); + + if (arena) + *conds= cond1; + else + thd->change_item_tree(conds, cond1); + table->system_versioning.is_moved_to_where= true; } } } + if (arena) + { + thd->restore_active_arena(arena, &backup); + } + DBUG_RETURN(0); } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 2bcf0199429..084e98b143f 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2224,7 +2224,7 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, hton->index_options); } - if (table->versioned_by_sql()) + if (table->versioned()) { const Field *fs = table->vers_start_field(); const Field *fe = table->vers_end_field(); @@ -2273,7 +2273,7 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, add_table_options(thd, table, create_info_arg, table_list->schema_table != 0, 0, packet); - if (table->versioned_by_sql()) + if (table->versioned()) { packet->append(STRING_WITH_LEN(" WITH SYSTEM VERSIONING")); } diff --git a/sql/sql_time.cc b/sql/sql_time.cc index 6f37f97feef..ee40dbff876 100644 --- a/sql/sql_time.cc +++ b/sql/sql_time.cc @@ -476,18 +476,6 @@ void localtime_to_TIME(MYSQL_TIME *to, struct tm *from) } -/* - Convert seconds since Epoch to TIME -*/ - -void unix_time_to_TIME(MYSQL_TIME *to, time_t secs, suseconds_t usecs) -{ - struct tm tm_time; - localtime_r(&secs, &tm_time); - localtime_to_TIME(to, &tm_time); - to->second_part = usecs; -} - void calc_time_from_sec(MYSQL_TIME *to, long seconds, long microseconds) { long t_seconds; diff --git a/sql/sql_time.h b/sql/sql_time.h index fd0c0273dcf..e6246d91fa5 100644 --- a/sql/sql_time.h +++ b/sql/sql_time.h @@ -171,15 +171,6 @@ bool calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2, int lsign, MYSQL_TIME *l_time3, ulonglong fuzzydate); int my_time_compare(const MYSQL_TIME *a, const MYSQL_TIME *b); void localtime_to_TIME(MYSQL_TIME *to, struct tm *from); -void unix_time_to_TIME(MYSQL_TIME *to, time_t secs, suseconds_t usecs); - -inline -longlong unix_time_to_packed(time_t secs, suseconds_t usecs) -{ - MYSQL_TIME mysql_time; - unix_time_to_TIME(&mysql_time, secs, usecs); - return pack_time(&mysql_time); -} void calc_time_from_sec(MYSQL_TIME *to, long seconds, long microseconds); uint calc_week(MYSQL_TIME *l_time, uint week_behaviour, uint *year); diff --git a/sql/tztime.h b/sql/tztime.h index eb7d85c48b2..d3f19fa2fd3 100644 --- a/sql/tztime.h +++ b/sql/tztime.h @@ -89,6 +89,7 @@ extern my_time_t sec_since_epoch_TIME(MYSQL_TIME *t); static const int MY_TZ_TABLES_COUNT= 4; +extern Time_zone* thd_get_timezone(THD* thd); #endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */ #endif /* TZTIME_INCLUDED */ diff --git a/sql/vtq.h b/sql/vtq.h new file mode 100755 index 00000000000..3a235352853 --- /dev/null +++ b/sql/vtq.h @@ -0,0 +1,25 @@ +#ifndef VTQ_INCLUDED +#define VTQ_INCLUDED +/* Copyright (c) 2016, MariaDB Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ + +enum vtq_field_t +{ + VTQ_BEGIN_TS = 0, + VTQ_COMMIT_TS +}; + +#endif /* VTQ_INCLUDED */ + diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc index 0b0902ba1b7..e3eb1004c62 100644 --- a/storage/innobase/dict/dict0crea.cc +++ b/storage/innobase/dict/dict0crea.cc @@ -1920,7 +1920,7 @@ dict_create_or_check_vtq_table(void) row_drop_table_for_mysql("SYS_VTQ", trx, false, TRUE); } - ib::warn() << + ib::info() << "Creating VTQ system table."; srv_file_per_table_backup = srv_file_per_table; diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc index 0fe6981f675..415f5eb8531 100644 --- a/storage/innobase/dict/dict0load.cc +++ b/storage/innobase/dict/dict0load.cc @@ -846,8 +846,8 @@ dict_process_sys_vtq( mem_heap_t* heap, /*!< in/out: heap memory */ const rec_t* rec, /*!< in: current rec */ trx_id_t* col_trx_id, /*!< out: field values */ -ullong* col_begin_ts, -ullong* col_commit_ts, +timeval* col_begin_ts, +timeval* col_commit_ts, char** col_concurr_trx) { ulint len, col, concurr_n; @@ -877,7 +877,8 @@ char** col_concurr_trx) if (len != sizeof(ullong)) return dict_print_error(heap, col, len, sizeof(ullong)); - *col_begin_ts = mach_read_from_8(field); + col_begin_ts->tv_sec = mach_read_from_4(field); + col_begin_ts->tv_usec = mach_read_from_4(field + 4); /* COMMIT_TS */ field = rec_get_nth_field_old( rec, (col = DICT_FLD__SYS_VTQ__COMMIT_TS), &len); @@ -885,7 +886,8 @@ char** col_concurr_trx) if (len != sizeof(ullong)) return dict_print_error(heap, col, len, sizeof(ullong)); - *col_commit_ts = mach_read_from_8(field); + col_commit_ts->tv_sec = mach_read_from_4(field); + col_commit_ts->tv_usec = mach_read_from_4(field + 4); /* CONCURR_TRX */ field = rec_get_nth_field_old( rec, (col = DICT_FLD__SYS_VTQ__CONCURR_TRX), &len); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 2899654e49d..8d0a742fa89 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -53,6 +53,7 @@ this program; if not, write to the Free Software Foundation, Inc., // MySQL 5.7 Header */ // #include #include +#include #include #include #include @@ -120,6 +121,7 @@ this program; if not, write to the Free Software Foundation, Inc., #include "trx0xa.h" #include "ut0mem.h" #include "row0ext.h" +#include "vtq.h" #define thd_get_trx_isolation(X) ((enum_tx_isolation)thd_tx_isolation(X)) @@ -1539,6 +1541,9 @@ innobase_fts_store_docid( } #endif +bool +innobase_get_vtq_ts(THD* thd, MYSQL_TIME *out, ulonglong in_trx_id, vtq_field_t field); + /*************************************************************//** Check for a valid value of innobase_commit_concurrency. @return 0 for valid innodb_commit_concurrency */ @@ -3871,6 +3876,9 @@ innobase_init( innobase_hton->table_options = innodb_table_option_list; + /* System Versioning */ + innobase_hton->vers_get_vtq_ts = innobase_get_vtq_ts; + innodb_remember_check_sysvar_funcs(); ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR); @@ -23109,3 +23117,108 @@ ib_push_frm_error( break; } } + + +inline +void +innobase_get_vtq_ts_result(THD* thd, vtq_query_t* q, MYSQL_TIME *out, vtq_field_t field) +{ + switch (field) { + case VTQ_BEGIN_TS: + thd_get_timezone(thd)->gmt_sec_to_TIME(out, q->begin_ts.tv_sec); + out->second_part = q->begin_ts.tv_usec; + break; + case VTQ_COMMIT_TS: + thd_get_timezone(thd)->gmt_sec_to_TIME(out, q->commit_ts.tv_sec); + out->second_part = q->commit_ts.tv_usec; + break; + default: + ut_error; + } +} + +UNIV_INTERN +bool +innobase_get_vtq_ts(THD* thd, MYSQL_TIME *out, ulonglong _in_trx_id, vtq_field_t field) +{ + trx_t* trx; + dict_index_t* index; + btr_pcur_t pcur; + dtuple_t* tuple; + dfield_t* dfield; + trx_id_t trx_id_net; + mtr_t mtr; + mem_heap_t* heap; + rec_t* rec; + ulint len; + byte* result_net; + bool found = false; + + DBUG_ENTER("innobase_get_vtq_ts"); + + if (_in_trx_id == 0) { + DBUG_RETURN(false); + } + + ut_ad(sizeof(_in_trx_id) == sizeof(trx_id_t)); + trx_id_t in_trx_id = static_cast(_in_trx_id); + + trx = thd_to_trx(thd); + ut_a(trx); + vtq_query_t* q = &trx->vtq_query; + + if (q->trx_id == in_trx_id) { + innobase_get_vtq_ts_result(thd, q, out, field); + DBUG_RETURN(true); + } + + index = dict_table_get_first_index(dict_sys->sys_vtq); + heap = mem_heap_create(0); + + ut_ad(index); + ut_ad(dict_index_is_clust(index)); + + mach_write_to_8( + reinterpret_cast(&trx_id_net), + in_trx_id); + + tuple = dtuple_create(heap, 1); + dfield = dtuple_get_nth_field(tuple, DICT_FLD__SYS_VTQ__TRX_ID); + dfield_set_data(dfield, &trx_id_net, 8); + dict_index_copy_types(tuple, index, 1); + + mtr_start_trx(&mtr, trx); + btr_pcur_open_on_user_rec(index, tuple, PAGE_CUR_GE, + BTR_SEARCH_LEAF, &pcur, &mtr); + + if (!btr_pcur_is_on_user_rec(&pcur)) + goto not_found; + + rec = btr_pcur_get_rec(&pcur); + result_net = rec_get_nth_field_old(rec, DICT_FLD__SYS_VTQ__TRX_ID, &len); + ut_ad(len == 8); + q->trx_id = mach_read_from_8(result_net); + + result_net = rec_get_nth_field_old(rec, DICT_FLD__SYS_VTQ__BEGIN_TS, &len); + ut_ad(len == 8); + q->begin_ts.tv_sec = mach_read_from_4(result_net); + q->begin_ts.tv_usec = mach_read_from_4(result_net + 4); + + result_net = rec_get_nth_field_old(rec, DICT_FLD__SYS_VTQ__COMMIT_TS, &len); + ut_ad(len == 8); + q->commit_ts.tv_sec = mach_read_from_4(result_net); + q->commit_ts.tv_usec = mach_read_from_4(result_net + 4); + + if (q->trx_id != in_trx_id) + goto not_found; + + innobase_get_vtq_ts_result(thd, q, out, field); + found = true; + +not_found: + btr_pcur_close(&pcur); + mtr_commit(&mtr); + mem_heap_free(heap); + + DBUG_RETURN(found); +} diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index 7125e2645aa..d3f3cff82f8 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -28,6 +28,8 @@ Modified Dec 29, 2014 Jan Lindström (Added sys_semaphore_waits) #include "ha_prototypes.h" #include #include +#include + #include "univ.i" #include @@ -375,22 +377,19 @@ Auxiliary function to store packed timestamp value in MYSQL_TYPE_DATETIME field. If the value is ULINT_UNDEFINED then the field it set to NULL. @return 0 on success */ int -field_store_packed_ts( +field_store_timeval( /*==============*/ Field* field, /*!< in/out: target field for storage */ -ullong n) /*!< in: value to store */ +timeval t, /*!< in: value to store */ +THD* thd) { int ret; MYSQL_TIME tmp; - if (n != UINT64_UNDEFINED) { - unpack_time(n, &tmp); - ret = field->store_time(&tmp); - field->set_notnull(); - } else { - ret = 0; /* success */ - field->set_null(); - } + thd_get_timezone(thd)->gmt_sec_to_TIME(&tmp, t.tv_sec); + tmp.second_part = t.tv_usec; + ret = field->store_time(&tmp); + field->set_notnull(); return(ret); } @@ -9711,8 +9710,8 @@ i_s_dict_fill_vtq( /*========================*/ THD* thd, /*!< in: thread */ ullong col_trx_id, /*!< in: table fields */ - ullong col_begin_ts, - ullong col_commit_ts, + timeval& col_begin_ts, + timeval& col_commit_ts, char* col_concurr_trx, TABLE* table_to_fill) /*!< in/out: fill this table */ { @@ -9722,8 +9721,8 @@ i_s_dict_fill_vtq( fields = table_to_fill->field; OK(field_store_ullong(fields[SYS_VTQ_TRX_ID], col_trx_id)); - OK(field_store_packed_ts(fields[SYS_VTQ_BEGIN_TS], col_begin_ts)); - OK(field_store_packed_ts(fields[SYS_VTQ_COMMIT_TS], col_commit_ts)); + OK(field_store_timeval(fields[SYS_VTQ_BEGIN_TS], col_begin_ts, thd)); + OK(field_store_timeval(fields[SYS_VTQ_COMMIT_TS], col_commit_ts, thd)); OK(field_store_string(fields[SYS_VTQ_CONCURR_TRX], col_concurr_trx)); OK(schema_table_store_record(thd, table_to_fill)); @@ -9770,8 +9769,8 @@ i_s_sys_vtq_fill_table( for (int i = 0; rec && i < I_S_SYS_VTQ_LIMIT; ++i) { const char* err_msg; trx_id_t col_trx_id; - ullong col_begin_ts; - ullong col_commit_ts; + timeval col_begin_ts; + timeval col_commit_ts; char* col_concurr_trx; /* Extract necessary information from SYS_VTQ row */ diff --git a/storage/innobase/include/dict0load.h b/storage/innobase/include/dict0load.h index 6c0c1ddc267..d9533240c18 100644 --- a/storage/innobase/include/dict0load.h +++ b/storage/innobase/include/dict0load.h @@ -328,8 +328,8 @@ dict_process_sys_vtq( mem_heap_t* heap, /*!< in/out: heap memory */ const rec_t* rec, /*!< in: current rec */ ullong* col_trx_id, /*!< out: field values */ -ullong* col_begin_ts, -ullong* col_commit_ts, +timeval* col_begin_ts, +timeval* col_commit_ts, char** col_concurr_trx); /** Update the record for space_id in SYS_TABLESPACES to this filepath. diff --git a/storage/innobase/include/row0ins.ic b/storage/innobase/include/row0ins.ic index 3192affc327..7b91e8b3cac 100644 --- a/storage/innobase/include/row0ins.ic +++ b/storage/innobase/include/row0ins.ic @@ -35,10 +35,25 @@ void set_row_field_8( dfield_t* dfield = dtuple_get_nth_field(row, field_num); ut_ad(dfield->type.len == fsize); if (dfield->len == UNIV_SQL_NULL) { - byte* buf = static_cast(mem_heap_alloc(heap, fsize)); - mach_write_to_8(buf, data); + byte* buf = reinterpret_cast(mem_heap_alloc(heap, fsize)); dfield_set_data(dfield, buf, fsize); - } else { - mach_write_to_8(dfield->data, data); } + mach_write_to_8(dfield->data, data); +} + +UNIV_INLINE +void set_row_field_8( + dtuple_t* row, + int field_num, + timeval& data, + mem_heap_t* heap) +{ + dfield_t* dfield = dtuple_get_nth_field(row, field_num); + ut_ad(dfield->type.len == 8); + if (dfield->len == UNIV_SQL_NULL) { + byte* buf = reinterpret_cast(mem_heap_alloc(heap, 8)); + dfield_set_data(dfield, buf, 8); + } + mach_write_to_4(reinterpret_cast(dfield->data), (ulint) data.tv_sec); + mach_write_to_4(reinterpret_cast(dfield->data) + 4, (ulint) data.tv_usec); } diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index a1de49cae1f..995929b957c 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -829,6 +829,12 @@ typedef enum { TRX_WSREP_ABORT = 1 } trx_abort_t; +struct vtq_query_t +{ + trx_id_t trx_id; + timeval begin_ts; + timeval commit_ts; +}; /** Represents an instance of rollback segment along with its state variables.*/ struct trx_undo_ptr_t { @@ -1267,7 +1273,12 @@ struct trx_t { os_event_t wsrep_event; /* event waited for in srv_conc_slot */ #endif /* WITH_WSREP */ - bool vtq_notify_on_commit; /*!< Notify VTQ for System Versioned update */ + /* System Versioning */ + bool vtq_notify_on_commit; + /*!< Notify VTQ for System Versioned update */ + vtq_query_t vtq_query; + trx_id_t* vtq_concurr_trx; + ulint vtq_concurr_n; ulint magic_n; /** @return whether any persistent undo log has been generated */ diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 4ee2be787ec..3e2f0683d18 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -55,7 +55,6 @@ Created 4/20/1996 Heikki Tuuri #include "fts0types.h" #include "m_string.h" #include "gis0geo.h" -#include "sql_time.h" /************************************************************************* IMPORTANT NOTE: Any operation that generates redo MUST check that there @@ -3876,12 +3875,6 @@ vers_row_ins_vtq_low(trx_t* trx, mem_heap_t* heap, dtuple_t* row) err = row_ins_sec_index_entry_low( flags, BTR_MODIFY_TREE, index, offsets_heap, heap, entry, trx->id, NULL, false, trx); - - ///* Report correct index name for duplicate key error. */ - // No need to report on commit phase? - //if (err == DB_DUPLICATE_KEY) { - // trx->error_key_num = n_index; - //} } while (err == DB_SUCCESS); mem_heap_free(offsets_heap); @@ -3897,10 +3890,10 @@ void vers_notify_vtq(trx_t* trx) mem_heap_t* heap = mem_heap_create(1024); dtuple_t* row = dtuple_create(heap, dict_table_get_n_cols(dict_sys->sys_vtq)); - ulint now_secs, now_usecs; - ut_usectime(&now_secs, &now_usecs); - ullong begin_ts = unix_time_to_packed(trx->start_time, trx->start_time_micro); - ullong commit_ts = unix_time_to_packed(now_secs, now_usecs); + timeval begin_ts, commit_ts; + begin_ts.tv_sec = trx->start_time; + begin_ts.tv_usec = trx->start_time_micro; + ut_usectime((ulint *)&commit_ts.tv_sec, (ulint *)&commit_ts.tv_usec); dict_table_copy_types(row, dict_sys->sys_vtq); set_row_field_8(row, DICT_FLD__SYS_VTQ__TRX_ID, trx->id, heap); @@ -3908,35 +3901,16 @@ void vers_notify_vtq(trx_t* trx) set_row_field_8(row, DICT_FLD__SYS_VTQ__COMMIT_TS - 2, commit_ts, heap); dfield_t* dfield = dtuple_get_nth_field(row, DICT_FLD__SYS_VTQ__CONCURR_TRX - 2); - mutex_enter(&trx_sys->mutex); - trx_ut_list_t &rw_list = trx_sys->rw_trx_list; - if (rw_list.count > 1) { - byte* buf = static_cast(mem_heap_alloc(heap, rw_list.count * 8)); - byte* ptr = buf; - ulint count = 0; - - for (trx_t* ctrx = UT_LIST_GET_FIRST(rw_list); - ctrx != NULL; - ctrx = UT_LIST_GET_NEXT(trx_list, ctrx)) - { - if (ctrx == trx || ctrx->state == TRX_STATE_NOT_STARTED) - continue; - - mach_write_to_8(ptr, ctrx->id); - ++count; + ulint count = 0; + byte* buf = NULL; + if (trx->vtq_concurr_n > 0) { + buf = static_cast(mem_heap_alloc(heap, trx->vtq_concurr_n * 8)); + for (byte* ptr = buf; count < trx->vtq_concurr_n; ++count) { + mach_write_to_8(ptr, trx->vtq_concurr_trx[count]); ptr += 8; } - - if (count) - dfield_set_data(dfield, buf, count * 8); - else - dfield_set_data(dfield, NULL, 0); - } else { - // there must be at least current transaction - ut_ad(rw_list.count == 1 && UT_LIST_GET_FIRST(rw_list) == trx); - dfield_set_data(dfield, NULL, 0); } - mutex_exit(&trx_sys->mutex); + dfield_set_data(dfield, buf, count * 8); err = vers_row_ins_vtq_low(trx, heap, row); if (DB_SUCCESS != err) diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 2bf26f242ca..2e3121a2e57 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -1489,11 +1489,22 @@ row_insert_for_mysql( if (DICT_TF2_FLAG_IS_SET(node->table, DICT_TF2_VERSIONED)) { ut_ad(table->vers_row_start != table->vers_row_end); + /* Return back modified fields into mysql_rec, so that + upper logic may benefit from it (f.ex. 'on duplicate key'). */ + const mysql_row_templ_t* t = &prebuilt->mysql_template[table->vers_row_end]; + ut_ad(t->mysql_col_len == 8); + if (historical) { set_row_field_8(node->row, table->vers_row_end, trx->id, node->entry_sys_heap); - } else { - set_row_field_8(node->row, table->vers_row_start, trx->id, node->entry_sys_heap); + int8store(&mysql_rec[t->mysql_col_offset], trx->id); + } + else { set_row_field_8(node->row, table->vers_row_end, IB_UINT64_MAX, node->entry_sys_heap); + int8store(&mysql_rec[t->mysql_col_offset], IB_UINT64_MAX); + t = &prebuilt->mysql_template[table->vers_row_start]; + ut_ad(t->mysql_col_len == 8); + set_row_field_8(node->row, table->vers_row_start, trx->id, node->entry_sys_heap); + int8store(&mysql_rec[t->mysql_col_offset], trx->id); } } @@ -1948,20 +1959,25 @@ row_update_for_mysql_using_upd_graph( if (DICT_TF2_FLAG_IS_SET(node->table, DICT_TF2_VERSIONED)) { - /* System Versioning: update sys_trx_start to current trx_id */ + /* System Versioning: modify update vector to set + sys_trx_start (or sys_trx_end in case of DELETE) + to current trx_id. */ upd_t* uvect = node->update; upd_field_t* ufield; dict_col_t* col; + const mysql_row_templ_t* t; + unsigned col_idx; if (node->is_delete) { ufield = &uvect->fields[0]; uvect->n_fields = 0; node->is_delete = false; - col = &table->cols[table->vers_row_end]; + col_idx = table->vers_row_end; } else { ut_ad(uvect->n_fields < node->table->n_cols); ufield = &uvect->fields[uvect->n_fields]; - col = &table->cols[table->vers_row_start]; + col_idx = table->vers_row_start; } + col = &table->cols[col_idx]; UNIV_MEM_INVALID(ufield, sizeof *ufield); ufield->field_no = dict_col_get_clust_pos(col, clust_index); ufield->orig_len = 0; @@ -1976,6 +1992,11 @@ row_update_for_mysql_using_upd_graph( uvect->n_fields++; ut_ad(node->in_mysql_interface); // otherwise needs to recalculate node->cmpl_info + + /* Return trx_id back to mysql_rec (for the sake of interface consistency). */ + t = &prebuilt->mysql_template[col_idx]; + ut_ad(t->mysql_col_len == 8); + int8store(&mysql_rec[t->mysql_col_offset], trx->id); } ut_a(node->pcur->rel_pos == BTR_PCUR_ON); diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 9b6159fc81e..7e1666c1703 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -316,6 +316,10 @@ struct TrxFactory { trx->lock.table_locks.~lock_pool_t(); trx->hit_list.~hit_list_t(); + + if (trx->vtq_concurr_trx) { + ut_free(trx->vtq_concurr_trx); + } } /** Enforce any invariants here, this is called before the transaction @@ -470,8 +474,6 @@ trx_create_low() trx_free(). */ ut_a(trx->mod_tables.size() == 0); - trx->vtq_notify_on_commit = false; - #ifdef WITH_WSREP trx->wsrep_event = NULL; #endif /* WITH_WSREP */ @@ -1214,6 +1216,33 @@ trx_t::assign_temp_rseg() return(rseg); } +/** Functor to create trx_ids array. */ +struct copy_trx_ids +{ + copy_trx_ids(trx_id_t* _array, ulint& _array_size) + : array(_array), array_size(_array_size) + { + array_size = 0; + } + + void operator()(trx_t* trx) + { + ut_ad(mutex_own(&trx_sys->mutex)); + ut_ad(trx->in_rw_trx_list); + + /* trx->state cannot change from or to NOT_STARTED + while we are holding the trx_sys->mutex. It may change + from ACTIVE to PREPARED or COMMITTED. */ + + if (!trx_state_eq(trx, TRX_STATE_COMMITTED_IN_MEMORY)) { + array[array_size++] = trx->id; + } + } + + trx_id_t* array; + ulint& array_size; +}; + /****************************************************************//** Starts a transaction. */ static @@ -1303,6 +1332,13 @@ trx_start_low( || srv_read_only_mode || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO); + if (UT_LIST_GET_LEN(trx_sys->rw_trx_list) > 0) { + trx->vtq_concurr_trx = static_cast( + ut_malloc_nokey(UT_LIST_GET_LEN(trx_sys->rw_trx_list) * sizeof(trx_id_t))); + copy_trx_ids f(trx->vtq_concurr_trx, trx->vtq_concurr_n); + ut_list_map(trx_sys->rw_trx_list, f); + } + UT_LIST_ADD_FIRST(trx_sys->rw_trx_list, trx); ut_d(trx->in_rw_trx_list = true); -- cgit v1.2.1 From 3579f5f9f77bdd1078325d9e9f4a83bd1c5ee885 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 4 Oct 2016 09:36:47 +0000 Subject: Tests: insert, update, delete, insert_select, insert_update, multi_update --- mysql-test/r/delete.result | 146 ++++++++++++----------- mysql-test/r/insert.result | 225 +++++++++++++++++++++-------------- mysql-test/r/insert_select.result | 91 +++++++++------ mysql-test/r/insert_update.result | 82 ++++++++----- mysql-test/r/multi_update.result | 93 ++++++++------- mysql-test/r/update.result | 72 +++++++----- mysql-test/t/delete.test | 150 ++++++++++++------------ mysql-test/t/insert.test | 239 ++++++++++++++++++++++++-------------- mysql-test/t/insert_select.opt | 1 + mysql-test/t/insert_select.test | 134 ++++++++++++--------- mysql-test/t/insert_update.opt | 1 + mysql-test/t/insert_update.test | 104 +++++++++++------ mysql-test/t/multi_update.opt | 1 + mysql-test/t/multi_update.test | 137 ++++++++++++---------- mysql-test/t/update.test | 98 ++++++++++------ 15 files changed, 935 insertions(+), 639 deletions(-) create mode 100644 mysql-test/t/insert_select.opt create mode 100644 mysql-test/t/insert_update.opt create mode 100644 mysql-test/t/multi_update.opt diff --git a/mysql-test/r/delete.result b/mysql-test/r/delete.result index ee1d7524541..4cb396511c1 100644 --- a/mysql-test/r/delete.result +++ b/mysql-test/r/delete.result @@ -526,27 +526,56 @@ ERROR HY000: Can not delete from join view 'test.v2' DROP VIEW v2, v1; DROP TABLE t1, t2; # -# Test for SYSTEM VERSIONING +# System Versioning Support # -SET @@session.time_zone='+00:00'; -create table t1 ( -XNo INT UNSIGNED, -Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, -Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, -PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) -) WITH SYSTEM VERSIONING; -INSERT INTO t1(XNo) VALUES(0); -INSERT INTO t1(XNo) VALUES(1); -INSERT INTO t1(XNo) VALUES(2); -INSERT INTO t1(XNo) VALUES(3); -INSERT INTO t1(XNo) VALUES(4); -INSERT INTO t1(XNo) VALUES(5); -INSERT INTO t1(XNo) VALUES(6); -INSERT INTO t1(XNo) VALUES(7); -INSERT INTO t1(XNo) VALUES(8); -INSERT INTO t1(XNo) VALUES(9); -SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; -XNo Sys_end < '2038-01-19 03:14:07' +# +set @@session.time_zone='+00:00'; +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +create procedure test_01( +sys_type varchar(255), +engine varchar(255), +fields varchar(255)) +begin +set @str= concat(' + create table t1( + XNo int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); +prepare stmt from @str; execute stmt; drop prepare stmt; +insert into t1(XNo) values(0); +insert into t1(XNo) values(1); +insert into t1(XNo) values(2); +insert into t1(XNo) values(3); +insert into t1(XNo) values(4); +insert into t1(XNo) values(5); +insert into t1(XNo) values(6); +insert into t1(XNo) values(7); +insert into t1(XNo) values(8); +insert into t1(XNo) values(9); +set @str= concat('select XNo, ', +fields, " < '2038-01-19 03:14:07' + from t1 for system_time + between timestamp '0000-0-0 0:0:0' + and timestamp '2038-01-19 04:14:07'"); +prepare stmt from @str; execute stmt; +delete from t1 where XNo = 0; +execute stmt; +delete from t1 where XNo = 1; +execute stmt; +delete from t1 where XNo > 5; +create view vt1 as select XNo from t1; +select XNo from vt1; +delete from vt1 where XNo = 3; +select XNo from vt1; +execute stmt; drop prepare stmt; +drop view vt1; +drop table t1; +end~~ +call test_01('timestamp(6)', 'myisam', 'sys_end'); +XNo sys_end < '2038-01-19 03:14:07' 0 0 1 0 2 0 @@ -557,9 +586,7 @@ XNo Sys_end < '2038-01-19 03:14:07' 7 0 8 0 9 0 -DELETE FROM t1 WHERE XNo = 0; -SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; -XNo Sys_end < '2038-01-19 03:14:07' +XNo sys_end < '2038-01-19 03:14:07' 0 1 1 0 2 0 @@ -570,9 +597,7 @@ XNo Sys_end < '2038-01-19 03:14:07' 7 0 8 0 9 0 -DELETE FROM t1 WHERE XNo = 1; -SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; -XNo Sys_end < '2038-01-19 03:14:07' +XNo sys_end < '2038-01-19 03:14:07' 0 1 1 1 2 0 @@ -583,22 +608,16 @@ XNo Sys_end < '2038-01-19 03:14:07' 7 0 8 0 9 0 -DELETE FROM t1 WHERE XNo > 5; -CREATE VIEW vt1 AS SELECT XNo FROM t1; -SELECT XNo FROM vt1; XNo 2 3 4 5 -DELETE FROM vt1 WHERE XNo = 3; -SELECT XNo FROM vt1; XNo 2 4 5 -SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; -XNo Sys_end < '2038-01-19 03:14:07' +XNo sys_end < '2038-01-19 03:14:07' 0 1 1 1 2 0 @@ -609,27 +628,8 @@ XNo Sys_end < '2038-01-19 03:14:07' 7 1 8 1 9 1 -DROP VIEW vt1; -DROP TABLE t1; -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; -create table t1 ( -XNo INT UNSIGNED, -Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, -Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, -PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) -) WITH SYSTEM VERSIONING ENGINE InnoDB; -INSERT INTO t1(XNo) VALUES(0); -INSERT INTO t1(XNo) VALUES(1); -INSERT INTO t1(XNo) VALUES(2); -INSERT INTO t1(XNo) VALUES(3); -INSERT INTO t1(XNo) VALUES(4); -INSERT INTO t1(XNo) VALUES(5); -INSERT INTO t1(XNo) VALUES(6); -INSERT INTO t1(XNo) VALUES(7); -INSERT INTO t1(XNo) VALUES(8); -INSERT INTO t1(XNo) VALUES(9); -SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; -XNo Sys_end < '2038-01-19 03:14:07' +call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +XNo commit_ts(sys_end) < '2038-01-19 03:14:07' 0 0 1 0 2 0 @@ -640,9 +640,7 @@ XNo Sys_end < '2038-01-19 03:14:07' 7 0 8 0 9 0 -DELETE FROM t1 WHERE XNo = 0; -SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; -XNo Sys_end < '2038-01-19 03:14:07' +XNo commit_ts(sys_end) < '2038-01-19 03:14:07' 0 1 1 0 2 0 @@ -653,9 +651,7 @@ XNo Sys_end < '2038-01-19 03:14:07' 7 0 8 0 9 0 -DELETE FROM t1 WHERE XNo = 1; -SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; -XNo Sys_end < '2038-01-19 03:14:07' +XNo commit_ts(sys_end) < '2038-01-19 03:14:07' 0 1 1 1 2 0 @@ -666,22 +662,16 @@ XNo Sys_end < '2038-01-19 03:14:07' 7 0 8 0 9 0 -DELETE FROM t1 WHERE XNo > 5; -CREATE VIEW vt1 AS SELECT XNo FROM t1; -SELECT XNo FROM vt1; XNo 2 3 4 5 -DELETE FROM vt1 WHERE XNo = 3; -SELECT XNo FROM vt1; XNo 2 4 5 -SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; -XNo Sys_end < '2038-01-19 03:14:07' +XNo commit_ts(sys_end) < '2038-01-19 03:14:07' 0 1 1 1 2 0 @@ -692,10 +682,23 @@ XNo Sys_end < '2038-01-19 03:14:07' 7 1 8 1 9 1 -DROP VIEW vt1; -DROP TABLE t1; -SET @i = 0; -SELECT @i:=@i+1 AS No, trx_id > 0 AS A, begin_ts > '2015-1-1 0:0:0' AS B, commit_ts > begin_ts AS C, concurr_trx IS NULL AS D FROM INFORMATION_SCHEMA.INNODB_VTQ WHERE trx_id > @start_trx_id; +drop procedure test_01; +create procedure verify_vtq() +begin +set @i= 0; +select +@i:= @i + 1 as No, +trx_id > 0 as A, +begin_ts > '1-1-1 0:0:0' as B, +commit_ts > begin_ts as C, +concurr_trx is null as D +from information_schema.innodb_vtq +where trx_id > @start_trx_id; +select ifnull(max(trx_id), 0) +into @start_trx_id +from information_schema.innodb_vtq; +end~~ +call verify_vtq; No A B C D 1 1 1 1 1 2 1 1 1 1 @@ -711,3 +714,4 @@ No A B C D 12 1 1 1 1 13 1 1 1 1 14 1 1 1 1 +drop procedure verify_vtq; diff --git a/mysql-test/r/insert.result b/mysql-test/r/insert.result index 7c9776732c9..96062931f37 100644 --- a/mysql-test/r/insert.result +++ b/mysql-test/r/insert.result @@ -721,114 +721,165 @@ DROP TABLE t1; # System Versioning Support # # -SET @@session.time_zone='+00:00'; +set @@session.time_zone='+00:00'; select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; -CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; -INSERT INTO t1(x, y) VALUES(3, 4); -INSERT INTO t1(x, y) VALUES(2, 3); -INSERT INTO t1 VALUES(40, 33); -SELECT x, y, Sys_end FROM t1; -x y Sys_end +create procedure test_01( +sys_type varchar(255), +engine varchar(255), +fields varchar(255)) +begin +set @str= concat(' + create table t1( + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); +prepare stmt from @str; execute stmt; drop prepare stmt; +insert into t1(x, y) values(3, 4); +insert into t1(x, y) values(2, 3); +insert into t1 values(40, 33); +set @str= concat('select x, y, ', fields, ' from t1'); +prepare stmt from @str; execute stmt; drop prepare stmt; +drop table t1; +end~~ +call test_01('timestamp(6)', 'myisam', 'sys_end'); +x y sys_end 3 4 2038-01-19 03:14:07.000000 2 3 2038-01-19 03:14:07.000000 40 33 2038-01-19 03:14:07.000000 -DROP TABLE t1; -CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; -INSERT INTO t1(x, y) VALUES(3, 4); -INSERT INTO t1(x, y) VALUES(2, 3); -INSERT INTO t1 VALUES(40, 33); -SELECT x, y, Sys_end FROM t1; -x y Sys_end +call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +x y commit_ts(sys_end) 3 4 2038-01-19 03:14:07.000000 2 3 2038-01-19 03:14:07.000000 40 33 2038-01-19 03:14:07.000000 -DROP TABLE t1; -CREATE TABLE t1(id INT UNSIGNED NOT NULL AUTO_INCREMENT, x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end), PRIMARY KEY(id)) WITH SYSTEM VERSIONING; -INSERT INTO t1(x, y) VALUES(33, 44); -INSERT INTO t1(id, x, y) VALUES(20, 33, 44); -INSERT INTO t1 VALUES(40, 33, 44); -SELECT id, x, y, Sys_end FROM t1; -id x y Sys_end +drop procedure test_01; +create procedure test_02( +sys_type varchar(255), +engine varchar(255), +fields varchar(255)) +begin +set @str= concat(' + create table t1( + id int unsigned auto_increment primary key, + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); +prepare stmt from @str; execute stmt; drop prepare stmt; +insert into t1(x, y) values(33, 44); +insert into t1(id, x, y) values(20, 33, 44); +insert into t1 values(40, 33, 44); +set @str= concat('select id, x, y, ', fields, ' from t1'); +prepare stmt from @str; execute stmt; drop prepare stmt; +drop table t1; +end~~ +call test_02('timestamp(6)', 'myisam', 'sys_end'); +id x y sys_end 1 33 44 2038-01-19 03:14:07.000000 20 33 44 2038-01-19 03:14:07.000000 40 33 44 2038-01-19 03:14:07.000000 -DROP TABLE t1; -CREATE TABLE t1(id INT UNSIGNED NOT NULL AUTO_INCREMENT, x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end), PRIMARY KEY(id)) WITH SYSTEM VERSIONING ENGINE=InnoDB; -INSERT INTO t1(x, y) VALUES(33, 44); -INSERT INTO t1(id, x, y) VALUES(20, 33, 44); -INSERT INTO t1 VALUES(40, 33, 44); -SELECT id, x, y, Sys_end FROM t1; -id x y Sys_end +call test_02('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +id x y commit_ts(sys_end) 1 33 44 2038-01-19 03:14:07.000000 20 33 44 2038-01-19 03:14:07.000000 40 33 44 2038-01-19 03:14:07.000000 -DROP TABLE t1; -CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; -CREATE VIEW vt1_1 AS SELECT x, y FROM t1; -CREATE VIEW vt1_2 AS SELECT x, y, Sys_end FROM t1; -INSERT INTO t1(x, y) VALUES(8001, 9001); -INSERT INTO t1(x, y, Sys_end) VALUES(8001, 9001, '2015-1-1 0:0:0'); -ERROR HY000: Generated field for System Versioning cannot be set by user -INSERT INTO vt1_1(x, y) VALUES(1001, 2001); -INSERT INTO vt1_1 VALUES(1002, 2002); -INSERT INTO vt1_2(x, y) VALUES(3001, 4001); -INSERT INTO vt1_2 VALUES(3002, 4002, '2015-1-1 0:0:0'); -ERROR HY000: Generated field for System Versioning cannot be set by user -SELECT x, y, Sys_end FROM t1; -x y Sys_end +drop procedure test_02; +create procedure test_03( +sys_type varchar(255), +engine varchar(255), +fields varchar(255)) +begin +set @str= concat(' + create table t1( + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); +prepare stmt from @str; execute stmt; drop prepare stmt; +create view vt1_1 as select x, y from t1; +create view vt1_2 as select x, y, sys_end from t1; +insert into t1(x, y) values(8001, 9001); +insert into vt1_1(x, y) values(1001, 2001); +insert into vt1_1 values(1002, 2002); +insert into vt1_2(x, y) values(3001, 4001); +set @str= concat('select x, y, ', fields, ' from t1'); +prepare stmt from @str; execute stmt; drop prepare stmt; +select x, y from vt1_1; +set @str= concat('select x, y, ', fields, ' from vt1_2'); +prepare stmt from @str; execute stmt; drop prepare stmt; +end~~ +call test_03('timestamp(6)', 'myisam', 'sys_end'); +x y sys_end 8001 9001 2038-01-19 03:14:07.000000 1001 2001 2038-01-19 03:14:07.000000 1002 2002 2038-01-19 03:14:07.000000 3001 4001 2038-01-19 03:14:07.000000 -SELECT x, y FROM vt1_1; x y 8001 9001 1001 2001 1002 2002 3001 4001 -SELECT x, y, Sys_end FROM vt1_2; -x y Sys_end +x y sys_end 8001 9001 2038-01-19 03:14:07.000000 1001 2001 2038-01-19 03:14:07.000000 1002 2002 2038-01-19 03:14:07.000000 3001 4001 2038-01-19 03:14:07.000000 -DROP TABLE t1; -DROP VIEW vt1_1; -DROP VIEW vt1_2; -CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; -CREATE VIEW vt1_1 AS SELECT x, y FROM t1; -CREATE VIEW vt1_2 AS SELECT x, y, Sys_end FROM t1; -INSERT INTO t1(x, y) VALUES(8001, 9001); -INSERT INTO t1(x, y, Sys_end) VALUES(8001, 9001, '2015-1-1 0:0:0'); +insert into t1(x, y, sys_end) values(8001, 9001, '2015-1-1 1:1:1'); ERROR HY000: Generated field for System Versioning cannot be set by user -INSERT INTO vt1_1(x, y) VALUES(1001, 2001); -INSERT INTO vt1_1 VALUES(1002, 2002); -INSERT INTO vt1_2(x, y) VALUES(3001, 4001); -INSERT INTO vt1_2 VALUES(3002, 4002, '2015-1-1 0:0:0'); +insert into vt1_2 values(3002, 4002, '2015-2-2 2:2:2'); ERROR HY000: Generated field for System Versioning cannot be set by user -SELECT x, y, Sys_end FROM t1; -x y Sys_end +drop table t1; +drop view vt1_1; +drop view vt1_2; +call test_03('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +x y commit_ts(sys_end) 8001 9001 2038-01-19 03:14:07.000000 1001 2001 2038-01-19 03:14:07.000000 1002 2002 2038-01-19 03:14:07.000000 3001 4001 2038-01-19 03:14:07.000000 -SELECT x, y FROM vt1_1; x y 8001 9001 1001 2001 1002 2002 3001 4001 -SELECT x, y, Sys_end FROM vt1_2; -x y Sys_end +x y commit_ts(sys_end) 8001 9001 2038-01-19 03:14:07.000000 1001 2001 2038-01-19 03:14:07.000000 1002 2002 2038-01-19 03:14:07.000000 3001 4001 2038-01-19 03:14:07.000000 -DROP TABLE t1; -DROP VIEW vt1_1; -DROP VIEW vt1_2; -SET @i = 0; -SELECT @i:=@i+1 AS No, trx_id > 0 AS A, begin_ts > '2015-1-1 0:0:0' AS B, commit_ts > begin_ts AS C, concurr_trx IS NULL AS D FROM INFORMATION_SCHEMA.INNODB_VTQ WHERE trx_id > @start_trx_id; +insert into t1(x, y, sys_end) values(8001, 9001, 1111111); +ERROR HY000: Generated field for System Versioning cannot be set by user +insert into vt1_2 values(3002, 4002, 2222222); +ERROR HY000: Generated field for System Versioning cannot be set by user +drop table t1; +drop view vt1_1; +drop view vt1_2; +drop procedure test_03; +create procedure verify_vtq() +begin +set @i= 0; +select +@i:= @i + 1 as No, +trx_id > 0 as A, +begin_ts > '1-1-1 0:0:0' as B, +commit_ts > begin_ts as C, +concurr_trx is null as D +from information_schema.innodb_vtq +where trx_id > @start_trx_id; +select ifnull(max(trx_id), 0) +into @start_trx_id +from information_schema.innodb_vtq; +end~~ +call verify_vtq; No A B C D 1 1 1 1 1 2 1 1 1 1 @@ -840,25 +891,27 @@ No A B C D 8 1 1 1 1 9 1 1 1 1 10 1 1 1 1 -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; -CREATE TABLE t1(x INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; -CREATE TABLE t2(x INT UNSIGNED) ENGINE=InnoDB; -START TRANSACTION; -INSERT INTO t1(x) VALUES(1); -COMMIT; -SET @i = 0; -SELECT @i:=@i+1 AS No, trx_id > 0 AS A, begin_ts > '2015-1-1 0:0:0' AS B, commit_ts > begin_ts AS C, concurr_trx IS NULL AS D FROM INFORMATION_SCHEMA.INNODB_VTQ WHERE trx_id > @start_trx_id; +create table t1( +x int unsigned, +sys_start bigint unsigned generated always as row start, +sys_end bigint unsigned generated always as row end, +period for system_time (sys_start, sys_end)) +with system versioning engine=innodb; +create table t2(x int unsigned) engine=innodb; +start transaction; +insert into t1(x) values(1); +commit; +call verify_vtq; No A B C D 1 1 1 1 1 -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; -START TRANSACTION; -INSERT INTO t2(x) VALUES(1); -SAVEPOINT a; -INSERT INTO t1(x) VALUES(1); -ROLLBACK TO a; -COMMIT; -SET @i = 0; -SELECT @i:=@i+1 AS No, trx_id > 0 AS A, begin_ts > '2015-1-1 0:0:0' AS B, commit_ts > begin_ts AS C, concurr_trx IS NULL AS D FROM INFORMATION_SCHEMA.INNODB_VTQ WHERE trx_id > @start_trx_id; +start transaction; +insert into t2(x) values(1); +savepoint a; +insert into t1(x) values(1); +rollback to a; +commit; +call verify_vtq; No A B C D -DROP TABLE t1; -DROP TABLE t2; +drop table t1; +drop table t2; +drop procedure verify_vtq; diff --git a/mysql-test/r/insert_select.result b/mysql-test/r/insert_select.result index da236c53825..3d38a934c71 100644 --- a/mysql-test/r/insert_select.result +++ b/mysql-test/r/insert_select.result @@ -860,9 +860,26 @@ End of 5.1 tests # System Versioning Support # # -CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=MyISAM; -CREATE TABLE t2(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=MyISAM; -INSERT INTO t1(x, y) VALUES +set @@session.time_zone='+00:00'; +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +create procedure test_01( +sys_type varchar(255), +engine varchar(255), +fields varchar(255)) +begin +set @str= concat('( + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); +set @str2= concat('create table t1', @str); +prepare stmt from @str2; execute stmt; drop prepare stmt; +set @str2= concat('create table t2', @str); +prepare stmt from @str2; execute stmt; drop prepare stmt; +insert into t1(x, y) values (1, 1000), (2, 2000), (3, 3000), @@ -872,8 +889,8 @@ INSERT INTO t1(x, y) VALUES (7, 7000), (8, 8000), (9, 9000); -DELETE FROM t1 WHERE x >= 1; -INSERT INTO t1(x, y) VALUES +delete from t1 where x >= 1; +insert into t1(x, y) values (1, 1001), (2, 2001), (3, 3001), @@ -883,8 +900,13 @@ INSERT INTO t1(x, y) VALUES (7, 7001), (8, 8001), (9, 9001); -INSERT INTO t2 SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; -SELECT x, y FROM t1; +insert into t2 select x, y from t1 for system_time between timestamp '0000-0-0 0:0:0' and timestamp '9999-1-1 0:0:0'; +select x, y from t1; +select x, y from t2; +drop table t1; +drop table t2; +end~~ +call test_01('timestamp(6)', 'myisam', 'sys_end'); x y 1 1001 2 2001 @@ -895,7 +917,6 @@ x y 7 7001 8 8001 9 9001 -SELECT x, y FROM t2; x y 1 1000 2 2000 @@ -915,33 +936,7 @@ x y 7 7001 8 8001 9 9001 -DROP TABLE t1; -DROP TABLE t2; -CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; -CREATE TABLE t2(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; -INSERT INTO t1(x, y) VALUES -(1, 1000), -(2, 2000), -(3, 3000), -(4, 4000), -(5, 5000), -(6, 6000), -(7, 7000), -(8, 8000), -(9, 9000); -DELETE FROM t1 WHERE x >= 1; -INSERT INTO t1(x, y) VALUES -(1, 1001), -(2, 2001), -(3, 3001), -(4, 4001), -(5, 5001), -(6, 6001), -(7, 7001), -(8, 8001), -(9, 9001); -INSERT INTO t2 SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; -SELECT x, y FROM t1; +call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); x y 1 1001 2 2001 @@ -952,7 +947,6 @@ x y 7 7001 8 8001 9 9001 -SELECT x, y FROM t2; x y 1 1000 2 2000 @@ -972,5 +966,26 @@ x y 7 7001 8 8001 9 9001 -DROP TABLE t1; -DROP TABLE t2; +drop procedure test_01; +create procedure verify_vtq() +begin +set @i= 0; +select +@i:= @i + 1 as No, +trx_id > 0 as A, +begin_ts > '1-1-1 0:0:0' as B, +commit_ts > begin_ts as C, +concurr_trx is null as D +from information_schema.innodb_vtq +where trx_id > @start_trx_id; +select ifnull(max(trx_id), 0) +into @start_trx_id +from information_schema.innodb_vtq; +end~~ +call verify_vtq; +No A B C D +1 1 1 1 1 +2 1 1 1 1 +3 1 1 1 1 +4 1 1 1 1 +drop procedure verify_vtq; diff --git a/mysql-test/r/insert_update.result b/mysql-test/r/insert_update.result index 6f25fd18b6a..e8567afdd45 100644 --- a/mysql-test/r/insert_update.result +++ b/mysql-test/r/insert_update.result @@ -416,8 +416,25 @@ drop table t1; # System Versioning Support # # -CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end), PRIMARY KEY(x, y)) WITH SYSTEM VERSIONING; -INSERT INTO t1(x, y) VALUES +set @@session.time_zone='+00:00'; +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +create procedure test_01( +sys_type varchar(255), +engine varchar(255), +fields varchar(255)) +begin +set @str= concat(' + create table t1( + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end), + primary key(x, y)) + with system versioning + engine ', engine); +prepare stmt from @str; execute stmt; drop prepare stmt; +insert into t1(x, y) values (1, 1000), (2, 2000), (3, 3000), @@ -427,11 +444,15 @@ INSERT INTO t1(x, y) VALUES (7, 7000), (8, 8000), (9, 9000); -INSERT INTO t1(x, y) VALUES(3, 3000) ON DUPLICATE KEY UPDATE y = y+1; -INSERT INTO t1(x, y) VALUES(4, 4000) ON DUPLICATE KEY UPDATE y = y+1; -INSERT INTO t1(x, y) VALUES(4, 4001) ON DUPLICATE KEY UPDATE y = y+1; -INSERT INTO t1(x, y) VALUES(4, 4444) ON DUPLICATE KEY UPDATE y = y+1; -SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; +insert into t1(x, y) values(3, 3000) on duplicate key update y = y+1; +insert into t1(x, y) values(4, 4000) on duplicate key update y = y+1; +insert into t1(x, y) values(4, 4001) on duplicate key update y = y+1; +insert into t1(x, y) values(4, 4444) on duplicate key update y = y+1; +select x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp '9999-1-1 0:0:0'; +select x, y from t1; +drop table t1; +end~~ +call test_01('timestamp(6)', 'myisam', 'sys_end'); x y 1 1000 2 2000 @@ -446,35 +467,18 @@ x y 4 4000 4 4001 4 4444 -SELECT x, y FROM t1; x y 1 1000 2 2000 3 3001 4 4002 +4 4444 5 5000 6 6000 7 7000 8 8000 9 9000 -4 4444 -DROP TABLE t1; -CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end), PRIMARY KEY(x, y)) WITH SYSTEM VERSIONING ENGINE=InnoDB; -INSERT INTO t1(x, y) VALUES -(1, 1000), -(2, 2000), -(3, 3000), -(4, 4000), -(5, 5000), -(6, 6000), -(7, 7000), -(8, 8000), -(9, 9000); -INSERT INTO t1(x, y) VALUES(3, 3000) ON DUPLICATE KEY UPDATE y = y+1; -INSERT INTO t1(x, y) VALUES(4, 4000) ON DUPLICATE KEY UPDATE y = y+1; -INSERT INTO t1(x, y) VALUES(4, 4001) ON DUPLICATE KEY UPDATE y = y+1; -INSERT INTO t1(x, y) VALUES(4, 4444) ON DUPLICATE KEY UPDATE y = y+1; -SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; +call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); x y 1 1000 2 2000 @@ -489,7 +493,6 @@ x y 7 7000 8 8000 9 9000 -SELECT x, y FROM t1; x y 1 1000 2 2000 @@ -501,4 +504,27 @@ x y 7 7000 8 8000 9 9000 -DROP TABLE t1; +drop procedure test_01; +create procedure verify_vtq() +begin +set @i= 0; +select +@i:= @i + 1 as No, +trx_id > 0 as A, +begin_ts > '1-1-1 0:0:0' as B, +commit_ts > begin_ts as C, +concurr_trx is null as D +from information_schema.innodb_vtq +where trx_id > @start_trx_id; +select ifnull(max(trx_id), 0) +into @start_trx_id +from information_schema.innodb_vtq; +end~~ +call verify_vtq; +No A B C D +1 1 1 1 1 +2 1 1 1 1 +3 1 1 1 1 +4 1 1 1 1 +5 1 1 1 1 +drop procedure verify_vtq; diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result index 35966f5ac1b..d244afa03e3 100644 --- a/mysql-test/r/multi_update.result +++ b/mysql-test/r/multi_update.result @@ -1060,9 +1060,26 @@ end of 10.0 tests # System Versioning Support # # -CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; -CREATE TABLE t2(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; -INSERT INTO t1(x, y) VALUES +set @@session.time_zone='+00:00'; +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +create procedure test_01( +sys_type varchar(255), +engine varchar(255), +fields varchar(255)) +begin +set @str= concat('( + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); +set @str2= concat('create table t1', @str); +prepare stmt from @str2; execute stmt; drop prepare stmt; +set @str2= concat('create table t2', @str); +prepare stmt from @str2; execute stmt; drop prepare stmt; +insert into t1(x, y) values (1, 1000), (2, 2000), (3, 3000), @@ -1072,7 +1089,7 @@ INSERT INTO t1(x, y) VALUES (7, 7000), (8, 8000), (9, 9000); -INSERT INTO t2(x, y) VALUES +insert into t2(x, y) values (1, 1010), (2, 2010), (3, 3010), @@ -1082,8 +1099,15 @@ INSERT INTO t2(x, y) VALUES (7, 7010), (8, 8010), (9, 9010); -UPDATE t1, t2 SET t1.y = t1.x + t1.y, t2.y = t2.x + t2.y WHERE t1.x > 7 AND t2.x < 7; -SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; +update t1, t2 set t1.y = t1.x + t1.y, t2.y = t2.x + t2.y where t1.x > 7 and t2.x < 7; +select x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp '9999-1-1 0:0:0'; +select x, y from t1; +select x, y from t2 for system_time between timestamp '0-0-0 0:0:0' and timestamp '9999-1-1 0:0:0'; +select x, y from t2; +drop table t1; +drop table t2; +end~~ +call test_01('timestamp(6)', 'myisam', 'sys_end'); x y 1 1000 2 2000 @@ -1096,7 +1120,6 @@ x y 9 9009 8 8000 9 9000 -SELECT x, y FROM t1; x y 1 1000 2 2000 @@ -1107,7 +1130,6 @@ x y 7 7000 8 8008 9 9009 -SELECT x, y FROM t2 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; x y 1 1011 2 2012 @@ -1124,7 +1146,6 @@ x y 4 4010 5 5010 6 6010 -SELECT x, y FROM t2; x y 1 1011 2 2012 @@ -1135,32 +1156,7 @@ x y 7 7010 8 8010 9 9010 -DROP TABLE t1; -DROP TABLE t2; -CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; -CREATE TABLE t2(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; -INSERT INTO t1(x, y) VALUES -(1, 1000), -(2, 2000), -(3, 3000), -(4, 4000), -(5, 5000), -(6, 6000), -(7, 7000), -(8, 8000), -(9, 9000); -INSERT INTO t2(x, y) VALUES -(1, 1010), -(2, 2010), -(3, 3010), -(4, 4010), -(5, 5010), -(6, 6010), -(7, 7010), -(8, 8010), -(9, 9010); -UPDATE t1, t2 SET t1.y = t1.x + t1.y, t2.y = t2.x + t2.y WHERE t1.x > 7 AND t2.x < 7; -SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; +call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); x y 1 1000 2 2000 @@ -1173,7 +1169,6 @@ x y 9 9009 8 8000 9 9000 -SELECT x, y FROM t1; x y 1 1000 2 2000 @@ -1184,7 +1179,6 @@ x y 7 7000 8 8008 9 9009 -SELECT x, y FROM t2 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; x y 1 1011 2 2012 @@ -1201,7 +1195,6 @@ x y 4 4010 5 5010 6 6010 -SELECT x, y FROM t2; x y 1 1011 2 2012 @@ -1212,5 +1205,25 @@ x y 7 7010 8 8010 9 9010 -DROP TABLE t1; -DROP TABLE t2; +drop procedure test_01; +create procedure verify_vtq() +begin +set @i= 0; +select +@i:= @i + 1 as No, +trx_id > 0 as A, +begin_ts > '1-1-1 0:0:0' as B, +commit_ts > begin_ts as C, +concurr_trx is null as D +from information_schema.innodb_vtq +where trx_id > @start_trx_id; +select ifnull(max(trx_id), 0) +into @start_trx_id +from information_schema.innodb_vtq; +end~~ +call verify_vtq; +No A B C D +1 1 1 1 1 +2 1 1 1 1 +3 1 1 1 1 +drop procedure verify_vtq; diff --git a/mysql-test/r/update.result b/mysql-test/r/update.result index 2933bb3b3ce..6bce00b8257 100644 --- a/mysql-test/r/update.result +++ b/mysql-test/r/update.result @@ -723,8 +723,24 @@ drop table t1, t2; # System Versioning Support # # -CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; -INSERT INTO t1(x, y) VALUES +set @@session.time_zone='+00:00'; +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +create procedure test_01( +sys_type varchar(255), +engine varchar(255), +fields varchar(255)) +begin +set @str= concat(' + create table t1( + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); +prepare stmt from @str; execute stmt; drop prepare stmt; +insert into t1(x, y) values (1, 1000), (2, 2000), (3, 3000), @@ -734,7 +750,15 @@ INSERT INTO t1(x, y) VALUES (7, 7000), (8, 8000), (9, 9000); -SELECT x, y FROM t1; +select x, y from t1; +update t1 set y = y + 1 where x > 7; +select x, y from t1; +select x, y from t1 for system_time +between timestamp '0000-0-0 0:0:0' + and timestamp '2038-01-19 04:14:07'; +drop table t1; +end~~ +call test_01('timestamp(6)', 'myisam', 'sys_end'); x y 1 1000 2 2000 @@ -745,8 +769,6 @@ x y 7 7000 8 8000 9 9000 -UPDATE t1 SET y = y + 1 WHERE x > 7; -SELECT x, y FROM t1; x y 1 1000 2 2000 @@ -757,7 +779,6 @@ x y 7 7000 8 8001 9 9001 -SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; x y 1 1000 2 2000 @@ -770,20 +791,7 @@ x y 9 9001 8 8000 9 9000 -DROP TABLE t1; -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; -CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; -INSERT INTO t1(x, y) VALUES -(1, 1000), -(2, 2000), -(3, 3000), -(4, 4000), -(5, 5000), -(6, 6000), -(7, 7000), -(8, 8000), -(9, 9000); -SELECT x, y FROM t1; +call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); x y 1 1000 2 2000 @@ -794,8 +802,6 @@ x y 7 7000 8 8000 9 9000 -UPDATE t1 SET y = y + 1 WHERE x > 7; -SELECT x, y FROM t1; x y 1 1000 2 2000 @@ -806,7 +812,6 @@ x y 7 7000 8 8001 9 9001 -SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; x y 1 1000 2 2000 @@ -819,9 +824,24 @@ x y 9 9001 8 8000 9 9000 -DROP TABLE t1; -SET @i = 0; -SELECT @i:=@i+1 AS No, trx_id > 0 AS A, begin_ts > '2015-1-1 0:0:0' AS B, commit_ts > begin_ts AS C, concurr_trx IS NULL AS D FROM INFORMATION_SCHEMA.INNODB_VTQ WHERE trx_id > @start_trx_id; +drop procedure test_01; +create procedure verify_vtq() +begin +set @i= 0; +select +@i:= @i + 1 as No, +trx_id > 0 as A, +begin_ts > '1-1-1 0:0:0' as B, +commit_ts > begin_ts as C, +concurr_trx is null as D +from information_schema.innodb_vtq +where trx_id > @start_trx_id; +select ifnull(max(trx_id), 0) +into @start_trx_id +from information_schema.innodb_vtq; +end~~ +call verify_vtq; No A B C D 1 1 1 1 1 2 1 1 1 1 +drop procedure verify_vtq; diff --git a/mysql-test/t/delete.test b/mysql-test/t/delete.test index 1832067e75c..00e06f27243 100644 --- a/mysql-test/t/delete.test +++ b/mysql-test/t/delete.test @@ -587,83 +587,83 @@ DROP TABLE t1, t2; # SQL DELETE for SYSTEM VERSIONING # --echo # ---echo # Test for SYSTEM VERSIONING +--echo # System Versioning Support +--echo # --echo # - -SET @@session.time_zone='+00:00'; - -create table t1 ( - XNo INT UNSIGNED, - Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, - Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, - PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) -) WITH SYSTEM VERSIONING; - -INSERT INTO t1(XNo) VALUES(0); -INSERT INTO t1(XNo) VALUES(1); -INSERT INTO t1(XNo) VALUES(2); -INSERT INTO t1(XNo) VALUES(3); -INSERT INTO t1(XNo) VALUES(4); -INSERT INTO t1(XNo) VALUES(5); -INSERT INTO t1(XNo) VALUES(6); -INSERT INTO t1(XNo) VALUES(7); -INSERT INTO t1(XNo) VALUES(8); -INSERT INTO t1(XNo) VALUES(9); - -SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; -DELETE FROM t1 WHERE XNo = 0; -SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; -DELETE FROM t1 WHERE XNo = 1; -SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; -DELETE FROM t1 WHERE XNo > 5; - -CREATE VIEW vt1 AS SELECT XNo FROM t1; - -SELECT XNo FROM vt1; -DELETE FROM vt1 WHERE XNo = 3; -SELECT XNo FROM vt1; -SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; - -DROP VIEW vt1; -DROP TABLE t1; -- source include/have_innodb.inc - +set @@session.time_zone='+00:00'; select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; -create table t1 ( - XNo INT UNSIGNED, - Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, - Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, - PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) -) WITH SYSTEM VERSIONING ENGINE InnoDB; - -INSERT INTO t1(XNo) VALUES(0); -INSERT INTO t1(XNo) VALUES(1); -INSERT INTO t1(XNo) VALUES(2); -INSERT INTO t1(XNo) VALUES(3); -INSERT INTO t1(XNo) VALUES(4); -INSERT INTO t1(XNo) VALUES(5); -INSERT INTO t1(XNo) VALUES(6); -INSERT INTO t1(XNo) VALUES(7); -INSERT INTO t1(XNo) VALUES(8); -INSERT INTO t1(XNo) VALUES(9); - -SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; -DELETE FROM t1 WHERE XNo = 0; -SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; -DELETE FROM t1 WHERE XNo = 1; -SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; -DELETE FROM t1 WHERE XNo > 5; - -CREATE VIEW vt1 AS SELECT XNo FROM t1; - -SELECT XNo FROM vt1; -DELETE FROM vt1 WHERE XNo = 3; -SELECT XNo FROM vt1; -SELECT XNo, Sys_end < '2038-01-19 03:14:07' FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; - -DROP VIEW vt1; -DROP TABLE t1; - -SET @i = 0; SELECT @i:=@i+1 AS No, trx_id > 0 AS A, begin_ts > '2015-1-1 0:0:0' AS B, commit_ts > begin_ts AS C, concurr_trx IS NULL AS D FROM INFORMATION_SCHEMA.INNODB_VTQ WHERE trx_id > @start_trx_id; +delimiter ~~; +create procedure test_01( + sys_type varchar(255), + engine varchar(255), + fields varchar(255)) +begin + set @str= concat(' + create table t1( + XNo int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); + prepare stmt from @str; execute stmt; drop prepare stmt; + insert into t1(XNo) values(0); + insert into t1(XNo) values(1); + insert into t1(XNo) values(2); + insert into t1(XNo) values(3); + insert into t1(XNo) values(4); + insert into t1(XNo) values(5); + insert into t1(XNo) values(6); + insert into t1(XNo) values(7); + insert into t1(XNo) values(8); + insert into t1(XNo) values(9); + set @str= concat('select XNo, ', + fields, " < '2038-01-19 03:14:07' + from t1 for system_time + between timestamp '0000-0-0 0:0:0' + and timestamp '2038-01-19 04:14:07'"); + prepare stmt from @str; execute stmt; + delete from t1 where XNo = 0; + execute stmt; + delete from t1 where XNo = 1; + execute stmt; + delete from t1 where XNo > 5; + create view vt1 as select XNo from t1; + select XNo from vt1; + delete from vt1 where XNo = 3; + select XNo from vt1; + execute stmt; drop prepare stmt; + drop view vt1; + drop table t1; +end~~ +delimiter ;~~ + +call test_01('timestamp(6)', 'myisam', 'sys_end'); +call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +drop procedure test_01; + +# VTQ test + +delimiter ~~; +create procedure verify_vtq() +begin + set @i= 0; + select + @i:= @i + 1 as No, + trx_id > 0 as A, + begin_ts > '1-1-1 0:0:0' as B, + commit_ts > begin_ts as C, + concurr_trx is null as D + from information_schema.innodb_vtq + where trx_id > @start_trx_id; + select ifnull(max(trx_id), 0) + into @start_trx_id + from information_schema.innodb_vtq; +end~~ +delimiter ;~~ + +call verify_vtq; +drop procedure verify_vtq; diff --git a/mysql-test/t/insert.test b/mysql-test/t/insert.test index f806d450bcd..aa7286ec372 100644 --- a/mysql-test/t/insert.test +++ b/mysql-test/t/insert.test @@ -580,92 +580,161 @@ DROP TABLE t1; --echo # -- source include/have_innodb.inc - -SET @@session.time_zone='+00:00'; - +set @@session.time_zone='+00:00'; select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; -CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; -INSERT INTO t1(x, y) VALUES(3, 4); -INSERT INTO t1(x, y) VALUES(2, 3); -INSERT INTO t1 VALUES(40, 33); -SELECT x, y, Sys_end FROM t1; -DROP TABLE t1; -CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; -INSERT INTO t1(x, y) VALUES(3, 4); -INSERT INTO t1(x, y) VALUES(2, 3); -INSERT INTO t1 VALUES(40, 33); -SELECT x, y, Sys_end FROM t1; -DROP TABLE t1; - -CREATE TABLE t1(id INT UNSIGNED NOT NULL AUTO_INCREMENT, x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end), PRIMARY KEY(id)) WITH SYSTEM VERSIONING; -INSERT INTO t1(x, y) VALUES(33, 44); -INSERT INTO t1(id, x, y) VALUES(20, 33, 44); -INSERT INTO t1 VALUES(40, 33, 44); -SELECT id, x, y, Sys_end FROM t1; -DROP TABLE t1; - -CREATE TABLE t1(id INT UNSIGNED NOT NULL AUTO_INCREMENT, x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end), PRIMARY KEY(id)) WITH SYSTEM VERSIONING ENGINE=InnoDB; -INSERT INTO t1(x, y) VALUES(33, 44); -INSERT INTO t1(id, x, y) VALUES(20, 33, 44); -INSERT INTO t1 VALUES(40, 33, 44); -SELECT id, x, y, Sys_end FROM t1; -DROP TABLE t1; - -CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; -CREATE VIEW vt1_1 AS SELECT x, y FROM t1; -CREATE VIEW vt1_2 AS SELECT x, y, Sys_end FROM t1; -INSERT INTO t1(x, y) VALUES(8001, 9001); ---error ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER -INSERT INTO t1(x, y, Sys_end) VALUES(8001, 9001, '2015-1-1 0:0:0'); -INSERT INTO vt1_1(x, y) VALUES(1001, 2001); -INSERT INTO vt1_1 VALUES(1002, 2002); -INSERT INTO vt1_2(x, y) VALUES(3001, 4001); ---error ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER -INSERT INTO vt1_2 VALUES(3002, 4002, '2015-1-1 0:0:0'); -SELECT x, y, Sys_end FROM t1; -SELECT x, y FROM vt1_1; -SELECT x, y, Sys_end FROM vt1_2; -DROP TABLE t1; -DROP VIEW vt1_1; -DROP VIEW vt1_2; - -CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; -CREATE VIEW vt1_1 AS SELECT x, y FROM t1; -CREATE VIEW vt1_2 AS SELECT x, y, Sys_end FROM t1; -INSERT INTO t1(x, y) VALUES(8001, 9001); ---error ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER -INSERT INTO t1(x, y, Sys_end) VALUES(8001, 9001, '2015-1-1 0:0:0'); -INSERT INTO vt1_1(x, y) VALUES(1001, 2001); -INSERT INTO vt1_1 VALUES(1002, 2002); -INSERT INTO vt1_2(x, y) VALUES(3001, 4001); ---error ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER -INSERT INTO vt1_2 VALUES(3002, 4002, '2015-1-1 0:0:0'); -SELECT x, y, Sys_end FROM t1; -SELECT x, y FROM vt1_1; -SELECT x, y, Sys_end FROM vt1_2; -DROP TABLE t1; -DROP VIEW vt1_1; -DROP VIEW vt1_2; - -SET @i = 0; SELECT @i:=@i+1 AS No, trx_id > 0 AS A, begin_ts > '2015-1-1 0:0:0' AS B, commit_ts > begin_ts AS C, concurr_trx IS NULL AS D FROM INFORMATION_SCHEMA.INNODB_VTQ WHERE trx_id > @start_trx_id; - -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; -CREATE TABLE t1(x INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; -CREATE TABLE t2(x INT UNSIGNED) ENGINE=InnoDB; -START TRANSACTION; -INSERT INTO t1(x) VALUES(1); -COMMIT; +delimiter ~~; +create procedure test_01( + sys_type varchar(255), + engine varchar(255), + fields varchar(255)) +begin + set @str= concat(' + create table t1( + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); + prepare stmt from @str; execute stmt; drop prepare stmt; + insert into t1(x, y) values(3, 4); + insert into t1(x, y) values(2, 3); + insert into t1 values(40, 33); + set @str= concat('select x, y, ', fields, ' from t1'); + prepare stmt from @str; execute stmt; drop prepare stmt; + drop table t1; +end~~ +delimiter ;~~ + +call test_01('timestamp(6)', 'myisam', 'sys_end'); +call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +drop procedure test_01; + +delimiter ~~; +create procedure test_02( + sys_type varchar(255), + engine varchar(255), + fields varchar(255)) +begin + set @str= concat(' + create table t1( + id int unsigned auto_increment primary key, + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); + prepare stmt from @str; execute stmt; drop prepare stmt; + insert into t1(x, y) values(33, 44); + insert into t1(id, x, y) values(20, 33, 44); + insert into t1 values(40, 33, 44); + set @str= concat('select id, x, y, ', fields, ' from t1'); + prepare stmt from @str; execute stmt; drop prepare stmt; + drop table t1; +end~~ +delimiter ;~~ + +call test_02('timestamp(6)', 'myisam', 'sys_end'); +call test_02('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +drop procedure test_02; + +delimiter ~~; +create procedure test_03( + sys_type varchar(255), + engine varchar(255), + fields varchar(255)) +begin + set @str= concat(' + create table t1( + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); + prepare stmt from @str; execute stmt; drop prepare stmt; + create view vt1_1 as select x, y from t1; + create view vt1_2 as select x, y, sys_end from t1; + insert into t1(x, y) values(8001, 9001); + insert into vt1_1(x, y) values(1001, 2001); + insert into vt1_1 values(1002, 2002); + insert into vt1_2(x, y) values(3001, 4001); + set @str= concat('select x, y, ', fields, ' from t1'); + prepare stmt from @str; execute stmt; drop prepare stmt; + select x, y from vt1_1; + set @str= concat('select x, y, ', fields, ' from vt1_2'); + prepare stmt from @str; execute stmt; drop prepare stmt; +end~~ +delimiter ;~~ + +call test_03('timestamp(6)', 'myisam', 'sys_end'); +--ERROR ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER +insert into t1(x, y, sys_end) values(8001, 9001, '2015-1-1 1:1:1'); +--ERROR ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER +insert into vt1_2 values(3002, 4002, '2015-2-2 2:2:2'); +drop table t1; +drop view vt1_1; +drop view vt1_2; + +call test_03('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +--ERROR ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER +insert into t1(x, y, sys_end) values(8001, 9001, 1111111); +--ERROR ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER +insert into vt1_2 values(3002, 4002, 2222222); +drop table t1; +drop view vt1_1; +drop view vt1_2; +drop procedure test_03; + +# VTQ test + +delimiter ~~; +create procedure verify_vtq() +begin + set @i= 0; + select + @i:= @i + 1 as No, + trx_id > 0 as A, + begin_ts > '1-1-1 0:0:0' as B, + commit_ts > begin_ts as C, + concurr_trx is null as D + from information_schema.innodb_vtq + where trx_id > @start_trx_id; + select ifnull(max(trx_id), 0) + into @start_trx_id + from information_schema.innodb_vtq; +end~~ +delimiter ;~~ + +call verify_vtq; + +create table t1( + x int unsigned, + sys_start bigint unsigned generated always as row start, + sys_end bigint unsigned generated always as row end, + period for system_time (sys_start, sys_end)) +with system versioning engine=innodb; + +create table t2(x int unsigned) engine=innodb; + +start transaction; +insert into t1(x) values(1); +commit; +call verify_vtq; -SET @i = 0; SELECT @i:=@i+1 AS No, trx_id > 0 AS A, begin_ts > '2015-1-1 0:0:0' AS B, commit_ts > begin_ts AS C, concurr_trx IS NULL AS D FROM INFORMATION_SCHEMA.INNODB_VTQ WHERE trx_id > @start_trx_id; +start transaction; +insert into t2(x) values(1); +savepoint a; +insert into t1(x) values(1); +rollback to a; +commit; +call verify_vtq; -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; -START TRANSACTION; -INSERT INTO t2(x) VALUES(1); -SAVEPOINT a; -INSERT INTO t1(x) VALUES(1); -ROLLBACK TO a; -COMMIT; -SET @i = 0; SELECT @i:=@i+1 AS No, trx_id > 0 AS A, begin_ts > '2015-1-1 0:0:0' AS B, commit_ts > begin_ts AS C, concurr_trx IS NULL AS D FROM INFORMATION_SCHEMA.INNODB_VTQ WHERE trx_id > @start_trx_id; -DROP TABLE t1; -DROP TABLE t2; +drop table t1; +drop table t2; +drop procedure verify_vtq; \ No newline at end of file diff --git a/mysql-test/t/insert_select.opt b/mysql-test/t/insert_select.opt new file mode 100644 index 00000000000..32a25eea24f --- /dev/null +++ b/mysql-test/t/insert_select.opt @@ -0,0 +1 @@ +--loose-innodb-vtq diff --git a/mysql-test/t/insert_select.test b/mysql-test/t/insert_select.test index 11dca894117..d2826fceec8 100644 --- a/mysql-test/t/insert_select.test +++ b/mysql-test/t/insert_select.test @@ -432,61 +432,79 @@ DROP TABLE t1; --echo # -- source include/have_innodb.inc - -CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=MyISAM; -CREATE TABLE t2(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=MyISAM; -INSERT INTO t1(x, y) VALUES - (1, 1000), - (2, 2000), - (3, 3000), - (4, 4000), - (5, 5000), - (6, 6000), - (7, 7000), - (8, 8000), - (9, 9000); -DELETE FROM t1 WHERE x >= 1; -INSERT INTO t1(x, y) VALUES - (1, 1001), - (2, 2001), - (3, 3001), - (4, 4001), - (5, 5001), - (6, 6001), - (7, 7001), - (8, 8001), - (9, 9001); -INSERT INTO t2 SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; -SELECT x, y FROM t1; -SELECT x, y FROM t2; -DROP TABLE t1; -DROP TABLE t2; - -CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; -CREATE TABLE t2(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; -INSERT INTO t1(x, y) VALUES - (1, 1000), - (2, 2000), - (3, 3000), - (4, 4000), - (5, 5000), - (6, 6000), - (7, 7000), - (8, 8000), - (9, 9000); -DELETE FROM t1 WHERE x >= 1; -INSERT INTO t1(x, y) VALUES - (1, 1001), - (2, 2001), - (3, 3001), - (4, 4001), - (5, 5001), - (6, 6001), - (7, 7001), - (8, 8001), - (9, 9001); -INSERT INTO t2 SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; -SELECT x, y FROM t1; -SELECT x, y FROM t2; -DROP TABLE t1; -DROP TABLE t2; +set @@session.time_zone='+00:00'; +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; + +delimiter ~~; +create procedure test_01( + sys_type varchar(255), + engine varchar(255), + fields varchar(255)) +begin + set @str= concat('( + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); + set @str2= concat('create table t1', @str); + prepare stmt from @str2; execute stmt; drop prepare stmt; + set @str2= concat('create table t2', @str); + prepare stmt from @str2; execute stmt; drop prepare stmt; + insert into t1(x, y) values + (1, 1000), + (2, 2000), + (3, 3000), + (4, 4000), + (5, 5000), + (6, 6000), + (7, 7000), + (8, 8000), + (9, 9000); + delete from t1 where x >= 1; + insert into t1(x, y) values + (1, 1001), + (2, 2001), + (3, 3001), + (4, 4001), + (5, 5001), + (6, 6001), + (7, 7001), + (8, 8001), + (9, 9001); + insert into t2 select x, y from t1 for system_time between timestamp '0000-0-0 0:0:0' and timestamp '9999-1-1 0:0:0'; + select x, y from t1; + select x, y from t2; + drop table t1; + drop table t2; +end~~ +delimiter ;~~ + +call test_01('timestamp(6)', 'myisam', 'sys_end'); +call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +drop procedure test_01; + +# VTQ test + +delimiter ~~; +create procedure verify_vtq() +begin + set @i= 0; + select + @i:= @i + 1 as No, + trx_id > 0 as A, + begin_ts > '1-1-1 0:0:0' as B, + commit_ts > begin_ts as C, + concurr_trx is null as D + from information_schema.innodb_vtq + where trx_id > @start_trx_id; + select ifnull(max(trx_id), 0) + into @start_trx_id + from information_schema.innodb_vtq; +end~~ +delimiter ;~~ + +call verify_vtq; +drop procedure verify_vtq; diff --git a/mysql-test/t/insert_update.opt b/mysql-test/t/insert_update.opt new file mode 100644 index 00000000000..32a25eea24f --- /dev/null +++ b/mysql-test/t/insert_update.opt @@ -0,0 +1 @@ +--loose-innodb-vtq diff --git a/mysql-test/t/insert_update.test b/mysql-test/t/insert_update.test index 518fea8d2a1..f2b571fba7e 100644 --- a/mysql-test/t/insert_update.test +++ b/mysql-test/t/insert_update.test @@ -318,41 +318,69 @@ drop table t1; --echo # -- source include/have_innodb.inc - -CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end), PRIMARY KEY(x, y)) WITH SYSTEM VERSIONING; -INSERT INTO t1(x, y) VALUES - (1, 1000), - (2, 2000), - (3, 3000), - (4, 4000), - (5, 5000), - (6, 6000), - (7, 7000), - (8, 8000), - (9, 9000); -INSERT INTO t1(x, y) VALUES(3, 3000) ON DUPLICATE KEY UPDATE y = y+1; -INSERT INTO t1(x, y) VALUES(4, 4000) ON DUPLICATE KEY UPDATE y = y+1; -INSERT INTO t1(x, y) VALUES(4, 4001) ON DUPLICATE KEY UPDATE y = y+1; -INSERT INTO t1(x, y) VALUES(4, 4444) ON DUPLICATE KEY UPDATE y = y+1; -SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; -SELECT x, y FROM t1; -DROP TABLE t1; - -CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end), PRIMARY KEY(x, y)) WITH SYSTEM VERSIONING ENGINE=InnoDB; -INSERT INTO t1(x, y) VALUES - (1, 1000), - (2, 2000), - (3, 3000), - (4, 4000), - (5, 5000), - (6, 6000), - (7, 7000), - (8, 8000), - (9, 9000); -INSERT INTO t1(x, y) VALUES(3, 3000) ON DUPLICATE KEY UPDATE y = y+1; -INSERT INTO t1(x, y) VALUES(4, 4000) ON DUPLICATE KEY UPDATE y = y+1; -INSERT INTO t1(x, y) VALUES(4, 4001) ON DUPLICATE KEY UPDATE y = y+1; -INSERT INTO t1(x, y) VALUES(4, 4444) ON DUPLICATE KEY UPDATE y = y+1; -SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; -SELECT x, y FROM t1; -DROP TABLE t1; +set @@session.time_zone='+00:00'; +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; + +delimiter ~~; +create procedure test_01( + sys_type varchar(255), + engine varchar(255), + fields varchar(255)) +begin + set @str= concat(' + create table t1( + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end), + primary key(x, y)) + with system versioning + engine ', engine); + prepare stmt from @str; execute stmt; drop prepare stmt; + insert into t1(x, y) values + (1, 1000), + (2, 2000), + (3, 3000), + (4, 4000), + (5, 5000), + (6, 6000), + (7, 7000), + (8, 8000), + (9, 9000); + insert into t1(x, y) values(3, 3000) on duplicate key update y = y+1; + insert into t1(x, y) values(4, 4000) on duplicate key update y = y+1; + insert into t1(x, y) values(4, 4001) on duplicate key update y = y+1; + insert into t1(x, y) values(4, 4444) on duplicate key update y = y+1; + select x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp '9999-1-1 0:0:0'; + select x, y from t1; + drop table t1; +end~~ +delimiter ;~~ + +call test_01('timestamp(6)', 'myisam', 'sys_end'); +call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +drop procedure test_01; + +# VTQ test + +delimiter ~~; +create procedure verify_vtq() +begin + set @i= 0; + select + @i:= @i + 1 as No, + trx_id > 0 as A, + begin_ts > '1-1-1 0:0:0' as B, + commit_ts > begin_ts as C, + concurr_trx is null as D + from information_schema.innodb_vtq + where trx_id > @start_trx_id; + select ifnull(max(trx_id), 0) + into @start_trx_id + from information_schema.innodb_vtq; +end~~ +delimiter ;~~ + +call verify_vtq; +drop procedure verify_vtq; diff --git a/mysql-test/t/multi_update.opt b/mysql-test/t/multi_update.opt new file mode 100644 index 00000000000..32a25eea24f --- /dev/null +++ b/mysql-test/t/multi_update.opt @@ -0,0 +1 @@ +--loose-innodb-vtq diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test index a5a9ca4943e..325d65e5872 100644 --- a/mysql-test/t/multi_update.test +++ b/mysql-test/t/multi_update.test @@ -1041,62 +1041,81 @@ SET SESSION SQL_MODE=default; --echo # --echo # -CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; -CREATE TABLE t2(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; -INSERT INTO t1(x, y) VALUES - (1, 1000), - (2, 2000), - (3, 3000), - (4, 4000), - (5, 5000), - (6, 6000), - (7, 7000), - (8, 8000), - (9, 9000); -INSERT INTO t2(x, y) VALUES - (1, 1010), - (2, 2010), - (3, 3010), - (4, 4010), - (5, 5010), - (6, 6010), - (7, 7010), - (8, 8010), - (9, 9010); -UPDATE t1, t2 SET t1.y = t1.x + t1.y, t2.y = t2.x + t2.y WHERE t1.x > 7 AND t2.x < 7; -SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; -SELECT x, y FROM t1; -SELECT x, y FROM t2 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; -SELECT x, y FROM t2; -DROP TABLE t1; -DROP TABLE t2; - -CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; -CREATE TABLE t2(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; -INSERT INTO t1(x, y) VALUES - (1, 1000), - (2, 2000), - (3, 3000), - (4, 4000), - (5, 5000), - (6, 6000), - (7, 7000), - (8, 8000), - (9, 9000); -INSERT INTO t2(x, y) VALUES - (1, 1010), - (2, 2010), - (3, 3010), - (4, 4010), - (5, 5010), - (6, 6010), - (7, 7010), - (8, 8010), - (9, 9010); -UPDATE t1, t2 SET t1.y = t1.x + t1.y, t2.y = t2.x + t2.y WHERE t1.x > 7 AND t2.x < 7; -SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; -SELECT x, y FROM t1; -SELECT x, y FROM t2 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '9999-1-1 0:0:0'; -SELECT x, y FROM t2; -DROP TABLE t1; -DROP TABLE t2; +-- source include/have_innodb.inc +set @@session.time_zone='+00:00'; +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; + +delimiter ~~; +create procedure test_01( + sys_type varchar(255), + engine varchar(255), + fields varchar(255)) +begin + set @str= concat('( + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); + set @str2= concat('create table t1', @str); + prepare stmt from @str2; execute stmt; drop prepare stmt; + set @str2= concat('create table t2', @str); + prepare stmt from @str2; execute stmt; drop prepare stmt; + insert into t1(x, y) values + (1, 1000), + (2, 2000), + (3, 3000), + (4, 4000), + (5, 5000), + (6, 6000), + (7, 7000), + (8, 8000), + (9, 9000); + insert into t2(x, y) values + (1, 1010), + (2, 2010), + (3, 3010), + (4, 4010), + (5, 5010), + (6, 6010), + (7, 7010), + (8, 8010), + (9, 9010); + update t1, t2 set t1.y = t1.x + t1.y, t2.y = t2.x + t2.y where t1.x > 7 and t2.x < 7; + select x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp '9999-1-1 0:0:0'; + select x, y from t1; + select x, y from t2 for system_time between timestamp '0-0-0 0:0:0' and timestamp '9999-1-1 0:0:0'; + select x, y from t2; + drop table t1; + drop table t2; +end~~ +delimiter ;~~ + +call test_01('timestamp(6)', 'myisam', 'sys_end'); +call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +drop procedure test_01; + +# VTQ test + +delimiter ~~; +create procedure verify_vtq() +begin + set @i= 0; + select + @i:= @i + 1 as No, + trx_id > 0 as A, + begin_ts > '1-1-1 0:0:0' as B, + commit_ts > begin_ts as C, + concurr_trx is null as D + from information_schema.innodb_vtq + where trx_id > @start_trx_id; + select ifnull(max(trx_id), 0) + into @start_trx_id + from information_schema.innodb_vtq; +end~~ +delimiter ;~~ + +call verify_vtq; +drop procedure verify_vtq; diff --git a/mysql-test/t/update.test b/mysql-test/t/update.test index a1e96c88a6b..784c563fbf2 100644 --- a/mysql-test/t/update.test +++ b/mysql-test/t/update.test @@ -660,41 +660,69 @@ drop table t1, t2; --echo # --echo # -CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; -INSERT INTO t1(x, y) VALUES - (1, 1000), - (2, 2000), - (3, 3000), - (4, 4000), - (5, 5000), - (6, 6000), - (7, 7000), - (8, 8000), - (9, 9000); -SELECT x, y FROM t1; -UPDATE t1 SET y = y + 1 WHERE x > 7; -SELECT x, y FROM t1; -SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; -DROP TABLE t1; - -- source include/have_innodb.inc - +set @@session.time_zone='+00:00'; select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; -CREATE TABLE t1(x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING ENGINE=InnoDB; -INSERT INTO t1(x, y) VALUES - (1, 1000), - (2, 2000), - (3, 3000), - (4, 4000), - (5, 5000), - (6, 6000), - (7, 7000), - (8, 8000), - (9, 9000); -SELECT x, y FROM t1; -UPDATE t1 SET y = y + 1 WHERE x > 7; -SELECT x, y FROM t1; -SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0000-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; -DROP TABLE t1; -SET @i = 0; SELECT @i:=@i+1 AS No, trx_id > 0 AS A, begin_ts > '2015-1-1 0:0:0' AS B, commit_ts > begin_ts AS C, concurr_trx IS NULL AS D FROM INFORMATION_SCHEMA.INNODB_VTQ WHERE trx_id > @start_trx_id; +delimiter ~~; +create procedure test_01( + sys_type varchar(255), + engine varchar(255), + fields varchar(255)) +begin + set @str= concat(' + create table t1( + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); + prepare stmt from @str; execute stmt; drop prepare stmt; + insert into t1(x, y) values + (1, 1000), + (2, 2000), + (3, 3000), + (4, 4000), + (5, 5000), + (6, 6000), + (7, 7000), + (8, 8000), + (9, 9000); + select x, y from t1; + update t1 set y = y + 1 where x > 7; + select x, y from t1; + select x, y from t1 for system_time + between timestamp '0000-0-0 0:0:0' + and timestamp '2038-01-19 04:14:07'; + drop table t1; +end~~ +delimiter ;~~ + +call test_01('timestamp(6)', 'myisam', 'sys_end'); +call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +drop procedure test_01; + +# VTQ test + +delimiter ~~; +create procedure verify_vtq() +begin + set @i= 0; + select + @i:= @i + 1 as No, + trx_id > 0 as A, + begin_ts > '1-1-1 0:0:0' as B, + commit_ts > begin_ts as C, + concurr_trx is null as D + from information_schema.innodb_vtq + where trx_id > @start_trx_id; + select ifnull(max(trx_id), 0) + into @start_trx_id + from information_schema.innodb_vtq; +end~~ +delimiter ;~~ + +call verify_vtq; +drop procedure verify_vtq; -- cgit v1.2.1 From 5c4473dc747039b97e121289db0e5fabb9ef899d Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 12 Oct 2016 15:01:42 +0000 Subject: IB: misc fix --- storage/innobase/row/row0ins.cc | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 3e2f0683d18..12a41d97a41 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -3861,21 +3861,18 @@ vers_row_ins_vtq_low(trx_t* trx, mem_heap_t* heap, dtuple_t* row) mem_heap_t* offsets_heap = mem_heap_create(1024); do { - n_index++; - if (!(index = dict_table_get_next_index(index))) { break; } - if (index->type & DICT_FTS) { - continue; - } + n_index++; entry = row_build_index_entry(row, NULL, index, heap); err = row_ins_sec_index_entry_low( flags, BTR_MODIFY_TREE, index, offsets_heap, heap, entry, trx->id, NULL, false, trx); } while (err == DB_SUCCESS); + ut_ad(n_index == 2 || err != DB_SUCCESS); mem_heap_free(offsets_heap); return err; -- cgit v1.2.1 From 2db17e662437268e09913a310ab0ec369df73e15 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Thu, 13 Oct 2016 13:30:22 +0000 Subject: Parser: versioned JOIN fix Moved opt_for_system_time_clause from table identifier (which binds it to single table) to table expression. --- sql/sql_lex.cc | 1 + sql/sql_lex.h | 3 +++ sql/sql_select.cc | 42 +++++++++++++++++++----------------------- sql/sql_yacc.yy | 18 +++++++----------- sql/table.h | 26 ++++++++++++++++---------- 5 files changed, 46 insertions(+), 44 deletions(-) diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index a45fc044f55..34b35d60c14 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2278,6 +2278,7 @@ void st_select_lex::init_select() with_dep= 0; join= 0; lock_type= TL_READ_DEFAULT; + vers_conditions.empty(); } /* diff --git a/sql/sql_lex.h b/sql/sql_lex.h index d3665844a69..64e0c9ddaa9 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -991,6 +991,9 @@ public: /* it is for correct printing SELECT options */ thr_lock_type lock_type; + /* System Versioning conditions */ + vers_select_conds_t vers_conditions; + void init_query(); void init_select(); st_select_lex_unit* master_unit() { return (st_select_lex_unit*) master; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 207ce5c0139..331421ecb6d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -688,11 +688,6 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **conds, SELECT_LEX *se { if (table->table && table->table->versioned()) versioned_tables++; - else if (table->system_versioning.type != FOR_SYSTEM_TIME_UNSPECIFIED) - { - my_error(ER_TABLE_DOESNT_SUPPORT_SYSTEM_VERSIONING, MYF(0), table->table_name); - DBUG_RETURN(-1); - } } if (versioned_tables == 0) @@ -746,7 +741,7 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **conds, SELECT_LEX *se } Item *cond1= 0, *cond2= 0, *curr= 0; - switch (table->system_versioning.type) + switch (select_lex->vers_conditions.type) { case FOR_SYSTEM_TIME_UNSPECIFIED: if (table->table->versioned_by_sql()) @@ -764,21 +759,21 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **conds, SELECT_LEX *se break; case FOR_SYSTEM_TIME_AS_OF: cond1= new (thd->mem_root) Item_func_le(thd, row_start, - table->system_versioning.start); + select_lex->vers_conditions.start); cond2= new (thd->mem_root) Item_func_gt(thd, row_end, - table->system_versioning.start); + select_lex->vers_conditions.start); break; case FOR_SYSTEM_TIME_FROM_TO: cond1= new (thd->mem_root) Item_func_lt(thd, row_start, - table->system_versioning.end); + select_lex->vers_conditions.end); cond2= new (thd->mem_root) Item_func_ge(thd, row_end, - table->system_versioning.start); + select_lex->vers_conditions.start); break; case FOR_SYSTEM_TIME_BETWEEN: cond1= new (thd->mem_root) Item_func_le(thd, row_start, - table->system_versioning.end); + select_lex->vers_conditions.end); cond2= new (thd->mem_root) Item_func_ge(thd, row_end, - table->system_versioning.start); + select_lex->vers_conditions.start); break; default: DBUG_ASSERT(0); @@ -797,10 +792,10 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **conds, SELECT_LEX *se else thd->change_item_tree(conds, cond1); - table->system_versioning.is_moved_to_where= true; + table->vers_moved_to_where= true; } - } - } + } // if (... table->table->versioned()) + } // for (table= tables; ...) if (arena) { @@ -24935,29 +24930,30 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result) void TABLE_LIST::print_system_versioning(THD *thd, table_map eliminated_tables, String *str, enum_query_type query_type) { - if (system_versioning.is_moved_to_where) + if (vers_moved_to_where) return; + DBUG_ASSERT(select_lex); // system versioning - if (system_versioning.type != FOR_SYSTEM_TIME_UNSPECIFIED) + if (select_lex->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED) { - switch (system_versioning.type) + switch (select_lex->vers_conditions.type) { case FOR_SYSTEM_TIME_AS_OF: str->append(STRING_WITH_LEN(" for system_time as of ")); - system_versioning.start->print(str, query_type); + select_lex->vers_conditions.start->print(str, query_type); break; case FOR_SYSTEM_TIME_FROM_TO: str->append(STRING_WITH_LEN(" for system_time from timestamp ")); - system_versioning.start->print(str, query_type); + select_lex->vers_conditions.start->print(str, query_type); str->append(STRING_WITH_LEN(" to ")); - system_versioning.end->print(str, query_type); + select_lex->vers_conditions.end->print(str, query_type); break; case FOR_SYSTEM_TIME_BETWEEN: str->append(STRING_WITH_LEN(" for system_time between timestamp ")); - system_versioning.start->print(str, query_type); + select_lex->vers_conditions.start->print(str, query_type); str->append(STRING_WITH_LEN(" and ")); - system_versioning.end->print(str, query_type); + select_lex->vers_conditions.end->print(str, query_type); break; default: DBUG_ASSERT(0); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index f681ed25596..05c05c3e144 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -758,7 +758,6 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr) uint sp_instr_addr; /* structs */ - system_versioning_for_select system_versioning; LEX_STRING lex_str; LEX_SYMBOL symbol; Lex_string_with_metadata_st lex_string_with_metadata; @@ -1954,7 +1953,6 @@ END_OF_INPUT %type window_frame_extent; %type opt_window_frame_exclusion; %type window_frame_start window_frame_bound; -%type opt_for_system_time_clause; %type '-' '+' '*' '/' '%' '(' ')' @@ -8628,6 +8626,7 @@ table_expression: opt_group_clause opt_having_clause opt_window_clause + opt_for_system_time_clause ; opt_table_expression: @@ -8664,14 +8663,12 @@ select_options: opt_for_system_time_clause: /* empty */ - { - $$.init(); - } + {} | FOR_SYSTEM_TIME_SYM AS OF_SYM TIMESTAMP simple_expr { - $$.init(FOR_SYSTEM_TIME_AS_OF, $5); + Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_AS_OF, $5); } | FOR_SYSTEM_TIME_SYM AS OF_SYM @@ -8680,7 +8677,7 @@ opt_for_system_time_clause: Item *item= new (thd->mem_root) Item_func_now_local(thd, 6); if (item == NULL) MYSQL_YYABORT; - $$.init(FOR_SYSTEM_TIME_AS_OF, item); + Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_AS_OF, item); } | FOR_SYSTEM_TIME_SYM FROM @@ -8688,7 +8685,7 @@ opt_for_system_time_clause: TO_SYM TIMESTAMP simple_expr { - $$.init(FOR_SYSTEM_TIME_FROM_TO, $4, $7); + Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_FROM_TO, $4, $7); } | FOR_SYSTEM_TIME_SYM BETWEEN_SYM @@ -8696,7 +8693,7 @@ opt_for_system_time_clause: AND_SYM TIMESTAMP simple_expr { - $$.init(FOR_SYSTEM_TIME_BETWEEN, $4, $7); + Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_BETWEEN, $4, $7); } ; @@ -11107,7 +11104,7 @@ table_primary_ident: SELECT_LEX *sel= Select; sel->table_join_options= 0; } - table_ident opt_use_partition opt_table_alias opt_key_definition opt_for_system_time_clause + table_ident opt_use_partition opt_table_alias opt_key_definition { if (!($$= Select->add_table_to_list(thd, $2, $4, Select->get_table_join_options(), @@ -11117,7 +11114,6 @@ table_primary_ident: $3))) MYSQL_YYABORT; Select->add_joined_table($$); - $$->system_versioning= $6; } ; diff --git a/sql/table.h b/sql/table.h index ad62c06838b..cc575602c49 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1814,26 +1814,32 @@ class Item_in_subselect; enum for_system_time_type { - FOR_SYSTEM_TIME_UNSPECIFIED, FOR_SYSTEM_TIME_AS_OF, - FOR_SYSTEM_TIME_FROM_TO, FOR_SYSTEM_TIME_BETWEEN + FOR_SYSTEM_TIME_UNSPECIFIED = 0, + FOR_SYSTEM_TIME_AS_OF, + FOR_SYSTEM_TIME_FROM_TO, + FOR_SYSTEM_TIME_BETWEEN }; /** System versioning support. */ -struct system_versioning_for_select +struct vers_select_conds_t { enum for_system_time_type type; Item *start, *end; - bool is_moved_to_where; + + void empty() + { + type= FOR_SYSTEM_TIME_UNSPECIFIED; + start= end= NULL; + } void init( - const enum for_system_time_type t=FOR_SYSTEM_TIME_UNSPECIFIED, - Item * const s=NULL, - Item * const e=NULL) + const enum for_system_time_type t, + Item * const s, + Item * const e= NULL) { type= t; start= s; end= e; - is_moved_to_where= false; } }; @@ -2293,8 +2299,8 @@ struct TABLE_LIST TABLE_LIST *first_leaf_for_name_resolution(); TABLE_LIST *last_leaf_for_name_resolution(); - /** System versioning support. */ - system_versioning_for_select system_versioning; + /* System Versioning */ + bool vers_moved_to_where; /** @brief -- cgit v1.2.1 From a9a56b235543fd34ba57c27624aa269c0a13df9d Mon Sep 17 00:00:00 2001 From: Kosov Eugene Date: Sun, 2 Oct 2016 12:35:50 +0300 Subject: SQL: 0.3 per column versioning syntax, .frm, optimized updates and tests --- mysql-test/r/create.result | 83 ++++++++++++++++++++++++++ mysql-test/r/multi_update.result | 32 ++++++++++ mysql-test/r/update.result | 17 ++++++ mysql-test/t/create.test | 51 ++++++++++++++++ mysql-test/t/multi_update.test | 29 +++++++++ mysql-test/t/update.test | 18 ++++++ sql/field.h | 14 ++++- sql/handler.cc | 123 ++++++++++++++++++++++++++++++++++++++- sql/handler.h | 33 +++++++++-- sql/lex.h | 1 + sql/share/errmsg-utf8.txt | 3 + sql/sql_class.h | 2 + sql/sql_parse.cc | 67 +-------------------- sql/sql_show.cc | 5 ++ sql/sql_table.cc | 2 + sql/sql_update.cc | 25 ++++++-- sql/sql_yacc.yy | 15 ++++- sql/table.cc | 3 + 18 files changed, 440 insertions(+), 83 deletions(-) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index e445842192f..b0255c7457b 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -2033,3 +2033,86 @@ Sys_end INT GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) ) WITH SYSTEM VERSIONING; ERROR HY000: System end field must be of type TIMESTAMP +CREATE TABLE t1 ( +A INT WITH SYSTEM VERSIONING, +B INT +); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `A` int(11) DEFAULT NULL, + `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, + `sys_trx_start` timestamp(6) NULL GENERATED AS ROW START, + `sys_trx_end` timestamp(6) NULL GENERATED AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +DROP TABLE t1; +CREATE TABLE t1 ( +A INT WITH SYSTEM VERSIONING, +B INT +) WITH SYSTEM VERSIONING; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `A` int(11) DEFAULT NULL, + `B` int(11) DEFAULT NULL, + `sys_trx_start` timestamp(6) NULL GENERATED AS ROW START, + `sys_trx_end` timestamp(6) NULL GENERATED AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +DROP TABLE t1; +CREATE TABLE t1 ( +A INT, +B INT WITHOUT SYSTEM VERSIONING +); +ERROR HY000: Every field specified unversioned in versioned table +CREATE TABLE t1 ( +A INT, +B INT WITHOUT SYSTEM VERSIONING +) WITH SYSTEM VERSIONING; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `A` int(11) DEFAULT NULL, + `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, + `sys_trx_start` timestamp(6) NULL GENERATED AS ROW START, + `sys_trx_end` timestamp(6) NULL GENERATED AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +DROP TABLE t1; +CREATE TABLE t1 ( +A INT WITH SYSTEM VERSIONING, +B INT WITHOUT SYSTEM VERSIONING +); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `A` int(11) DEFAULT NULL, + `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, + `sys_trx_start` timestamp(6) NULL GENERATED AS ROW START, + `sys_trx_end` timestamp(6) NULL GENERATED AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +DROP TABLE t1; +CREATE TABLE t1 ( +A INT WITH SYSTEM VERSIONING, +B INT WITHOUT SYSTEM VERSIONING +) WITH SYSTEM VERSIONING; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `A` int(11) DEFAULT NULL, + `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, + `sys_trx_start` timestamp(6) NULL GENERATED AS ROW START, + `sys_trx_end` timestamp(6) NULL GENERATED AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +DROP TABLE t1; +CREATE TABLE t1 ( +A INT WITHOUT SYSTEM VERSIONING +); +ERROR HY000: Every field specified unversioned in versioned table +CREATE TABLE t1 ( +A INT WITHOUT SYSTEM VERSIONING +) WITH SYSTEM VERSIONING; +ERROR HY000: Every field specified unversioned in versioned table diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result index d244afa03e3..bb68029a490 100644 --- a/mysql-test/r/multi_update.result +++ b/mysql-test/r/multi_update.result @@ -1227,3 +1227,35 @@ No A B C D 2 1 1 1 1 3 1 1 1 1 drop procedure verify_vtq; +CREATE TABLE t1 ( +id BIGINT PRIMARY KEY, +name VARCHAR(128) WITH SYSTEM VERSIONING, +salary BIGINT +); +INSERT INTO t1 VALUES (1, "Jeremy", 3000); +CREATE TABLE t2 ( +id BIGINT PRIMARY KEY, +name VARCHAR(128) WITH SYSTEM VERSIONING, +salary BIGINT +); +INSERT INTO t2 VALUES (1, "Jeremy", 4000); +SELECT sys_trx_start INTO @tmp1 FROM t1; +SELECT sys_trx_start INTO @tmp2 FROM t2; +UPDATE t1, t2 SET t1.name="Jerry", t2.name="Jerry" WHERE t1.id=t2.id AND t1.name="Jeremy"; +SELECT @tmp1 < sys_trx_start, name FROM t1; +@tmp1 < sys_trx_start name +1 Jerry +SELECT @tmp2 < sys_trx_start, name FROM t2; +@tmp2 < sys_trx_start name +1 Jerry +SELECT sys_trx_start INTO @tmp1 FROM t1; +SELECT sys_trx_start INTO @tmp2 FROM t2; +UPDATE t1, t2 SET t1.salary=2500, t2.salary=2500 WHERE t1.id=t2.id AND t1.name="Jerry"; +SELECT @tmp1 = sys_trx_start, salary FROM t1; +@tmp1 = sys_trx_start salary +1 2500 +SELECT @tmp2 = sys_trx_start, salary FROM t2; +@tmp2 = sys_trx_start salary +1 2500 +DROP TABLE t1; +DROP TABLE t2; diff --git a/mysql-test/r/update.result b/mysql-test/r/update.result index 6bce00b8257..e0e58985adc 100644 --- a/mysql-test/r/update.result +++ b/mysql-test/r/update.result @@ -845,3 +845,20 @@ No A B C D 1 1 1 1 1 2 1 1 1 1 drop procedure verify_vtq; +CREATE TABLE t1 ( +id BIGINT PRIMARY KEY, +A INT, +B INT WITHOUT SYSTEM VERSIONING +) WITH SYSTEM VERSIONING; +INSERT INTO t1 VALUES(1, 1, 1); +SELECT sys_trx_start INTO @tmp1 FROM t1; +UPDATE t1 SET A=11, B=11 WHERE id=1; +SELECT @tmp1 < sys_trx_start, A, B FROM t1; +@tmp1 < sys_trx_start A B +1 11 11 +SELECT sys_trx_start INTO @tmp1 FROM t1; +UPDATE t1 SET B=1 WHERE id=1; +SELECT @tmp1 = sys_trx_start, B FROM t1; +@tmp1 = sys_trx_start B +1 1 +DROP TABLE t1; diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 5732fbbe03d..ebdd3794176 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -1887,3 +1887,54 @@ create table t1 ( Sys_end INT GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) ) WITH SYSTEM VERSIONING; + +CREATE TABLE t1 ( + A INT WITH SYSTEM VERSIONING, + B INT +); +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1 ( + A INT WITH SYSTEM VERSIONING, + B INT +) WITH SYSTEM VERSIONING; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +--error ER_NO_VERSIONED_FIELDS_IN_VERSIONED_TABLE +CREATE TABLE t1 ( + A INT, + B INT WITHOUT SYSTEM VERSIONING +); + +CREATE TABLE t1 ( + A INT, + B INT WITHOUT SYSTEM VERSIONING +) WITH SYSTEM VERSIONING; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1 ( + A INT WITH SYSTEM VERSIONING, + B INT WITHOUT SYSTEM VERSIONING +); +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1 ( + A INT WITH SYSTEM VERSIONING, + B INT WITHOUT SYSTEM VERSIONING +) WITH SYSTEM VERSIONING; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +--error ER_NO_VERSIONED_FIELDS_IN_VERSIONED_TABLE +CREATE TABLE t1 ( + A INT WITHOUT SYSTEM VERSIONING +); + +--error ER_NO_VERSIONED_FIELDS_IN_VERSIONED_TABLE +CREATE TABLE t1 ( + A INT WITHOUT SYSTEM VERSIONING +) WITH SYSTEM VERSIONING; diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test index 325d65e5872..3e2b9ceeaea 100644 --- a/mysql-test/t/multi_update.test +++ b/mysql-test/t/multi_update.test @@ -1119,3 +1119,32 @@ delimiter ;~~ call verify_vtq; drop procedure verify_vtq; + +CREATE TABLE t1 ( + id BIGINT PRIMARY KEY, + name VARCHAR(128) WITH SYSTEM VERSIONING, + salary BIGINT +); +INSERT INTO t1 VALUES (1, "Jeremy", 3000); + +CREATE TABLE t2 ( + id BIGINT PRIMARY KEY, + name VARCHAR(128) WITH SYSTEM VERSIONING, + salary BIGINT +); +INSERT INTO t2 VALUES (1, "Jeremy", 4000); + +SELECT sys_trx_start INTO @tmp1 FROM t1; +SELECT sys_trx_start INTO @tmp2 FROM t2; +UPDATE t1, t2 SET t1.name="Jerry", t2.name="Jerry" WHERE t1.id=t2.id AND t1.name="Jeremy"; +SELECT @tmp1 < sys_trx_start, name FROM t1; +SELECT @tmp2 < sys_trx_start, name FROM t2; + +SELECT sys_trx_start INTO @tmp1 FROM t1; +SELECT sys_trx_start INTO @tmp2 FROM t2; +UPDATE t1, t2 SET t1.salary=2500, t2.salary=2500 WHERE t1.id=t2.id AND t1.name="Jerry"; +SELECT @tmp1 = sys_trx_start, salary FROM t1; +SELECT @tmp2 = sys_trx_start, salary FROM t2; + +DROP TABLE t1; +DROP TABLE t2; diff --git a/mysql-test/t/update.test b/mysql-test/t/update.test index 784c563fbf2..41d59199e47 100644 --- a/mysql-test/t/update.test +++ b/mysql-test/t/update.test @@ -726,3 +726,21 @@ delimiter ;~~ call verify_vtq; drop procedure verify_vtq; + +CREATE TABLE t1 ( + id BIGINT PRIMARY KEY, + A INT, + B INT WITHOUT SYSTEM VERSIONING +) WITH SYSTEM VERSIONING; + +INSERT INTO t1 VALUES(1, 1, 1); + +SELECT sys_trx_start INTO @tmp1 FROM t1; +UPDATE t1 SET A=11, B=11 WHERE id=1; +SELECT @tmp1 < sys_trx_start, A, B FROM t1; + +SELECT sys_trx_start INTO @tmp1 FROM t1; +UPDATE t1 SET B=1 WHERE id=1; +SELECT @tmp1 = sys_trx_start, B FROM t1; + +DROP TABLE t1; diff --git a/sql/field.h b/sql/field.h index 4b6607fa099..bf4f8b5ce5c 100644 --- a/sql/field.h +++ b/sql/field.h @@ -3872,6 +3872,13 @@ class Column_definition: public Sql_alloc } } public: + enum enum_column_versioning + { + VERSIONING_NOT_SET, + WITH_VERSIONING, + WITHOUT_VERSIONING + }; + const char *field_name; LEX_STRING comment; // Comment for field Item *on_update; // ON UPDATE NOW() @@ -3907,6 +3914,8 @@ public: *default_value, // Default value *check_constraint; // Check constraint + enum_column_versioning versioning; + Column_definition(): comment(null_lex_str), on_update(NULL), sql_type(MYSQL_TYPE_NULL), length(0), decimals(0), @@ -3914,7 +3923,8 @@ public: interval(0), charset(&my_charset_bin), srid(0), geom_type(Field::GEOM_GEOMETRY), option_list(NULL), pack_flag(0), - vcol_info(0), default_value(0), check_constraint(0) + vcol_info(0), default_value(0), check_constraint(0), + versioning(VERSIONING_NOT_SET) { interval_list.empty(); } @@ -4276,6 +4286,7 @@ bool check_expression(Virtual_column_info *vcol, const char *name, #define FIELDFLAG_TREAT_BIT_AS_CHAR 4096U /* use Field_bit_as_char */ #define FIELDFLAG_LONG_DECIMAL 8192U +#define FIELDFLAG_WITHOUT_SYSTEM_VERSIONING 8192U #define FIELDFLAG_NO_DEFAULT 16384U /* sql */ #define FIELDFLAG_MAYBE_NULL 32768U // sql #define FIELDFLAG_HEX_ESCAPE 0x10000U @@ -4302,5 +4313,6 @@ bool check_expression(Virtual_column_info *vcol, const char *name, #define f_no_default(x) ((x) & FIELDFLAG_NO_DEFAULT) #define f_bit_as_char(x) ((x) & FIELDFLAG_TREAT_BIT_AS_CHAR) #define f_is_hex_escape(x) ((x) & FIELDFLAG_HEX_ESCAPE) +#define f_without_system_versioning(x) ((x) & FIELDFLAG_WITHOUT_SYSTEM_VERSIONING) #endif /* FIELD_INCLUDED */ diff --git a/sql/handler.cc b/sql/handler.cc index 0c2dea8b00e..174d15194a0 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6582,12 +6582,35 @@ static bool create_sys_trx_field_if_missing(THD *thd, const char *field_name, return false; } -bool System_versioning_info::add_implicit_fields(THD *thd, +bool System_versioning_info::add_versioning_info(THD *thd, Alter_info *alter_info) { - if (!declared_system_versioning) + DBUG_ASSERT(versioned()); + + if (!declared_system_versioning && !has_versioned_fields) return false; + bool without_system_versioning_by_default= !declared_system_versioning; + List_iterator it(alter_info->create_list); + while (Create_field *f= it++) + { + const char *name= f->field_name; + size_t len= strlen(name); + if (generated_as_row.start && + !strncmp(name, generated_as_row.start->c_ptr(), len)) + continue; + if (generated_as_row.end && + !strncmp(name, generated_as_row.end->c_ptr(), len)) + continue; + + if (f->versioning == Column_definition::VERSIONING_NOT_SET && + without_system_versioning_by_default) + f->flags|= WITHOUT_SYSTEM_VERSIONING_FLAG; + + else if (f->versioning == Column_definition::WITHOUT_VERSIONING) + f->flags|= WITHOUT_SYSTEM_VERSIONING_FLAG; + } + // If user specified some of these he must specify the others too. Do nothing. if (generated_as_row.start || generated_as_row.end || period_for_system_time.start || period_for_system_time.end) @@ -6602,3 +6625,99 @@ bool System_versioning_info::add_implicit_fields(THD *thd, create_string(thd->mem_root, &period_for_system_time.end, "sys_trx_end"); } + +bool System_versioning_info::check(THD *thd, Alter_info *alter_info) +{ + if (!versioned()) + return false; + + if (add_versioning_info(thd, alter_info)) + return true; + + bool r= false; + + { + int not_set= 0; + int with= 0; + List_iterator it(alter_info->create_list); + while (const Create_field *f= it++) + { + const char *name= f->field_name; + size_t len= strlen(name); + if (generated_as_row.start && + !strncmp(name, generated_as_row.start->c_ptr(), len)) + continue; + if (generated_as_row.end && + !strncmp(name, generated_as_row.end->c_ptr(), len)) + continue; + + if (f->versioning == Column_definition::VERSIONING_NOT_SET) + not_set++; + else if (f->versioning == Column_definition::WITH_VERSIONING) + with++; + } + + bool table_with_system_versioning= + declared_system_versioning || generated_as_row.start || + generated_as_row.end || period_for_system_time.start || + period_for_system_time.end; + + if ((table_with_system_versioning && not_set == 0 && with == 0) || + (!table_with_system_versioning && with == 0)) + { + r= true; + my_error(ER_NO_VERSIONED_FIELDS_IN_VERSIONED_TABLE, MYF(0)); + } + } + + if (!declared_system_versioning && !has_versioned_fields) + { + r= true; + my_error(ER_MISSING_WITH_SYSTEM_VERSIONING, MYF(0)); + } + + if (!generated_as_row.start) + { + r= true; + my_error(ER_SYS_START_NOT_SPECIFIED, MYF(0)); + } + + if (!generated_as_row.end) + { + r= true; + my_error(ER_SYS_END_NOT_SPECIFIED, MYF(0)); + } + + if (!period_for_system_time.start || !period_for_system_time.end) + { + r= true; + my_error(ER_MISSING_PERIOD_FOR_SYSTEM_TIME, MYF(0)); + } + + if (!r) + { + if (my_strcasecmp(system_charset_info, generated_as_row.start->c_ptr(), + period_for_system_time.start->c_ptr())) + { + r= true; + my_error(ER_PERIOD_FOR_SYSTEM_TIME_CONTAINS_WRONG_START_COLUMN, MYF(0)); + } + + if (my_strcasecmp(system_charset_info, generated_as_row.end->c_ptr(), + period_for_system_time.end->c_ptr())) + { + r= true; + my_error(ER_PERIOD_FOR_SYSTEM_TIME_CONTAINS_WRONG_END_COLUMN, MYF(0)); + } + } + + return r; // false means no error +} + +bool System_versioning_info::versioned() const +{ + return has_versioned_fields || has_unversioned_fields || + declared_system_versioning || period_for_system_time.start || + period_for_system_time.end || generated_as_row.start || + generated_as_row.end; +} diff --git a/sql/handler.h b/sql/handler.h index 8b7b6f516a1..698703f89ff 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1671,6 +1671,14 @@ struct Schema_specification_st struct System_versioning_info { + System_versioning_info() : + period_for_system_time({NULL, NULL}), + generated_as_row({NULL, NULL}), + declared_system_versioning(false), + has_versioned_fields(false), + has_unversioned_fields(false) + {} + struct { String *start, *end; @@ -1693,13 +1701,28 @@ struct System_versioning_info } /** Returns true on failure */ - bool add_implicit_fields(THD *thd, Alter_info *alter_info); + bool add_versioning_info(THD *thd, Alter_info *alter_info); + + /** Returns true on failure */ + bool check(THD *thd, Alter_info *alter_info); + + /** Returns true if table is versioned */ + bool versioned() const; /** User has added 'WITH SYSTEM VERSIONING' to table definition */ - bool declared_system_versioning; + bool declared_system_versioning : 1; - /** Table described by this structure have enabled system versioning */ - bool versioned; + /** + At least one field was specified 'WITH SYSTEM VERSIONING'. Useful for + error handling. + */ + bool has_versioned_fields : 1; + + /** + At least one field was specified 'WITHOUT SYSTEM VERSIONING'. Useful for + error handling. + */ + bool has_unversioned_fields : 1; }; /** @@ -1791,7 +1814,7 @@ struct Table_scope_and_contents_source_st bool versioned() const { - return system_versioning_info.versioned; + return system_versioning_info.versioned(); } const System_versioning_info *get_system_versioning_info() const { diff --git a/sql/lex.h b/sql/lex.h index da5a288be99..dff6624518a 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -703,6 +703,7 @@ static SYMBOL symbols[] = { { "WHILE", SYM(WHILE_SYM)}, { "WINDOW", SYM(WINDOW_SYM)}, { "WITH", SYM(WITH)}, + { "WITHOUT", SYM(WITHOUT)}, { "WORK", SYM(WORK_SYM)}, { "WRAPPER", SYM(WRAPPER_SYM)}, { "WRITE", SYM(WRITE_SYM)}, diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index f3859b5ba4a..167be4d10fc 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7537,3 +7537,6 @@ ER_SYS_START_FIELD_MUST_BE_BIGINT ER_SYS_END_FIELD_MUST_BE_BIGINT eng "System end field must be of type BIGINT UNSIGNED" + +ER_NO_VERSIONED_FIELDS_IN_VERSIONED_TABLE + eng "Every field specified unversioned in versioned table" diff --git a/sql/sql_class.h b/sql/sql_class.h index 1b920b23a2d..49f62f9ea4e 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -5533,6 +5533,8 @@ class multi_update :public select_result_interceptor // For System Versioning (may need to insert new fields to a table). ha_rows updated_sys_ver; + bool has_vers_fields; + public: multi_update(THD *thd_arg, TABLE_LIST *ut, List *leaves_list, List *fields, List *values, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 9bae9ecc658..6b75c030374 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -138,7 +138,6 @@ static void sql_kill_user(THD *thd, LEX_USER *user, killed_state state); static bool lock_tables_precheck(THD *thd, TABLE_LIST *tables); static bool execute_show_status(THD *, TABLE_LIST *); static bool check_rename_table(THD *, TABLE_LIST *, TABLE_LIST *); -static bool check_system_versioning(Table_scope_and_contents_source_st *); const char *any_db="*any*"; // Special symbol for check_access @@ -3856,11 +3855,7 @@ mysql_execute_command(THD *thd) goto end_with_restore_list; } - if (System_versioning_info *info= create_info.get_system_versioning_info()) - if (info->add_implicit_fields(thd, &alter_info)) - goto end_with_restore_list; - - if (check_system_versioning(&create_info)) + if (create_info.system_versioning_info.check(thd, &alter_info)) goto end_with_restore_list; /* Check privileges */ @@ -7326,66 +7321,6 @@ bool check_fk_parent_table_access(THD *thd, } - -/**************************************************************************** - Checks related to system versioning -****************************************************************************/ - -static bool check_system_versioning(Table_scope_and_contents_source_st *create_info) -{ - const System_versioning_info *versioning_info = &create_info->system_versioning_info; - - if (!versioning_info->versioned) - return false; - - bool r = false; - - if (!versioning_info->declared_system_versioning) - { - r = true; - my_error(ER_MISSING_WITH_SYSTEM_VERSIONING, MYF(0)); - } - - if (!versioning_info->generated_as_row.start) - { - r = true; - my_error(ER_SYS_START_NOT_SPECIFIED, MYF(0)); - } - - if (!versioning_info->generated_as_row.end) - { - r = true; - my_error(ER_SYS_END_NOT_SPECIFIED, MYF(0)); - } - - if (!versioning_info->period_for_system_time.start || !versioning_info->period_for_system_time.end) - { - r = true; - my_error(ER_MISSING_PERIOD_FOR_SYSTEM_TIME, MYF(0)); - } - - if (!r) - { - if (my_strcasecmp(system_charset_info, - versioning_info->generated_as_row.start->c_ptr(), - versioning_info->period_for_system_time.start->c_ptr())) - { - r = true; - my_error(ER_PERIOD_FOR_SYSTEM_TIME_CONTAINS_WRONG_START_COLUMN, MYF(0)); - } - - if (my_strcasecmp(system_charset_info, - versioning_info->generated_as_row.end->c_ptr(), - versioning_info->period_for_system_time.end->c_ptr())) - { - r = true; - my_error(ER_PERIOD_FOR_SYSTEM_TIME_CONTAINS_WRONG_END_COLUMN, MYF(0)); - } - } - - return r; // false means no error -} - /**************************************************************************** Check stack size; Send error if there isn't enough stack to continue ****************************************************************************/ diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 084e98b143f..cc7f2b0a017 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2133,6 +2133,11 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, packet->append(STRING_WITH_LEN(" GENERATED AS ROW END")); } + if (field->is_versioning_disabled()) + { + packet->append(STRING_WITH_LEN(" WITHOUT SYSTEM VERSIONING")); + } + if (!limited_mysql_mode && print_on_update_clause(field, &def_value, false)) { diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 620f580d688..8b62c71733c 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2989,6 +2989,8 @@ bool Column_definition::prepare_create_field(uint *blob_columns, pack_flag|= FIELDFLAG_MAYBE_NULL; if (flags & NO_DEFAULT_VALUE_FLAG) pack_flag|= FIELDFLAG_NO_DEFAULT; + if (flags & WITHOUT_SYSTEM_VERSIONING_FLAG) + pack_flag|= FIELDFLAG_WITHOUT_SYSTEM_VERSIONING; DBUG_RETURN(false); } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index acbbf559c63..419ccc1bc94 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -155,6 +155,17 @@ static bool check_fields(THD *thd, List &items) return FALSE; } +static bool check_has_vers_fields(List &items) +{ + List_iterator it(items); + while (Item *item= it++) + { + if (Item_field *item_field= item->field_for_view_update()) + if (!(item_field->field->flags & WITHOUT_SYSTEM_VERSIONING_FLAG)) + return true; + } + return false; +} /** Re-read record if more columns are needed for error message. @@ -355,6 +366,7 @@ int mysql_update(THD *thd, { DBUG_RETURN(1); } + bool has_vers_fields= check_has_vers_fields(fields); if (check_key_in_view(thd, table_list)) { my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "UPDATE"); @@ -763,7 +775,7 @@ int mysql_update(THD *thd, TRG_EVENT_UPDATE)) break; /* purecov: inspected */ - if (table->versioned_by_sql()) + if (has_vers_fields && table->versioned_by_sql()) table->vers_update_fields(); found++; @@ -835,7 +847,7 @@ int mysql_update(THD *thd, { updated++; - if (table->versioned()) + if (has_vers_fields && table->versioned()) { if (table->versioned_by_sql()) { @@ -1671,6 +1683,7 @@ multi_update::multi_update(THD *thd_arg, TABLE_LIST *table_list, transactional_tables(0), ignore(ignore_arg), error_handled(0), prepared(0), updated_sys_ver(0) { + has_vers_fields= check_has_vers_fields(*field_list); } @@ -2176,7 +2189,7 @@ int multi_update::send_data(List ¬_used_values) if (table->default_field && table->update_default_fields(1, ignore)) DBUG_RETURN(1); - if (table->versioned_by_sql()) + if (has_vers_fields && table->versioned_by_sql()) table->vers_update_fields(); if ((error= cur_table->view_check_option(thd, ignore)) != @@ -2226,7 +2239,7 @@ int multi_update::send_data(List ¬_used_values) error= 0; updated--; } - else if (table->versioned()) + else if (has_vers_fields && table->versioned()) { if (table->versioned_by_sql()) { @@ -2511,7 +2524,7 @@ int multi_update::do_updates() goto err2; } } - if (table->versioned_by_sql()) + if (has_vers_fields && table->versioned_by_sql()) table->vers_update_fields(); if ((local_error=table->file->ha_update_row(table->record[1], @@ -2529,7 +2542,7 @@ int multi_update::do_updates() { updated++; - if (table->versioned()) + if (has_vers_fields && table->versioned()) { if (table->versioned_by_sql()) { diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 05c05c3e144..9b11ac0cfe9 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1572,6 +1572,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token WINDOW_SYM %token WHILE_SYM %token WITH /* SQL-2003-R */ +%token WITHOUT /* SQL-2003-R */ %token WITH_CUBE_SYM /* INTERNAL */ %token WITH_ROLLUP_SYM /* INTERNAL */ %token WORK_SYM /* SQL-2003-N */ @@ -5852,7 +5853,7 @@ create_table_option: { System_versioning_info &info= Lex->vers_get_info(); info.declared_system_versioning= true; - info.versioned= true; + Lex->create_info.options|= HA_VERSIONED_TABLE; } ; @@ -6064,7 +6065,6 @@ period_for_system_time: MYSQL_YYABORT; } info.set_period_for_system_time($4, $6); - info.versioned= true; } ; @@ -6165,7 +6165,6 @@ field_def: | opt_generated_always AS ROW_SYM start_or_end { System_versioning_info &info= Lex->vers_get_info(); - info.versioned= true; String *field_name= new (thd->mem_root) String((const char*)Lex->last_field->field_name, system_charset_info); if (!field_name) @@ -6667,6 +6666,16 @@ serial_attribute: new (thd->mem_root) engine_option_value($1, &Lex->last_field->option_list, &Lex->option_list_last); } + | WITH SYSTEM VERSIONING + { + Lex->last_field->versioning = Column_definition::WITH_VERSIONING; + Lex->create_info.system_versioning_info.has_versioned_fields= true; + } + | WITHOUT SYSTEM VERSIONING + { + Lex->last_field->versioning = Column_definition::WITHOUT_VERSIONING; + Lex->create_info.system_versioning_info.has_unversioned_fields= true; + } ; diff --git a/sql/table.cc b/sql/table.cc index 80a7046be1a..3a75fbe8e48 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2017,6 +2017,9 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, if (f_no_default(pack_flag)) reg_field->flags|= NO_DEFAULT_VALUE_FLAG; + if (f_without_system_versioning(pack_flag)) + reg_field->flags|= WITHOUT_SYSTEM_VERSIONING_FLAG; + if (reg_field->unireg_check == Field::NEXT_NUMBER) share->found_next_number_field= field_ptr; -- cgit v1.2.1 From 82114170bcfad83408723dd6876e4e1a5e8c7148 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Thu, 13 Oct 2016 20:23:27 +0000 Subject: SQL: implicit fields for IB tables + misc cleanups --- sql/handler.cc | 50 ++++++++++++++++++++++++++---------------- sql/handler.h | 51 ++++++++++++------------------------------- sql/sql_lex.h | 4 ++-- sql/sql_parse.cc | 8 ++++--- sql/sql_table.cc | 25 +++++++-------------- sql/sql_yacc.yy | 12 ++++++----- sql/unireg.cc | 66 +++++++++++++++----------------------------------------- 7 files changed, 84 insertions(+), 132 deletions(-) diff --git a/sql/handler.cc b/sql/handler.cc index 174d15194a0..f577f581083 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6560,7 +6560,8 @@ static bool create_string(MEM_ROOT *mem_root, String **s, const char *value) } static bool create_sys_trx_field_if_missing(THD *thd, const char *field_name, - Alter_info *alter_info, String **s) + Alter_info *alter_info, String **s, + bool integer_fields) { Create_field *f= new (thd->mem_root) Create_field(); if (!f) @@ -6568,8 +6569,17 @@ static bool create_sys_trx_field_if_missing(THD *thd, const char *field_name, f->field_name= field_name; f->charset= system_charset_info; - f->sql_type= MYSQL_TYPE_TIMESTAMP2; - f->length= 6; + if (integer_fields) + { + f->sql_type= MYSQL_TYPE_LONGLONG; + f->flags= UNSIGNED_FLAG; + f->length= MY_INT64_NUM_DECIMAL_DIGITS; + } + else + { + f->sql_type= MYSQL_TYPE_TIMESTAMP2; + f->length= 6; + } f->decimals= 0; if (f->check(thd)) @@ -6582,11 +6592,11 @@ static bool create_sys_trx_field_if_missing(THD *thd, const char *field_name, return false; } -bool System_versioning_info::add_versioning_info(THD *thd, - Alter_info *alter_info) +bool Vers_parse_info::add_versioning_info( + THD *thd, + Alter_info *alter_info, + bool integer_fields) { - DBUG_ASSERT(versioned()); - if (!declared_system_versioning && !has_versioned_fields) return false; @@ -6617,21 +6627,30 @@ bool System_versioning_info::add_versioning_info(THD *thd, return false; return create_sys_trx_field_if_missing(thd, "sys_trx_start", alter_info, - &generated_as_row.start) || + &generated_as_row.start, integer_fields) || create_sys_trx_field_if_missing(thd, "sys_trx_end", alter_info, - &generated_as_row.end) || + &generated_as_row.end, integer_fields) || create_string(thd->mem_root, &period_for_system_time.start, "sys_trx_start") || create_string(thd->mem_root, &period_for_system_time.end, "sys_trx_end"); } -bool System_versioning_info::check(THD *thd, Alter_info *alter_info) +bool Vers_parse_info::check(THD *thd, Alter_info *alter_info, bool integer_fields) { - if (!versioned()) + if (!( + has_versioned_fields || + has_unversioned_fields || + declared_system_versioning || + period_for_system_time.start || + period_for_system_time.end || + generated_as_row.start || + generated_as_row.end)) + { return false; + } - if (add_versioning_info(thd, alter_info)) + if (add_versioning_info(thd, alter_info, integer_fields)) return true; bool r= false; @@ -6714,10 +6733,3 @@ bool System_versioning_info::check(THD *thd, Alter_info *alter_info) return r; // false means no error } -bool System_versioning_info::versioned() const -{ - return has_versioned_fields || has_unversioned_fields || - declared_system_versioning || period_for_system_time.start || - period_for_system_time.end || generated_as_row.start || - generated_as_row.end; -} diff --git a/sql/handler.h b/sql/handler.h index 698703f89ff..11b71a6f03d 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1669,45 +1669,34 @@ struct Schema_specification_st }; -struct System_versioning_info +struct Vers_parse_info { - System_versioning_info() : - period_for_system_time({NULL, NULL}), - generated_as_row({NULL, NULL}), + Vers_parse_info() : declared_system_versioning(false), has_versioned_fields(false), has_unversioned_fields(false) {} - struct - { - String *start, *end; - } period_for_system_time; - - struct + struct start_end_t { + start_end_t() : + start(NULL), + end(NULL) {} String *start; String *end; - } generated_as_row; + }; + + start_end_t period_for_system_time; + start_end_t generated_as_row; void set_period_for_system_time(String *start, String *end) { period_for_system_time.start = start; period_for_system_time.end = end; } - void set_period_for_system_time() - { - set_period_for_system_time(NULL, NULL); - } - - /** Returns true on failure */ - bool add_versioning_info(THD *thd, Alter_info *alter_info); - /** Returns true on failure */ - bool check(THD *thd, Alter_info *alter_info); - - /** Returns true if table is versioned */ - bool versioned() const; + bool add_versioning_info(THD *thd, Alter_info *alter_info, bool integer_fields); + bool check(THD *thd, Alter_info *alter_info, bool integer_fields); /** User has added 'WITH SYSTEM VERSIONING' to table definition */ bool declared_system_versioning : 1; @@ -1799,7 +1788,7 @@ struct Table_scope_and_contents_source_st bool table_was_deleted; sequence_definition *seq_create_info; - System_versioning_info system_versioning_info; + Vers_parse_info vers_info; void init() { @@ -1814,19 +1803,7 @@ struct Table_scope_and_contents_source_st bool versioned() const { - return system_versioning_info.versioned(); - } - const System_versioning_info *get_system_versioning_info() const - { - if (!versioned()) - return NULL; - return &system_versioning_info; - } - System_versioning_info *get_system_versioning_info() - { - if (!versioned()) - return NULL; - return &system_versioning_info; + return options & HA_VERSIONED_TABLE; } }; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 64e0c9ddaa9..f2fc43074c6 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3565,9 +3565,9 @@ public: bool add_unit_in_brackets(SELECT_LEX *nselect); void check_automatic_up(enum sub_select_type type); - System_versioning_info &vers_get_info() + Vers_parse_info &vers_get_info() { - return create_info.system_versioning_info; + return create_info.vers_info; } }; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 6b75c030374..611e1c1a021 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3855,9 +3855,6 @@ mysql_execute_command(THD *thd) goto end_with_restore_list; } - if (create_info.system_versioning_info.check(thd, &alter_info)) - goto end_with_restore_list; - /* Check privileges */ if ((res= create_table_precheck(thd, select_tables, create_table))) goto end_with_restore_list; @@ -3878,6 +3875,11 @@ mysql_execute_command(THD *thd) */ if (!(create_info.used_fields & HA_CREATE_USED_ENGINE)) create_info.use_default_db_type(thd); + + DBUG_ASSERT(create_info.db_type); + if (create_info.vers_info.check(thd, &alter_info, create_info.db_type->versioned())) + goto end_with_restore_list; + /* If we are using SET CHARSET without DEFAULT, add an implicit DEFAULT to not confuse old users. (This may change). diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 8b62c71733c..c4bc2028caf 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3155,12 +3155,9 @@ copy_info_about_generated_fields(Alter_info *dst_alter_info, if (!src_create_info->versioned()) return; - const System_versioning_info *versioning_info = - src_create_info->get_system_versioning_info(); - DBUG_ASSERT(versioning_info); - const char *row_start_field = versioning_info->generated_as_row.start->c_ptr(); + const char *row_start_field = src_create_info->vers_info.generated_as_row.start->c_ptr(); DBUG_ASSERT(row_start_field); - const char *row_end_field = versioning_info->generated_as_row.end->c_ptr(); + const char *row_end_field = src_create_info->vers_info.generated_as_row.end->c_ptr(); DBUG_ASSERT(row_end_field); List_iterator it(dst_alter_info->create_list); @@ -3249,8 +3246,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, } select_field_pos= alter_info->create_list.elements - select_field_count; - const System_versioning_info *versioning_info = - create_info->get_system_versioning_info(); for (field_no=0; (sql_field=it++) ; field_no++) { @@ -3478,15 +3473,15 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, if (sql_field->stored_in_db()) record_offset+= sql_field->pack_length; - if (versioning_info) + if (create_info->versioned()) { const bool is_generated_as_row_start = !my_strcasecmp(system_charset_info, - versioning_info->generated_as_row.start->c_ptr(), + create_info->vers_info.generated_as_row.start->c_ptr(), sql_field->field_name); const bool is_generated_as_row_end = !my_strcasecmp(system_charset_info, - versioning_info->generated_as_row.end->c_ptr(), + create_info->vers_info.generated_as_row.end->c_ptr(), sql_field->field_name); if (is_generated_as_row_start && is_generated_as_row_end) { @@ -4351,13 +4346,9 @@ vers_prepare_keys(THD *thd, { DBUG_ASSERT(create_info->versioned()); - const System_versioning_info *versioning_info= - create_info->get_system_versioning_info(); - - DBUG_ASSERT(versioning_info); - const char *row_start_field= versioning_info->generated_as_row.start->c_ptr(); + const char *row_start_field= create_info->vers_info.generated_as_row.start->c_ptr(); DBUG_ASSERT(row_start_field); - const char *row_end_field= versioning_info->generated_as_row.end->c_ptr(); + const char *row_end_field= create_info->vers_info.generated_as_row.end->c_ptr(); DBUG_ASSERT(row_end_field); List_iterator key_it(alter_info->key_list); @@ -4384,7 +4375,7 @@ vers_prepare_keys(THD *thd, continue; // Key already contains Sys_start or Sys_end const LEX_STRING &lex_sys_end= - versioning_info->generated_as_row.end->lex_string(); + create_info->vers_info.generated_as_row.end->lex_string(); Key_part_spec *key_part_sys_end_col= new(thd->mem_root) Key_part_spec(lex_sys_end, 0); key->columns.push_back(key_part_sys_end_col); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 9b11ac0cfe9..9d5640280e0 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5851,7 +5851,7 @@ create_table_option: } | WITH SYSTEM VERSIONING { - System_versioning_info &info= Lex->vers_get_info(); + Vers_parse_info &info= Lex->vers_get_info(); info.declared_system_versioning= true; Lex->create_info.options|= HA_VERSIONED_TABLE; } @@ -6058,7 +6058,7 @@ period_for_system_time: // If FOR_SYM is followed by SYSTEM_TIME_SYM then they are merged to: FOR_SYSTEM_TIME_SYM . PERIOD_SYM FOR_SYSTEM_TIME_SYM '(' period_for_system_time_column_id ',' period_for_system_time_column_id ')' { - System_versioning_info &info= Lex->vers_get_info(); + Vers_parse_info &info= Lex->vers_get_info(); if (!my_strcasecmp(system_charset_info, $4->c_ptr(), $6->c_ptr())) { my_error(ER_SYS_START_AND_SYS_END_SAME, MYF(0), $4->c_ptr()); @@ -6164,7 +6164,7 @@ field_def: vcol_opt_specifier vcol_opt_attribute | opt_generated_always AS ROW_SYM start_or_end { - System_versioning_info &info= Lex->vers_get_info(); + Vers_parse_info &info= Lex->vers_get_info(); String *field_name= new (thd->mem_root) String((const char*)Lex->last_field->field_name, system_charset_info); if (!field_name) @@ -6669,12 +6669,14 @@ serial_attribute: | WITH SYSTEM VERSIONING { Lex->last_field->versioning = Column_definition::WITH_VERSIONING; - Lex->create_info.system_versioning_info.has_versioned_fields= true; + Lex->create_info.vers_info.has_versioned_fields= true; + Lex->create_info.options|= HA_VERSIONED_TABLE; } | WITHOUT SYSTEM VERSIONING { Lex->last_field->versioning = Column_definition::WITHOUT_VERSIONING; - Lex->create_info.system_versioning_info.has_unversioned_fields= true; + Lex->create_info.vers_info.has_unversioned_fields= true; + Lex->create_info.options|= HA_VERSIONED_TABLE; } ; diff --git a/sql/unireg.cc b/sql/unireg.cc index 0465626c132..445d3441af7 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -87,31 +87,28 @@ static uchar *extra2_write(uchar *pos, enum extra2_frm_value_type type, return extra2_write(pos, type, reinterpret_cast(str)); } -static bool -versioned(HA_CREATE_INFO *create_info) -{ - return create_info->versioned(); -} +static const bool ROW_START = true; +static const bool ROW_END = false; -static uint16 -get_row_start_field(HA_CREATE_INFO *create_info, List &create_fields) +inline +uint16 +vers_get_field(HA_CREATE_INFO *create_info, List &create_fields, bool row_start) { - DBUG_ASSERT(versioned(create_info)); + DBUG_ASSERT(create_info->versioned()); List_iterator it(create_fields); - Create_field*sql_field = NULL; - - const System_versioning_info *versioning_info = - create_info->get_system_versioning_info(); - DBUG_ASSERT(versioning_info); + Create_field *sql_field = NULL; - const char *row_start_field = versioning_info->generated_as_row.start->c_ptr(); - DBUG_ASSERT(row_start_field); + const char *row_field = + row_start ? + create_info->vers_info.generated_as_row.start->c_ptr() : + create_info->vers_info.generated_as_row.end->c_ptr(); + DBUG_ASSERT(row_field); for (unsigned field_no = 0; (sql_field = it++); ++field_no) { if (!my_strcasecmp(system_charset_info, - row_start_field, + row_field, sql_field->field_name)) { DBUG_ASSERT(field_no <= uint16(~0U)); @@ -123,35 +120,6 @@ get_row_start_field(HA_CREATE_INFO *create_info, List &create_fiel return 0; } -static uint16 -get_row_end_field(HA_CREATE_INFO *create_info, List &create_fields) -{ - DBUG_ASSERT(versioned(create_info)); - - List_iterator it(create_fields); - Create_field*sql_field = NULL; - - const System_versioning_info *versioning_info = - create_info->get_system_versioning_info(); - DBUG_ASSERT(versioning_info); - - const char *row_end_field = versioning_info->generated_as_row.end->c_ptr(); - DBUG_ASSERT(row_end_field); - - for (unsigned field_no = 0; (sql_field = it++); ++field_no) - { - if (!my_strcasecmp(system_charset_info, - row_end_field, - sql_field->field_name)) - { - DBUG_ASSERT(field_no <= uint16(~0U)); - return uint16(field_no); - } - } - - DBUG_ASSERT(0); /* Not Reachable */ - return 0; -} /** Create a frm (table definition) file @@ -285,7 +253,7 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table, if (gis_extra2_len) extra2_size+= 1 + (gis_extra2_len > 255 ? 3 : 1) + gis_extra2_len; - if (versioned(create_info)) + if (create_info->versioned()) { extra2_size+= 1 + 1 + 2 * sizeof(uint16); } @@ -345,13 +313,13 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table, } #endif /*HAVE_SPATIAL*/ - if (versioned(create_info)) + if (create_info->versioned()) { *pos++= EXTRA2_PERIOD_FOR_SYSTEM_TIME; *pos++= 2 * sizeof(uint16); - int2store(pos, get_row_start_field(create_info, create_fields)); + int2store(pos, vers_get_field(create_info, create_fields, ROW_START)); pos+= sizeof(uint16); - int2store(pos, get_row_end_field(create_info, create_fields)); + int2store(pos, vers_get_field(create_info, create_fields, ROW_END)); pos+= sizeof(uint16); } -- cgit v1.2.1 From 6ccae7369b2d5a9b38cbad480e393ee9a3a7fec8 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Fri, 14 Oct 2016 07:24:59 +0000 Subject: SQL: fixed LEFT JOIN, RIGHT JOIN --- sql/sql_lex.cc | 2 +- sql/sql_lex.h | 2 +- sql/sql_select.cc | 43 +++++++++++++++++++++++++++++++++---------- sql/table.h | 1 + 4 files changed, 36 insertions(+), 12 deletions(-) diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 34b35d60c14..242923de546 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2200,7 +2200,7 @@ void st_select_lex::init_query() join= 0; having= prep_having= where= prep_where= 0; cond_pushed_into_where= cond_pushed_into_having= 0; - saved_conds= 0; + saved_where= 0; olap= UNSPECIFIED_OLAP_TYPE; having_fix_field= 0; context.select_lex= this; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index f2fc43074c6..826ebd03063 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -810,7 +810,7 @@ public: Item *prep_having;/* saved HAVING clause for prepared statement processing */ Item *cond_pushed_into_where; /* condition pushed into the select's WHERE */ Item *cond_pushed_into_having; /* condition pushed into the select's HAVING */ - Item *saved_conds; + Item *saved_where; /* Saved values of the WHERE and HAVING clauses*/ Item::cond_result cond_value, having_value; /* point on lex in which it was created, used in view subquery detection */ diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 331421ecb6d..9aff4c3e731 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -668,7 +668,7 @@ setup_without_group(THD *thd, Ref_ptr_array ref_pointer_array, } static int -setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **conds, SELECT_LEX *select_lex) +setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LEX *select_lex) { DBUG_ENTER("setup_for_system_time"); @@ -697,23 +697,46 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **conds, SELECT_LEX *se because they must outlive execution phase for multiple executions. */ arena= thd->activate_stmt_arena_if_needed(&backup); - if (select_lex->saved_conds) + if (select_lex->saved_where) { DBUG_ASSERT(thd->stmt_arena->is_sp_execute()); - *conds= select_lex->saved_conds; + *where_expr= select_lex->saved_where; } else if (thd->stmt_arena->is_sp_execute()) { - if (thd->stmt_arena->is_stmt_execute()) - *conds= 0; - else if (*conds) - select_lex->saved_conds= (*conds)->copy_andor_structure(thd); + if (thd->stmt_arena->is_stmt_execute()) // SP executed second time (STMT_EXECUTED) + *where_expr= 0; + else if (*where_expr) // SP executed first time (STMT_INITIALIZED_FOR_SP) + /* copy_andor_structure() is required since this andor tree + is modified later (and on shorter arena) */ + select_lex->saved_where= (*where_expr)->copy_andor_structure(thd); } for (table= tables; table; table= table->next_local) { if (table->table && table->table->versioned()) { + COND** dst_cond; + if (table->on_expr) + { + if (table->saved_on_expr) // same logic as saved_where + { + DBUG_ASSERT(thd->stmt_arena->is_sp_execute()); + table->on_expr= table->saved_on_expr; + } + else if (thd->stmt_arena->is_sp_execute()) + { + if (thd->stmt_arena->is_stmt_execute()) // SP executed second time (STMT_EXECUTED) + table->on_expr= 0; + else if (table->on_expr) // SP executed first time (STMT_INITIALIZED_FOR_SP) + table->saved_on_expr= table->on_expr->copy_andor_structure(thd); + } + dst_cond= &table->on_expr; + } + else + { + dst_cond= where_expr; + } Field *fstart= table->table->vers_start_field(); Field *fend= table->table->vers_end_field(); @@ -782,15 +805,15 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **conds, SELECT_LEX *se if (cond1) { cond1= and_items(thd, - *conds, + *dst_cond, and_items(thd, cond2, cond1)); if (arena) - *conds= cond1; + *dst_cond= cond1; else - thd->change_item_tree(conds, cond1); + thd->change_item_tree(dst_cond, cond1); table->vers_moved_to_where= true; } diff --git a/sql/table.h b/sql/table.h index cc575602c49..e2c055b14d5 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1908,6 +1908,7 @@ struct TABLE_LIST char *db, *alias, *table_name, *schema_table_name; char *option; /* Used by cache index */ Item *on_expr; /* Used with outer join */ + Item *saved_on_expr; /* Used with SP and System Versioning */ Item *sj_on_expr; /* -- cgit v1.2.1 From 2c4527fb941920d46f409ff4a5b160d482045c68 Mon Sep 17 00:00:00 2001 From: Kosov Eugene Date: Fri, 14 Oct 2016 18:18:35 +0300 Subject: Tests: added tests for versioned tables with implicitly added fields --- mysql-test/r/insert.result | 14 ++++++++++++++ mysql-test/t/insert.test | 20 +++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/insert.result b/mysql-test/r/insert.result index 96062931f37..b0e1b0d67a7 100644 --- a/mysql-test/r/insert.result +++ b/mysql-test/r/insert.result @@ -915,3 +915,17 @@ No A B C D drop table t1; drop table t2; drop procedure verify_vtq; +CREATE TABLE t1( +id BIGINT PRIMARY KEY, +A INT, +B INT +) WITH SYSTEM VERSIONING; +INSERT INTO t1 VALUES(1, 1, 1); +DROP TABLE t1; +CREATE TABLE t1( +id BIGINT PRIMARY KEY, +A INT, +B INT +) WITH SYSTEM VERSIONING ENGINE=INNODB; +INSERT INTO t1 VALUES(1, 1, 1); +DROP TABLE t1; diff --git a/mysql-test/t/insert.test b/mysql-test/t/insert.test index aa7286ec372..ed4fb5ecc68 100644 --- a/mysql-test/t/insert.test +++ b/mysql-test/t/insert.test @@ -737,4 +737,22 @@ call verify_vtq; drop table t1; drop table t2; -drop procedure verify_vtq; \ No newline at end of file +drop procedure verify_vtq; + +# Check whether it is possible to insert rows in a versioned table +# with implicit fields without crash. +CREATE TABLE t1( + id BIGINT PRIMARY KEY, + A INT, + B INT +) WITH SYSTEM VERSIONING; +INSERT INTO t1 VALUES(1, 1, 1); +DROP TABLE t1; + +CREATE TABLE t1( + id BIGINT PRIMARY KEY, + A INT, + B INT +) WITH SYSTEM VERSIONING ENGINE=INNODB; +INSERT INTO t1 VALUES(1, 1, 1); +DROP TABLE t1; -- cgit v1.2.1 From 27944ef9b459b1036358117f50371226eb1f99e7 Mon Sep 17 00:00:00 2001 From: Kosov Eugene Date: Fri, 14 Oct 2016 23:08:37 +0300 Subject: enable update_multi.test --- mysql-test/t/multi_update.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test index 3e2b9ceeaea..3ee7ab3bcf4 100644 --- a/mysql-test/t/multi_update.test +++ b/mysql-test/t/multi_update.test @@ -986,7 +986,7 @@ drop table t1,t2,t3; --echo end of 5.5 tests ---source include/have_xtradb.inc +#--source include/have_xtradb.inc --echo --echo # Bug mdev-5970 -- cgit v1.2.1 From 2edb6fda2a2a3f58c2aa96662f2bca7b19adc7db Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Fri, 14 Oct 2016 20:33:41 +0000 Subject: Tests: select.test fix ded545be9f7a416d1d50d653ab278dd0fc7e6c5e --- mysql-test/r/select.result | 2 +- mysql-test/t/select.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index c260e2ff333..ebcc1155fc9 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -5567,7 +5567,7 @@ INSERT INTO t1(x, y) VALUES DELETE FROM t1 WHERE x = 3; DELETE FROM t1 WHERE x > 7; INSERT INTO t1(x, y) VALUES(3, 33); -SELECT @time := Sys_start FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07' WHERE x = 3 AND y = 33; +SELECT @time := Sys_start FROM t1 WHERE x = 3 AND y = 33 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; @time := Sys_start Sys_start SELECT x, y FROM t1; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 3d2c689591e..8f3055850b9 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -4693,7 +4693,7 @@ DELETE FROM t1 WHERE x > 7; --real_sleep 1 INSERT INTO t1(x, y) VALUES(3, 33); --replace_column 1 Sys_start -SELECT @time := Sys_start FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07' WHERE x = 3 AND y = 33; +SELECT @time := Sys_start FROM t1 WHERE x = 3 AND y = 33 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; SELECT x, y FROM t1; SET @query=CONCAT('SELECT x, y FROM t1 FOR SYSTEM_TIME FROM TIMESTAMP \'0-0-0 0:0:0\' TO TIMESTAMP \'', @time, '\''); PREPARE stmt_t1 FROM @query; -- cgit v1.2.1 From a03da4fa7886f41641d379362a4599b5f2f8fe52 Mon Sep 17 00:00:00 2001 From: Kosov Eugene Date: Sat, 15 Oct 2016 00:54:32 +0300 Subject: Style: removed unused header, other small fixes --- sql/field.h | 2 -- sql/handler.cc | 15 +++++++-------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/sql/field.h b/sql/field.h index bf4f8b5ce5c..a52fb656b39 100644 --- a/sql/field.h +++ b/sql/field.h @@ -33,8 +33,6 @@ #include "compat56.h" #include "sql_type.h" /* Type_std_attributes */ -#include - class Send_field; class Copy_field; class Protocol; diff --git a/sql/handler.cc b/sql/handler.cc index f577f581083..e3b8d6ace3f 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6559,9 +6559,9 @@ static bool create_string(MEM_ROOT *mem_root, String **s, const char *value) return *s == NULL; } -static bool create_sys_trx_field_if_missing(THD *thd, const char *field_name, - Alter_info *alter_info, String **s, - bool integer_fields) +static bool create_sys_trx_field(THD *thd, const char *field_name, + Alter_info *alter_info, String **s, + bool integer_fields) { Create_field *f= new (thd->mem_root) Create_field(); if (!f) @@ -6626,10 +6626,10 @@ bool Vers_parse_info::add_versioning_info( period_for_system_time.start || period_for_system_time.end) return false; - return create_sys_trx_field_if_missing(thd, "sys_trx_start", alter_info, - &generated_as_row.start, integer_fields) || - create_sys_trx_field_if_missing(thd, "sys_trx_end", alter_info, - &generated_as_row.end, integer_fields) || + return create_sys_trx_field(thd, "sys_trx_start", alter_info, + &generated_as_row.start, integer_fields) || + create_sys_trx_field(thd, "sys_trx_end", alter_info, + &generated_as_row.end, integer_fields) || create_string(thd->mem_root, &period_for_system_time.start, "sys_trx_start") || create_string(thd->mem_root, &period_for_system_time.end, @@ -6732,4 +6732,3 @@ bool Vers_parse_info::check(THD *thd, Alter_info *alter_info, bool integer_field return r; // false means no error } - -- cgit v1.2.1 From 31e296c55827a35ad0e5db4a57fc5b2c21679aaf Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Sat, 15 Oct 2016 07:46:11 +0000 Subject: IB: wrong 'interface consistency' (fixes #47) --- storage/innobase/row/row0mysql.cc | 6 ------ 1 file changed, 6 deletions(-) diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 2e3121a2e57..c1a4871a9ff 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -1965,7 +1965,6 @@ row_update_for_mysql_using_upd_graph( upd_t* uvect = node->update; upd_field_t* ufield; dict_col_t* col; - const mysql_row_templ_t* t; unsigned col_idx; if (node->is_delete) { ufield = &uvect->fields[0]; @@ -1992,11 +1991,6 @@ row_update_for_mysql_using_upd_graph( uvect->n_fields++; ut_ad(node->in_mysql_interface); // otherwise needs to recalculate node->cmpl_info - - /* Return trx_id back to mysql_rec (for the sake of interface consistency). */ - t = &prebuilt->mysql_template[col_idx]; - ut_ad(t->mysql_col_len == 8); - int8store(&mysql_rec[t->mysql_col_offset], trx->id); } ut_a(node->pcur->rel_pos == BTR_PCUR_ON); -- cgit v1.2.1 From 0a8fd20ad6860bbf04f3bbf573b64045d0da87c5 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Sat, 15 Oct 2016 08:21:11 +0000 Subject: SQL: NOT NULL for implicit fields (fixes #46) --- sql/handler.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sql/handler.cc b/sql/handler.cc index e3b8d6ace3f..0b079676fc9 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6567,20 +6567,21 @@ static bool create_sys_trx_field(THD *thd, const char *field_name, if (!f) return true; + memset(f, 0, sizeof(*f)); f->field_name= field_name; f->charset= system_charset_info; if (integer_fields) { f->sql_type= MYSQL_TYPE_LONGLONG; - f->flags= UNSIGNED_FLAG; + f->flags= UNSIGNED_FLAG | NOT_NULL_FLAG; f->length= MY_INT64_NUM_DECIMAL_DIGITS; } else { f->sql_type= MYSQL_TYPE_TIMESTAMP2; + f->flags= NOT_NULL_FLAG; f->length= 6; } - f->decimals= 0; if (f->check(thd)) return true; -- cgit v1.2.1 From 4c5a2e504d9c20347e202aabd3b3c299b7efedb1 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Sat, 15 Oct 2016 14:15:28 +0000 Subject: Tests: create, select_pkeycache, select_jcl6 results create: 5de65ef52df9f941ec8eea93f4801283e3d7fa05 select_pkeycache, select_jcl6: ded545be9f7a416d1d50d653ab278dd0fc7e6c5e --- mysql-test/r/create.result | 24 ++++++++++++------------ mysql-test/r/select_jcl6.result | 2 +- mysql-test/r/select_pkeycache.result | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index b0255c7457b..70037b4466e 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -1957,8 +1957,8 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `XNo` int(10) unsigned DEFAULT NULL, - `sys_trx_start` timestamp(6) NULL GENERATED AS ROW START, - `sys_trx_end` timestamp(6) NULL GENERATED AS ROW END, + `sys_trx_start` timestamp(6) NOT NULL GENERATED AS ROW START, + `sys_trx_end` timestamp(6) NOT NULL GENERATED AS ROW END, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING drop table if exists t1; @@ -2042,8 +2042,8 @@ Table Create Table t1 CREATE TABLE `t1` ( `A` int(11) DEFAULT NULL, `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, - `sys_trx_start` timestamp(6) NULL GENERATED AS ROW START, - `sys_trx_end` timestamp(6) NULL GENERATED AS ROW END, + `sys_trx_start` timestamp(6) NOT NULL GENERATED AS ROW START, + `sys_trx_end` timestamp(6) NOT NULL GENERATED AS ROW END, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING DROP TABLE t1; @@ -2056,8 +2056,8 @@ Table Create Table t1 CREATE TABLE `t1` ( `A` int(11) DEFAULT NULL, `B` int(11) DEFAULT NULL, - `sys_trx_start` timestamp(6) NULL GENERATED AS ROW START, - `sys_trx_end` timestamp(6) NULL GENERATED AS ROW END, + `sys_trx_start` timestamp(6) NOT NULL GENERATED AS ROW START, + `sys_trx_end` timestamp(6) NOT NULL GENERATED AS ROW END, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING DROP TABLE t1; @@ -2075,8 +2075,8 @@ Table Create Table t1 CREATE TABLE `t1` ( `A` int(11) DEFAULT NULL, `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, - `sys_trx_start` timestamp(6) NULL GENERATED AS ROW START, - `sys_trx_end` timestamp(6) NULL GENERATED AS ROW END, + `sys_trx_start` timestamp(6) NOT NULL GENERATED AS ROW START, + `sys_trx_end` timestamp(6) NOT NULL GENERATED AS ROW END, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING DROP TABLE t1; @@ -2089,8 +2089,8 @@ Table Create Table t1 CREATE TABLE `t1` ( `A` int(11) DEFAULT NULL, `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, - `sys_trx_start` timestamp(6) NULL GENERATED AS ROW START, - `sys_trx_end` timestamp(6) NULL GENERATED AS ROW END, + `sys_trx_start` timestamp(6) NOT NULL GENERATED AS ROW START, + `sys_trx_end` timestamp(6) NOT NULL GENERATED AS ROW END, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING DROP TABLE t1; @@ -2103,8 +2103,8 @@ Table Create Table t1 CREATE TABLE `t1` ( `A` int(11) DEFAULT NULL, `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, - `sys_trx_start` timestamp(6) NULL GENERATED AS ROW START, - `sys_trx_end` timestamp(6) NULL GENERATED AS ROW END, + `sys_trx_start` timestamp(6) NOT NULL GENERATED AS ROW START, + `sys_trx_end` timestamp(6) NOT NULL GENERATED AS ROW END, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING DROP TABLE t1; diff --git a/mysql-test/r/select_jcl6.result b/mysql-test/r/select_jcl6.result index ade583db19e..be93151ea6f 100644 --- a/mysql-test/r/select_jcl6.result +++ b/mysql-test/r/select_jcl6.result @@ -5578,7 +5578,7 @@ INSERT INTO t1(x, y) VALUES DELETE FROM t1 WHERE x = 3; DELETE FROM t1 WHERE x > 7; INSERT INTO t1(x, y) VALUES(3, 33); -SELECT @time := Sys_start FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07' WHERE x = 3 AND y = 33; +SELECT @time := Sys_start FROM t1 WHERE x = 3 AND y = 33 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; @time := Sys_start Sys_start SELECT x, y FROM t1; diff --git a/mysql-test/r/select_pkeycache.result b/mysql-test/r/select_pkeycache.result index c260e2ff333..ebcc1155fc9 100644 --- a/mysql-test/r/select_pkeycache.result +++ b/mysql-test/r/select_pkeycache.result @@ -5567,7 +5567,7 @@ INSERT INTO t1(x, y) VALUES DELETE FROM t1 WHERE x = 3; DELETE FROM t1 WHERE x > 7; INSERT INTO t1(x, y) VALUES(3, 33); -SELECT @time := Sys_start FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07' WHERE x = 3 AND y = 33; +SELECT @time := Sys_start FROM t1 WHERE x = 3 AND y = 33 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; @time := Sys_start Sys_start SELECT x, y FROM t1; -- cgit v1.2.1 From 5cf3dd79fafc4918360aa45af47054de3a1d034f Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 18 Oct 2016 08:07:22 +0000 Subject: SQL: JOIN + WHERE in SP --- sql/sql_select.cc | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 9aff4c3e731..eec6f742d9d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -681,6 +681,7 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LE && !is_prepare && !thd->stmt_arena->is_sp_execute()) { + // statement is already prepared DBUG_RETURN(0); } @@ -716,27 +717,30 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LE { if (table->table && table->table->versioned()) { - COND** dst_cond; - if (table->on_expr) + COND** dst_cond= where_expr; + if (table->saved_on_expr) // same logic as saved_where { - if (table->saved_on_expr) // same logic as saved_where + DBUG_ASSERT(thd->stmt_arena->is_sp_execute()); + if (table->on_expr) { - DBUG_ASSERT(thd->stmt_arena->is_sp_execute()); table->on_expr= table->saved_on_expr; + dst_cond= &table->on_expr; } - else if (thd->stmt_arena->is_sp_execute()) + else { - if (thd->stmt_arena->is_stmt_execute()) // SP executed second time (STMT_EXECUTED) - table->on_expr= 0; - else if (table->on_expr) // SP executed first time (STMT_INITIALIZED_FOR_SP) - table->saved_on_expr= table->on_expr->copy_andor_structure(thd); + // on_expr was moved to WHERE (see below: Add ON expression to the WHERE) + *dst_cond= and_items(thd, + *where_expr, + table->saved_on_expr); } - dst_cond= &table->on_expr; } - else + else if (table->on_expr) { - dst_cond= where_expr; + dst_cond= &table->on_expr; + if (thd->stmt_arena->state == Query_arena::STMT_INITIALIZED_FOR_SP) + table->saved_on_expr= table->on_expr->copy_andor_structure(thd); } + Field *fstart= table->table->vers_start_field(); Field *fend= table->table->vers_end_field(); -- cgit v1.2.1 From d3b737d9106c2a192379252fc6f9aaf20694dc63 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 18 Oct 2016 09:05:49 +0000 Subject: Tests: moved to dedicated versioning suite Run `mtr --suite=versioning` or `mtr versioning.` --- mysql-test/suite/versioning/common.inc | 22 + mysql-test/suite/versioning/common.opt | 1 + .../suite/versioning/r/auto_increment.result | 99 ++++ mysql-test/suite/versioning/r/create.result | 198 ++++++++ mysql-test/suite/versioning/r/delete.result | 310 ++++++++++++ mysql-test/suite/versioning/r/insert.result | 336 +++++++++++++ mysql-test/suite/versioning/r/select.result | 256 ++++++++++ mysql-test/suite/versioning/r/update.result | 519 +++++++++++++++++++++ mysql-test/suite/versioning/t/auto_increment.test | 68 +++ mysql-test/suite/versioning/t/create.test | 172 +++++++ mysql-test/suite/versioning/t/delete.test | 120 +++++ mysql-test/suite/versioning/t/insert.test | 210 +++++++++ mysql-test/suite/versioning/t/select.test | 96 ++++ mysql-test/suite/versioning/t/update.test | 267 +++++++++++ 14 files changed, 2674 insertions(+) create mode 100644 mysql-test/suite/versioning/common.inc create mode 100644 mysql-test/suite/versioning/common.opt create mode 100644 mysql-test/suite/versioning/r/auto_increment.result create mode 100644 mysql-test/suite/versioning/r/create.result create mode 100644 mysql-test/suite/versioning/r/delete.result create mode 100644 mysql-test/suite/versioning/r/insert.result create mode 100644 mysql-test/suite/versioning/r/select.result create mode 100644 mysql-test/suite/versioning/r/update.result create mode 100644 mysql-test/suite/versioning/t/auto_increment.test create mode 100644 mysql-test/suite/versioning/t/create.test create mode 100644 mysql-test/suite/versioning/t/delete.test create mode 100644 mysql-test/suite/versioning/t/insert.test create mode 100644 mysql-test/suite/versioning/t/select.test create mode 100644 mysql-test/suite/versioning/t/update.test diff --git a/mysql-test/suite/versioning/common.inc b/mysql-test/suite/versioning/common.inc new file mode 100644 index 00000000000..6306e9e9ed3 --- /dev/null +++ b/mysql-test/suite/versioning/common.inc @@ -0,0 +1,22 @@ +-- source include/have_innodb.inc + +set @@session.time_zone='+00:00'; +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; + +delimiter ~~; +create procedure if not exists verify_vtq() +begin + set @i= 0; + select + @i:= @i + 1 as No, + trx_id > 0 as A, + begin_ts > '1-1-1 0:0:0' as B, + commit_ts > begin_ts as C, + concurr_trx is null as D + from information_schema.innodb_vtq + where trx_id > @start_trx_id; + select ifnull(max(trx_id), 0) + into @start_trx_id + from information_schema.innodb_vtq; +end~~ +delimiter ;~~ diff --git a/mysql-test/suite/versioning/common.opt b/mysql-test/suite/versioning/common.opt new file mode 100644 index 00000000000..32a25eea24f --- /dev/null +++ b/mysql-test/suite/versioning/common.opt @@ -0,0 +1 @@ +--loose-innodb-vtq diff --git a/mysql-test/suite/versioning/r/auto_increment.result b/mysql-test/suite/versioning/r/auto_increment.result new file mode 100644 index 00000000000..bd1c3f9828e --- /dev/null +++ b/mysql-test/suite/versioning/r/auto_increment.result @@ -0,0 +1,99 @@ +set @@session.time_zone='+00:00'; +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +create procedure if not exists verify_vtq() +begin +set @i= 0; +select +@i:= @i + 1 as No, +trx_id > 0 as A, +begin_ts > '1-1-1 0:0:0' as B, +commit_ts > begin_ts as C, +concurr_trx is null as D +from information_schema.innodb_vtq +where trx_id > @start_trx_id; +select ifnull(max(trx_id), 0) +into @start_trx_id +from information_schema.innodb_vtq; +end~~ +create procedure test_01( +sys_type varchar(255), +engine varchar(255), +fields varchar(255)) +begin +set @str= concat(' + create table t1( + id int unsigned auto_increment primary key, + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); +prepare stmt from @str; execute stmt; drop prepare stmt; +set @str= concat(' + create table t2( + id int unsigned auto_increment primary key, + x int unsigned, + y int unsigned) + engine ', engine); +prepare stmt from @str; execute stmt; drop prepare stmt; +insert into t1(x, y) values(1, 11); +insert into t2(x, y) values(1, 11); +insert into t1(x, y) values(2, 12); +insert into t2(x, y) values(2, 12); +insert into t1(x, y) values(3, 13); +insert into t2(x, y) values(3, 13); +insert into t1(x, y) values(4, 14); +insert into t2(x, y) values(4, 14); +insert into t1(x, y) values(5, 15); +insert into t2(x, y) values(5, 15); +insert into t1(x, y) values(6, 16); +insert into t2(x, y) values(6, 16); +insert into t1(x, y) values(7, 17); +insert into t2(x, y) values(7, 17); +insert into t1(x, y) values(8, 18); +insert into t2(x, y) values(8, 18); +insert into t1(x, y) values(9, 19); +insert into t2(x, y) values(9, 19); +select t1.x = t2.x and t1.y = t2.y as A, t1.x, t1.y, t2.x, t2.y from t1 inner join t2 on t1.id = t2.id; +delete from t1 where x = 2; +delete from t2 where x = 2; +select t1.x = t2.x and t1.y = t2.y as A, t1.x, t1.y, t2.x, t2.y from t1 inner join t2 on t1.id = t2.id; +delete from t1 where x > 7; +delete from t2 where x > 7; +select t1.x = t2.x and t1.y = t2.y as A, t1.x, t1.y, t2.x, t2.y from t1 inner join t2 on t1.id = t2.id; +drop table t1; +drop table t2; +end~~ +call test_01('timestamp(6)', 'myisam', 'sys_end'); +A x y x y +1 1 11 1 11 +1 2 12 2 12 +1 3 13 3 13 +1 4 14 4 14 +1 5 15 5 15 +1 6 16 6 16 +1 7 17 7 17 +1 8 18 8 18 +1 9 19 9 19 +A x y x y +1 1 11 1 11 +1 3 13 3 13 +1 4 14 4 14 +1 5 15 5 15 +1 6 16 6 16 +1 7 17 7 17 +1 8 18 8 18 +1 9 19 9 19 +A x y x y +1 1 11 1 11 +1 3 13 3 13 +1 4 14 4 14 +1 5 15 5 15 +1 6 16 6 16 +1 7 17 7 17 +call verify_vtq; +No A B C D +drop procedure test_01; +drop procedure verify_vtq; diff --git a/mysql-test/suite/versioning/r/create.result b/mysql-test/suite/versioning/r/create.result new file mode 100644 index 00000000000..0238d189690 --- /dev/null +++ b/mysql-test/suite/versioning/r/create.result @@ -0,0 +1,198 @@ +drop table if exists t1; +create table t1 ( +XNo int unsigned, +Sys_start timestamp(6) generated always as row start, +Sys_end timestamp(6) generated always as row end, +period for system_time (Sys_start, Sys_end) +) with system versioning; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `XNo` int(10) unsigned DEFAULT NULL, + `Sys_start` timestamp(6) NOT NULL GENERATED AS ROW START, + `Sys_end` timestamp(6) NOT NULL GENERATED AS ROW END, + PERIOD FOR SYSTEM_TIME (`Sys_start`, `Sys_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +# Implicit fields test +create or replace table t1 ( +XNo int unsigned +) with system versioning; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `XNo` int(10) unsigned DEFAULT NULL, + `sys_trx_start` timestamp(6) NOT NULL GENERATED AS ROW START, + `sys_trx_end` timestamp(6) NOT NULL GENERATED AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +create or replace table t1 ( +XNo int unsigned, +Sys_start timestamp(6) generated always as row start, +Sys_start2 timestamp(6) generated always as row start, +Sys_end timestamp(6) generated always as row end, +period for system_time (Sys_start, Sys_end) +) with system versioning; +ERROR HY000: 'Generated as row start' specified more than once +create or replace table t1 ( +XNo int unsigned, +Sys_start timestamp(6) generated always as row start, +Sys_end2 timestamp(6) generated always as row end, +period for system_time (Sys_start, Sys_end) +) with system versioning; +ERROR HY000: Second column in 'period for system time' must be equal to 'generated as row end' column +create or replace table t1 ( +XNo int unsigned, +Sys_start timestamp(6) generated always as row start, +Sys_end timestamp(6) generated always as row end, +Sys_end2 timestamp(6) generated always as row end, +period for system_time (Sys_start, Sys_end) +) with system versioning; +ERROR HY000: Generated as row end specified more than once +create or replace table t1 ( +XNo int unsigned, +period for system_time (Sys_start, Sys_end) +) with system versioning; +ERROR HY000: 'Generated as row start' not specified +create or replace table t1 ( +XNo int unsigned, +Sys_start timestamp(6) generated always as row start, +Sys_end timestamp(6) generated always as row end, +Sys_end2 timestamp(6) generated always as row end, +period for system_time (Sys_start, Sys_end) +); +ERROR HY000: Generated as row end specified more than once +create or replace table t1 ( +XNo int unsigned, +Sys_start timestamp(6) generated always as row start, +Sys_end timestamp(6) generated always as row end, +period for system_time (sys_insert, sys_remove) +) with system versioning; +ERROR HY000: First column in 'period for system time' must be equal to 'generated as row start' column +create or replace table t1 ( +XNo int unsigned, +Sys_start timestamp(6) generated always as row start, +Sys_end timestamp(6) generated always as row end, +period for system_time (Sys_start, Sys_end) +); +ERROR HY000: 'With system versioning' is missing +create or replace table t1 ( +XNo int unsigned, +Sys_start timestamp(6) generated always as row start, +Sys_end timestamp(6) generated always as row end, +period for system_time (Sys_start, Sys_start) +); +ERROR HY000: 'Period for system_time' must contain two different columns +create or replace table t1 ( +XNo int unsigned, +Sys_start int generated always as row start, +Sys_end timestamp(6) generated always as row end, +period for system_time (Sys_start, Sys_end) +) with system versioning; +ERROR HY000: System start field must be of type TIMESTAMP +create or replace table t1 ( +XNo int unsigned, +Sys_start timestamp(6) generated always as row start, +Sys_end int generated always as row end, +period for system_time (Sys_start, Sys_end) +) with system versioning; +ERROR HY000: System end field must be of type TIMESTAMP +create or replace table t1 ( +XNo int unsigned, +Sys_start timestamp(6) generated always as row start, +Sys_end bigint generated always as row end, +period for system_time (Sys_start, Sys_end) +) with system versioning engine innodb; +ERROR HY000: System start field must be of type BIGINT UNSIGNED +create or replace table t1 ( +XNo int unsigned, +Sys_start bigint generated always as row start, +Sys_end bigint generated always as row end, +period for system_time (Sys_start, Sys_end) +) with system versioning engine innodb; +ERROR HY000: System start field must be of type BIGINT UNSIGNED +create or replace table t1 ( +XNo int unsigned, +Sys_start bigint unsigned generated always as row start, +Sys_end bigint generated always as row end, +period for system_time (Sys_start, Sys_end) +) with system versioning engine innodb; +ERROR HY000: System end field must be of type BIGINT UNSIGNED +create or replace table t1 ( +A int with system versioning, +B int +); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `A` int(11) DEFAULT NULL, + `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, + `sys_trx_start` timestamp(6) NOT NULL GENERATED AS ROW START, + `sys_trx_end` timestamp(6) NOT NULL GENERATED AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +create or replace table t1 ( +A int with system versioning, +B int +) with system versioning; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `A` int(11) DEFAULT NULL, + `B` int(11) DEFAULT NULL, + `sys_trx_start` timestamp(6) NOT NULL GENERATED AS ROW START, + `sys_trx_end` timestamp(6) NOT NULL GENERATED AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +create or replace table t1 ( +A int, +B int without system versioning +); +ERROR HY000: Every field specified unversioned in versioned table +create or replace table t1 ( +A int, +B int without system versioning +) with system versioning; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `A` int(11) DEFAULT NULL, + `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, + `sys_trx_start` timestamp(6) NOT NULL GENERATED AS ROW START, + `sys_trx_end` timestamp(6) NOT NULL GENERATED AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +create or replace table t1 ( +A int with system versioning, +B int without system versioning +); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `A` int(11) DEFAULT NULL, + `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, + `sys_trx_start` timestamp(6) NOT NULL GENERATED AS ROW START, + `sys_trx_end` timestamp(6) NOT NULL GENERATED AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +create or replace table t1 ( +A int with system versioning, +B int without system versioning +) with system versioning; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `A` int(11) DEFAULT NULL, + `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, + `sys_trx_start` timestamp(6) NOT NULL GENERATED AS ROW START, + `sys_trx_end` timestamp(6) NOT NULL GENERATED AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +create or replace table t1 ( +A int without system versioning +); +ERROR HY000: Every field specified unversioned in versioned table +create or replace table t1 ( +A int without system versioning +) with system versioning; +ERROR HY000: Every field specified unversioned in versioned table +drop table t1; diff --git a/mysql-test/suite/versioning/r/delete.result b/mysql-test/suite/versioning/r/delete.result new file mode 100644 index 00000000000..2d604ff3381 --- /dev/null +++ b/mysql-test/suite/versioning/r/delete.result @@ -0,0 +1,310 @@ +set @@session.time_zone='+00:00'; +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +create procedure if not exists verify_vtq() +begin +set @i= 0; +select +@i:= @i + 1 as No, +trx_id > 0 as A, +begin_ts > '1-1-1 0:0:0' as B, +commit_ts > begin_ts as C, +concurr_trx is null as D +from information_schema.innodb_vtq +where trx_id > @start_trx_id; +select ifnull(max(trx_id), 0) +into @start_trx_id +from information_schema.innodb_vtq; +end~~ +create or replace procedure test_01( +sys_type varchar(255), +engine varchar(255), +fields varchar(255)) +begin +set @str= concat(' + create or replace table t1( + XNo int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); +prepare stmt from @str; execute stmt; drop prepare stmt; +insert into t1(XNo) values(0); +insert into t1(XNo) values(1); +insert into t1(XNo) values(2); +insert into t1(XNo) values(3); +insert into t1(XNo) values(4); +insert into t1(XNo) values(5); +insert into t1(XNo) values(6); +insert into t1(XNo) values(7); +insert into t1(XNo) values(8); +insert into t1(XNo) values(9); +set @str= concat('select XNo, ', +fields, " < '2038-01-19 03:14:07' + from t1 for system_time + between timestamp '0000-0-0 0:0:0' + and timestamp '2038-01-19 04:14:07'"); +prepare stmt from @str; execute stmt; +delete from t1 where XNo = 0; +execute stmt; +delete from t1 where XNo = 1; +execute stmt; +delete from t1 where XNo > 5; +create view vt1 as select XNo from t1; +select XNo from vt1; +delete from vt1 where XNo = 3; +select XNo from vt1; +execute stmt; drop prepare stmt; +drop view vt1; +drop table t1; +end~~ +create or replace procedure test_02( +sys_type varchar(255), +engine varchar(255), +fields varchar(255)) +begin +set @str= concat('create or replace table t1 ( + x int, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); +prepare stmt from @str; execute stmt; drop prepare stmt; +insert into t1(x) values (1); +select sys_start into @sys_start from t1; +delete from t1; +select * from t1; +select x = 1 as A, sys_start = @sys_start as B, sys_end > sys_start as C +from t1 for system_time between timestamp '0-0-0' and timestamp '2038-01-19 04:14:07'; +drop table t1; +end~~ +create or replace procedure test_03( +sys_type varchar(255), +engine varchar(255), +fields varchar(255)) +begin +set @str0= concat('( + x int, + y int, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); +set @str= concat('create or replace table t1', @str0); +prepare stmt from @str; execute stmt; drop prepare stmt; +set @str= concat('create or replace table t2', @str0); +prepare stmt from @str; execute stmt; drop prepare stmt; +insert into t1(x, y) values (1, 1), (2, 2), (3, 3), (14, 4); +insert into t2(x, y) values (11, 1), (12, 2), (13, 32), (14, 4); +delete t1, t2 from t1 join t2 where t1.y = 3 and t2.y = 32; +select x as t1_x from t1; +select x as t2_x from t2; +delete t1, t2 from t1 join t2 where t1.x = t2.x; +select x as t1_x from t1; +select x as t2_x from t2; +select x as t1_x_all from t1 for system_time between timestamp '0-0-0' and timestamp '2038-01-19 04:14:07'; +select x as t2_x_all from t2 for system_time between timestamp '0-0-0' and timestamp '2038-01-19 04:14:07'; +drop table t1; +drop table t2; +end~~ +# Basic + delete from view +call test_01('timestamp(6)', 'myisam', 'sys_end'); +XNo sys_end < '2038-01-19 03:14:07' +0 0 +1 0 +2 0 +3 0 +4 0 +5 0 +6 0 +7 0 +8 0 +9 0 +XNo sys_end < '2038-01-19 03:14:07' +0 1 +1 0 +2 0 +3 0 +4 0 +5 0 +6 0 +7 0 +8 0 +9 0 +XNo sys_end < '2038-01-19 03:14:07' +0 1 +1 1 +2 0 +3 0 +4 0 +5 0 +6 0 +7 0 +8 0 +9 0 +XNo +2 +3 +4 +5 +XNo +2 +4 +5 +XNo sys_end < '2038-01-19 03:14:07' +0 1 +1 1 +2 0 +3 1 +4 0 +5 0 +6 1 +7 1 +8 1 +9 1 +call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +XNo commit_ts(sys_end) < '2038-01-19 03:14:07' +0 0 +1 0 +2 0 +3 0 +4 0 +5 0 +6 0 +7 0 +8 0 +9 0 +XNo commit_ts(sys_end) < '2038-01-19 03:14:07' +0 1 +1 0 +2 0 +3 0 +4 0 +5 0 +6 0 +7 0 +8 0 +9 0 +XNo commit_ts(sys_end) < '2038-01-19 03:14:07' +0 1 +1 1 +2 0 +3 0 +4 0 +5 0 +6 0 +7 0 +8 0 +9 0 +XNo +2 +3 +4 +5 +XNo +2 +4 +5 +XNo commit_ts(sys_end) < '2038-01-19 03:14:07' +0 1 +1 1 +2 0 +3 1 +4 0 +5 0 +6 1 +7 1 +8 1 +9 1 +call verify_vtq; +No A B C D +1 1 1 1 1 +2 1 1 1 1 +3 1 1 1 1 +4 1 1 1 1 +5 1 1 1 1 +6 1 1 1 1 +7 1 1 1 1 +8 1 1 1 1 +9 1 1 1 1 +10 1 1 1 1 +11 1 1 1 1 +12 1 1 1 1 +13 1 1 1 1 +14 1 1 1 1 +# Check sys_start, sys_end +call test_02('timestamp(6)', 'myisam', 'sys_end'); +x sys_start sys_end +A B C +1 1 1 +call test_02('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +x sys_start sys_end +A B C +1 1 1 +call verify_vtq; +No A B C D +1 1 1 1 1 +2 1 1 1 1 +# Multi-delete +call test_03('timestamp(6)', 'myisam', 'sys_end'); +t1_x +1 +2 +14 +t2_x +11 +12 +14 +t1_x +1 +2 +t2_x +11 +12 +t1_x_all +1 +2 +3 +14 +t2_x_all +11 +12 +13 +14 +call test_03('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +t1_x +1 +2 +14 +t2_x +11 +12 +14 +t1_x +1 +2 +t2_x +11 +12 +t1_x_all +1 +2 +3 +14 +t2_x_all +11 +12 +13 +14 +call verify_vtq; +No A B C D +1 1 1 1 1 +2 1 1 1 1 +3 1 1 1 1 +4 1 1 1 1 +drop procedure test_01; +drop procedure test_02; +drop procedure test_03; +drop procedure verify_vtq; diff --git a/mysql-test/suite/versioning/r/insert.result b/mysql-test/suite/versioning/r/insert.result new file mode 100644 index 00000000000..343abb7978c --- /dev/null +++ b/mysql-test/suite/versioning/r/insert.result @@ -0,0 +1,336 @@ +set @@session.time_zone='+00:00'; +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +create procedure if not exists verify_vtq() +begin +set @i= 0; +select +@i:= @i + 1 as No, +trx_id > 0 as A, +begin_ts > '1-1-1 0:0:0' as B, +commit_ts > begin_ts as C, +concurr_trx is null as D +from information_schema.innodb_vtq +where trx_id > @start_trx_id; +select ifnull(max(trx_id), 0) +into @start_trx_id +from information_schema.innodb_vtq; +end~~ +create procedure test_01( +sys_type varchar(255), +engine varchar(255), +fields varchar(255)) +begin +set @str= concat(' + create table t1( + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); +prepare stmt from @str; execute stmt; drop prepare stmt; +insert into t1(x, y) values(3, 4); +insert into t1(x, y) values(2, 3); +insert into t1 values(40, 33); +set @str= concat('select x, y, ', fields, ' from t1'); +prepare stmt from @str; execute stmt; drop prepare stmt; +drop table t1; +end~~ +create procedure test_02( +sys_type varchar(255), +engine varchar(255), +fields varchar(255)) +begin +set @str= concat(' + create table t1( + id int unsigned auto_increment primary key, + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); +prepare stmt from @str; execute stmt; drop prepare stmt; +insert into t1(x, y) values(33, 44); +insert into t1(id, x, y) values(20, 33, 44); +insert into t1 values(40, 33, 44); +set @str= concat('select id, x, y, ', fields, ' from t1'); +prepare stmt from @str; execute stmt; drop prepare stmt; +drop table t1; +end~~ +create procedure test_03( +sys_type varchar(255), +engine varchar(255), +fields varchar(255)) +begin +set @str= concat(' + create table t1( + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); +prepare stmt from @str; execute stmt; drop prepare stmt; +create view vt1_1 as select x, y from t1; +create view vt1_2 as select x, y, sys_end from t1; +insert into t1(x, y) values(8001, 9001); +insert into vt1_1(x, y) values(1001, 2001); +insert into vt1_1 values(1002, 2002); +insert into vt1_2(x, y) values(3001, 4001); +set @str= concat('select x, y, ', fields, ' from t1'); +prepare stmt from @str; execute stmt; drop prepare stmt; +select x, y from vt1_1; +set @str= concat('select x, y, ', fields, ' from vt1_2'); +prepare stmt from @str; execute stmt; drop prepare stmt; +end~~ +create procedure test_04( +sys_type varchar(255), +engine varchar(255), +fields varchar(255)) +begin +set @str= concat(' + create table t1( + id bigint primary key, + a int, + b int) + with system versioning + engine ', engine); +prepare stmt from @str; execute stmt; drop prepare stmt; +insert into t1 values(1, 1, 1); +select sys_trx_start, sys_trx_end from t1 into @sys_start, @sys_end; +select id, a, b from t1; +insert into t1 values(2, 2, 2); +select id, a, b, sys_trx_start > @sys_start as C, sys_trx_end = @sys_end as D from t1 where id = 2; +drop table t1; +end~~ +create procedure test_05( +sys_type varchar(255), +engine varchar(255), +fields varchar(255)) +begin +set @str= concat('( + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); +set @str2= concat('create table t1', @str); +prepare stmt from @str2; execute stmt; drop prepare stmt; +set @str2= concat('create table t2', @str); +prepare stmt from @str2; execute stmt; drop prepare stmt; +insert into t1(x, y) values +(1, 1000), +(2, 2000), +(3, 3000), +(4, 4000), +(5, 5000), +(6, 6000), +(7, 7000), +(8, 8000), +(9, 9000); +delete from t1 where x >= 1; +insert into t1(x, y) values +(1, 1001), +(2, 2001), +(3, 3001), +(4, 4001), +(5, 5001), +(6, 6001), +(7, 7001), +(8, 8001), +(9, 9001); +insert into t2 select x, y from t1 for system_time between timestamp '0000-0-0 0:0:0' and timestamp '9999-1-1 0:0:0'; +select x, y from t1; +select x, y from t2; +drop table t1; +drop table t2; +end~~ +call test_01('timestamp(6)', 'myisam', 'sys_end'); +x y sys_end +3 4 2038-01-19 03:14:07.000000 +2 3 2038-01-19 03:14:07.000000 +40 33 2038-01-19 03:14:07.000000 +call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +x y commit_ts(sys_end) +3 4 2038-01-19 03:14:07.000000 +2 3 2038-01-19 03:14:07.000000 +40 33 2038-01-19 03:14:07.000000 +call test_02('timestamp(6)', 'myisam', 'sys_end'); +id x y sys_end +1 33 44 2038-01-19 03:14:07.000000 +20 33 44 2038-01-19 03:14:07.000000 +40 33 44 2038-01-19 03:14:07.000000 +call test_02('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +id x y commit_ts(sys_end) +1 33 44 2038-01-19 03:14:07.000000 +20 33 44 2038-01-19 03:14:07.000000 +40 33 44 2038-01-19 03:14:07.000000 +call test_03('timestamp(6)', 'myisam', 'sys_end'); +x y sys_end +8001 9001 2038-01-19 03:14:07.000000 +1001 2001 2038-01-19 03:14:07.000000 +1002 2002 2038-01-19 03:14:07.000000 +3001 4001 2038-01-19 03:14:07.000000 +x y +8001 9001 +1001 2001 +1002 2002 +3001 4001 +x y sys_end +8001 9001 2038-01-19 03:14:07.000000 +1001 2001 2038-01-19 03:14:07.000000 +1002 2002 2038-01-19 03:14:07.000000 +3001 4001 2038-01-19 03:14:07.000000 +insert into t1(x, y, sys_end) values(8001, 9001, '2015-1-1 1:1:1'); +ERROR HY000: Generated field for System Versioning cannot be set by user +insert into vt1_2 values(3002, 4002, '2015-2-2 2:2:2'); +ERROR HY000: Generated field for System Versioning cannot be set by user +drop table t1; +drop view vt1_1; +drop view vt1_2; +call test_03('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +x y commit_ts(sys_end) +8001 9001 2038-01-19 03:14:07.000000 +1001 2001 2038-01-19 03:14:07.000000 +1002 2002 2038-01-19 03:14:07.000000 +3001 4001 2038-01-19 03:14:07.000000 +x y +8001 9001 +1001 2001 +1002 2002 +3001 4001 +x y commit_ts(sys_end) +8001 9001 2038-01-19 03:14:07.000000 +1001 2001 2038-01-19 03:14:07.000000 +1002 2002 2038-01-19 03:14:07.000000 +3001 4001 2038-01-19 03:14:07.000000 +insert into t1(x, y, sys_end) values(8001, 9001, 1111111); +ERROR HY000: Generated field for System Versioning cannot be set by user +insert into vt1_2 values(3002, 4002, 2222222); +ERROR HY000: Generated field for System Versioning cannot be set by user +drop table t1; +drop view vt1_1; +drop view vt1_2; +call test_04('timestamp(6)', 'myisam', 'sys_end'); +id a b +1 1 1 +id a b C D +2 2 2 1 1 +call test_04('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +id a b +1 1 1 +id a b C D +2 2 2 1 1 +call test_05('timestamp(6)', 'myisam', 'sys_end'); +x y +1 1001 +2 2001 +3 3001 +4 4001 +5 5001 +6 6001 +7 7001 +8 8001 +9 9001 +x y +1 1000 +2 2000 +3 3000 +4 4000 +5 5000 +6 6000 +7 7000 +8 8000 +9 9000 +1 1001 +2 2001 +3 3001 +4 4001 +5 5001 +6 6001 +7 7001 +8 8001 +9 9001 +call test_05('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +x y +1 1001 +2 2001 +3 3001 +4 4001 +5 5001 +6 6001 +7 7001 +8 8001 +9 9001 +x y +1 1000 +2 2000 +3 3000 +4 4000 +5 5000 +6 6000 +7 7000 +8 8000 +9 9000 +1 1001 +2 2001 +3 3001 +4 4001 +5 5001 +6 6001 +7 7001 +8 8001 +9 9001 +call verify_vtq; +No A B C D +1 1 1 1 1 +2 1 1 1 1 +3 1 1 1 1 +4 1 1 1 1 +5 1 1 1 1 +6 1 1 1 1 +7 1 1 1 1 +8 1 1 1 1 +9 1 1 1 1 +10 1 1 1 1 +11 1 1 1 1 +12 1 1 1 1 +13 1 1 1 1 +14 1 1 1 1 +15 1 1 1 1 +16 1 1 1 1 +create table t1( +x int unsigned, +sys_start bigint unsigned generated always as row start, +sys_end bigint unsigned generated always as row end, +period for system_time (sys_start, sys_end)) +with system versioning engine=innodb; +create table t2(x int unsigned) engine=innodb; +start transaction; +insert into t1(x) values(1); +commit; +call verify_vtq; +No A B C D +1 1 1 1 1 +start transaction; +insert into t2(x) values(1); +savepoint a; +insert into t1(x) values(1); +rollback to a; +commit; +call verify_vtq; +No A B C D +drop table t1; +drop table t2; +drop procedure test_01; +drop procedure test_02; +drop procedure test_03; +drop procedure test_04; +drop procedure test_05; +drop procedure verify_vtq; diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result new file mode 100644 index 00000000000..a691019c80c --- /dev/null +++ b/mysql-test/suite/versioning/r/select.result @@ -0,0 +1,256 @@ +set @@session.time_zone='+00:00'; +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +create procedure if not exists verify_vtq() +begin +set @i= 0; +select +@i:= @i + 1 as No, +trx_id > 0 as A, +begin_ts > '1-1-1 0:0:0' as B, +commit_ts > begin_ts as C, +concurr_trx is null as D +from information_schema.innodb_vtq +where trx_id > @start_trx_id; +select ifnull(max(trx_id), 0) +into @start_trx_id +from information_schema.innodb_vtq; +end~~ +create procedure test_01( +sys_type varchar(255), +engine varchar(255), +fields varchar(255)) +begin +set @str= concat(' + create table t1( + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); +prepare stmt from @str; execute stmt; drop prepare stmt; +insert into t1 (x, y) values +(0, 100), +(1, 101), +(2, 102), +(3, 103), +(4, 104), +(5, 105), +(6, 106), +(7, 107), +(8, 108), +(9, 109); +set @t0= now(6); +delete from t1 where x = 3; +delete from t1 where x > 7; +insert into t1(x, y) values(3, 33); +set @str= concat('select ', fields, ' from t1 where x = 3 and y = 33 into @t1'); +prepare stmt from @str; execute stmt; drop prepare stmt; +select x, y from t1; +select x as AS_OF_x, y from t1 for system_time as of timestamp @t0; +select x as FROM_TO_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; +select x as BETWEEN_AND_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; +drop table t1; +end~~ +create or replace procedure test_02( +sys_type varchar(255), +engine varchar(255), +fields varchar(255)) +begin +set @str0= concat('( + x int, + y int, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); +set @str= concat('create or replace table t1', @str0); +prepare stmt from @str; execute stmt; drop prepare stmt; +set @str= concat('create or replace table t2', @str0); +prepare stmt from @str; execute stmt; drop prepare stmt; +insert into t1 values (1, 1), (1, 2), (1, 3), (4, 4), (5, 5); +insert into t2 values (1, 2), (2, 1), (3, 1); +set @t0= now(6); +select t1.x as IJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x; +select t1.x as LJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x; +select t1.x as RJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x; +delete from t1; +delete from t2; +select t1.x as IJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x +for system_time as of timestamp @t0; +select t1.x as LJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x +for system_time as of timestamp @t0; +select t1.x as RJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x +for system_time as of timestamp @t0; +drop table t1; +drop table t2; +end~~ +call test_01('timestamp(6)', 'myisam', 'sys_start'); +x y +0 100 +1 101 +2 102 +4 104 +5 105 +6 106 +7 107 +3 33 +AS_OF_x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +FROM_TO_x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +BETWEEN_AND_x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +3 33 +call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_start)'); +x y +0 100 +1 101 +2 102 +4 104 +5 105 +6 106 +7 107 +3 33 +AS_OF_x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +FROM_TO_x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +BETWEEN_AND_x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +3 33 +call test_02('timestamp(6)', 'myisam', 'sys_start'); +IJ1_x1 y1 x2 y2 +1 1 1 2 +1 2 1 2 +1 3 1 2 +LJ1_x1 y1 x2 y2 +1 1 1 2 +1 2 1 2 +1 3 1 2 +4 4 NULL NULL +5 5 NULL NULL +RJ1_x1 y1 x2 y2 +1 1 1 2 +1 2 1 2 +1 3 1 2 +NULL NULL 2 1 +NULL NULL 3 1 +IJ2_x1 y1 x2 y2 +1 1 1 2 +1 2 1 2 +1 3 1 2 +LJ2_x1 y1 x2 y2 +1 1 1 2 +1 2 1 2 +1 3 1 2 +4 4 NULL NULL +5 5 NULL NULL +RJ2_x1 y1 x2 y2 +1 1 1 2 +1 2 1 2 +1 3 1 2 +NULL NULL 2 1 +NULL NULL 3 1 +call test_02('bigint unsigned', 'innodb', 'commit_ts(sys_start)'); +IJ1_x1 y1 x2 y2 +1 1 1 2 +1 2 1 2 +1 3 1 2 +LJ1_x1 y1 x2 y2 +1 1 1 2 +1 2 1 2 +1 3 1 2 +4 4 NULL NULL +5 5 NULL NULL +RJ1_x1 y1 x2 y2 +1 1 1 2 +1 2 1 2 +1 3 1 2 +NULL NULL 2 1 +NULL NULL 3 1 +IJ2_x1 y1 x2 y2 +1 1 1 2 +1 2 1 2 +1 3 1 2 +LJ2_x1 y1 x2 y2 +1 1 1 2 +1 2 1 2 +1 3 1 2 +4 4 NULL NULL +5 5 NULL NULL +RJ2_x1 y1 x2 y2 +1 1 1 2 +1 2 1 2 +1 3 1 2 +NULL NULL 2 1 +NULL NULL 3 1 +call verify_vtq; +No A B C D +1 1 1 1 1 +2 1 1 1 1 +3 1 1 1 1 +4 1 1 1 1 +5 1 1 1 1 +6 1 1 1 1 +7 1 1 1 1 +8 1 1 1 1 +drop procedure test_01; +drop procedure test_02; +drop procedure verify_vtq; diff --git a/mysql-test/suite/versioning/r/update.result b/mysql-test/suite/versioning/r/update.result new file mode 100644 index 00000000000..06fb2186d7d --- /dev/null +++ b/mysql-test/suite/versioning/r/update.result @@ -0,0 +1,519 @@ +set @@session.time_zone='+00:00'; +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +create procedure if not exists verify_vtq() +begin +set @i= 0; +select +@i:= @i + 1 as No, +trx_id > 0 as A, +begin_ts > '1-1-1 0:0:0' as B, +commit_ts > begin_ts as C, +concurr_trx is null as D +from information_schema.innodb_vtq +where trx_id > @start_trx_id; +select ifnull(max(trx_id), 0) +into @start_trx_id +from information_schema.innodb_vtq; +end~~ +create procedure test_01( +sys_type varchar(255), +engine varchar(255), +fields varchar(255)) +begin +set @str= concat(' + create table t1( + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); +prepare stmt from @str; execute stmt; drop prepare stmt; +insert into t1(x, y) values +(1, 1000), +(2, 2000), +(3, 3000), +(4, 4000), +(5, 5000), +(6, 6000), +(7, 7000), +(8, 8000), +(9, 9000); +select x, y from t1; +update t1 set y = y + 1 where x > 7; +select x, y from t1; +select x, y from t1 for system_time +between timestamp '0000-0-0 0:0:0' + and timestamp '2038-01-19 04:14:07'; +drop table t1; +end~~ +create procedure test_02( +sys_type varchar(255), +engine varchar(255), +fields varchar(255)) +begin +set @str= concat(' + create table t1 ( + id bigint primary key, + a int, + b int without system versioning) + with system versioning + engine ', engine); +prepare stmt from @str; execute stmt; drop prepare stmt; +insert into t1 values(1, 1, 1); +set @ins_t= now(6); +select sys_trx_start into @tmp1 from t1; +update t1 set a=11, b=11 where id=1; +select @tmp1 < sys_trx_start, a, b from t1; +select sys_trx_start into @tmp1 from t1; +update t1 set b=1 where id=1; +select @tmp1 = sys_trx_start, b from t1; +drop table t1; +end~~ +create procedure test_03( +sys_type varchar(255), +engine varchar(255), +fields varchar(255)) +begin +set @str= concat(' + create table t1 ( + x int, + y int) + with system versioning + engine ', engine); +prepare stmt from @str; execute stmt; drop prepare stmt; +insert into t1 (x, y) values (1, 1), (2, 1), (3, 1); +start transaction; +update t1 set y= y + 1 where x = 3; +update t1 set y= y + 1 where x = 3; +commit; +select x, y from t1 for system_time +between timestamp '0000-0-0 0:0:0' + and timestamp '2038-01-19 04:14:07'; +drop table t1; +end~~ +create procedure test_04( +sys_type varchar(255), +engine varchar(255), +fields varchar(255)) +begin +set @str= concat(' + create table t1 ( + id int primary key auto_increment, + x int) + with system versioning + engine ', engine); +prepare stmt from @str; execute stmt; drop prepare stmt; +set @t0= now(6); +insert into t1 (x) values (1); +set @t1= now(6); +update t1 set x= 2 where id = 1; +set @t2= now(6); +update t1 set x= 3 where id = 1; +select x from t1 for system_time as of timestamp @t0; +select x from t1 for system_time as of timestamp @t1; +select x from t1 for system_time as of timestamp @t2; +select x from t1 for system_time as of timestamp now(6); +drop table t1; +end~~ +create procedure test_05( +sys_type varchar(255), +engine varchar(255), +fields varchar(255)) +begin +set @str= concat(' + create table t1( + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end), + primary key(x, y)) + with system versioning + engine ', engine); +prepare stmt from @str; execute stmt; drop prepare stmt; +insert into t1(x, y) values +(1, 1000), +(2, 2000), +(3, 3000), +(4, 4000), +(5, 5000), +(6, 6000), +(7, 7000), +(8, 8000), +(9, 9000); +insert into t1(x, y) values(3, 3000) on duplicate key update y = y+1; +insert into t1(x, y) values(4, 4000) on duplicate key update y = y+1; +insert into t1(x, y) values(4, 4001) on duplicate key update y = y+1; +insert into t1(x, y) values(4, 4444) on duplicate key update y = y+1; +select x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp '9999-1-1 0:0:0'; +select x, y from t1; +drop table t1; +end~~ +create procedure test_06( +sys_type varchar(255), +engine varchar(255), +fields varchar(255)) +begin +set @str= concat('( + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); +set @str2= concat('create table t1', @str); +prepare stmt from @str2; execute stmt; drop prepare stmt; +set @str2= concat('create table t2', @str); +prepare stmt from @str2; execute stmt; drop prepare stmt; +insert into t1(x, y) values +(1, 1000), +(2, 2000), +(3, 3000), +(4, 4000), +(5, 5000), +(6, 6000), +(7, 7000), +(8, 8000), +(9, 9000); +insert into t2(x, y) values +(1, 1010), +(2, 2010), +(3, 3010), +(4, 4010), +(5, 5010), +(6, 6010), +(7, 7010), +(8, 8010), +(9, 9010); +update t1, t2 set t1.y = t1.x + t1.y, t2.y = t2.x + t2.y where t1.x > 7 and t2.x < 7; +select x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp '9999-1-1 0:0:0'; +select x, y from t1; +select x, y from t2 for system_time between timestamp '0-0-0 0:0:0' and timestamp '9999-1-1 0:0:0'; +select x, y from t2; +drop table t1; +drop table t2; +end~~ +create procedure test_07( +sys_type varchar(255), +engine varchar(255), +fields varchar(255)) +begin +set @str= concat('( + id bigint primary key, + name varchar(128) with system versioning, + salary bigint) + engine ', engine); +set @str2= concat('create table t1', @str); +prepare stmt from @str2; execute stmt; drop prepare stmt; +set @str2= concat('create table t2', @str); +prepare stmt from @str2; execute stmt; drop prepare stmt; +insert into t1 values (1, "Jeremy", 3000); +insert into t2 values (1, "Jeremy", 4000); +select sys_trx_start into @tmp1 from t1; +select sys_trx_start into @tmp2 from t2; +update t1, t2 set t1.name= "Jerry", t2.name= "Jerry" where t1.id = t2.id and t1.name = "Jeremy"; +select @tmp1 < sys_trx_start as A1, name from t1; +select @tmp2 < sys_trx_start as A2, name from t2; +select sys_trx_start into @tmp1 from t1; +select sys_trx_start into @tmp2 from t2; +update t1, t2 set t1.salary= 2500, t2.salary= 2500 where t1.id = t2.id and t1.name = "Jerry"; +select @tmp1 = sys_trx_start as B1, salary from t1; +select @tmp2 = sys_trx_start as B2, salary from t2; +drop table t1; +drop table t2; +end~~ +call test_01('timestamp(6)', 'myisam', 'sys_end'); +x y +1 1000 +2 2000 +3 3000 +4 4000 +5 5000 +6 6000 +7 7000 +8 8000 +9 9000 +x y +1 1000 +2 2000 +3 3000 +4 4000 +5 5000 +6 6000 +7 7000 +8 8001 +9 9001 +x y +1 1000 +2 2000 +3 3000 +4 4000 +5 5000 +6 6000 +7 7000 +8 8001 +9 9001 +8 8000 +9 9000 +call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +x y +1 1000 +2 2000 +3 3000 +4 4000 +5 5000 +6 6000 +7 7000 +8 8000 +9 9000 +x y +1 1000 +2 2000 +3 3000 +4 4000 +5 5000 +6 6000 +7 7000 +8 8001 +9 9001 +x y +1 1000 +2 2000 +3 3000 +4 4000 +5 5000 +6 6000 +7 7000 +8 8001 +9 9001 +8 8000 +9 9000 +call test_02('timestamp(6)', 'myisam', 'sys_end'); +@tmp1 < sys_trx_start a b +1 11 11 +@tmp1 = sys_trx_start b +1 1 +call test_02('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +@tmp1 < sys_trx_start a b +1 11 11 +@tmp1 = sys_trx_start b +0 1 +call test_03('timestamp(6)', 'myisam', 'sys_end'); +x y +1 1 +2 1 +3 3 +3 1 +3 2 +call test_03('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +x y +1 1 +2 1 +3 3 +3 1 +call test_04('timestamp(6)', 'myisam', 'sys_end'); +x +x +1 +x +2 +x +3 +call test_04('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +x +x +1 +x +2 +x +3 +call test_05('timestamp(6)', 'myisam', 'sys_end'); +x y +1 1000 +2 2000 +3 3001 +4 4002 +5 5000 +6 6000 +7 7000 +8 8000 +9 9000 +3 3000 +4 4000 +4 4001 +4 4444 +x y +1 1000 +2 2000 +3 3001 +4 4002 +4 4444 +5 5000 +6 6000 +7 7000 +8 8000 +9 9000 +call test_05('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +x y +1 1000 +2 2000 +3 3000 +3 3001 +4 4000 +4 4001 +4 4002 +4 4444 +5 5000 +6 6000 +7 7000 +8 8000 +9 9000 +x y +1 1000 +2 2000 +3 3001 +4 4002 +4 4444 +5 5000 +6 6000 +7 7000 +8 8000 +9 9000 +call test_06('timestamp(6)', 'myisam', 'sys_end'); +x y +1 1000 +2 2000 +3 3000 +4 4000 +5 5000 +6 6000 +7 7000 +8 8008 +9 9009 +8 8000 +9 9000 +x y +1 1000 +2 2000 +3 3000 +4 4000 +5 5000 +6 6000 +7 7000 +8 8008 +9 9009 +x y +1 1011 +2 2012 +3 3013 +4 4014 +5 5015 +6 6016 +7 7010 +8 8010 +9 9010 +1 1010 +2 2010 +3 3010 +4 4010 +5 5010 +6 6010 +x y +1 1011 +2 2012 +3 3013 +4 4014 +5 5015 +6 6016 +7 7010 +8 8010 +9 9010 +call test_06('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +x y +1 1000 +2 2000 +3 3000 +4 4000 +5 5000 +6 6000 +7 7000 +8 8008 +9 9009 +8 8000 +9 9000 +x y +1 1000 +2 2000 +3 3000 +4 4000 +5 5000 +6 6000 +7 7000 +8 8008 +9 9009 +x y +1 1011 +2 2012 +3 3013 +4 4014 +5 5015 +6 6016 +7 7010 +8 8010 +9 9010 +1 1010 +2 2010 +3 3010 +4 4010 +5 5010 +6 6010 +x y +1 1011 +2 2012 +3 3013 +4 4014 +5 5015 +6 6016 +7 7010 +8 8010 +9 9010 +call test_07('timestamp(6)', 'myisam', 'sys_end'); +A1 name +1 Jerry +A2 name +1 Jerry +B1 salary +1 2500 +B2 salary +1 2500 +call verify_vtq; +No A B C D +1 1 1 1 1 +2 1 1 1 1 +3 1 1 1 1 +4 1 1 1 1 +5 1 1 1 1 +6 1 1 1 1 +7 1 1 1 1 +8 1 1 1 1 +9 1 1 1 1 +10 1 1 1 1 +11 1 1 1 1 +12 1 1 1 1 +13 1 1 1 1 +14 1 1 1 1 +15 1 1 1 1 +16 1 1 1 1 +17 1 1 1 1 +18 1 1 1 1 +drop procedure test_01; +drop procedure test_02; +drop procedure test_03; +drop procedure test_04; +drop procedure test_05; +drop procedure test_06; +drop procedure test_07; +drop procedure verify_vtq; diff --git a/mysql-test/suite/versioning/t/auto_increment.test b/mysql-test/suite/versioning/t/auto_increment.test new file mode 100644 index 00000000000..4872428ff7d --- /dev/null +++ b/mysql-test/suite/versioning/t/auto_increment.test @@ -0,0 +1,68 @@ +-- source suite/versioning/common.inc + +delimiter ~~; +create procedure test_01( + sys_type varchar(255), + engine varchar(255), + fields varchar(255)) +begin + set @str= concat(' + create table t1( + id int unsigned auto_increment primary key, + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); + prepare stmt from @str; execute stmt; drop prepare stmt; + + set @str= concat(' + create table t2( + id int unsigned auto_increment primary key, + x int unsigned, + y int unsigned) + engine ', engine); + prepare stmt from @str; execute stmt; drop prepare stmt; + + insert into t1(x, y) values(1, 11); + insert into t2(x, y) values(1, 11); + insert into t1(x, y) values(2, 12); + insert into t2(x, y) values(2, 12); + insert into t1(x, y) values(3, 13); + insert into t2(x, y) values(3, 13); + insert into t1(x, y) values(4, 14); + insert into t2(x, y) values(4, 14); + insert into t1(x, y) values(5, 15); + insert into t2(x, y) values(5, 15); + insert into t1(x, y) values(6, 16); + insert into t2(x, y) values(6, 16); + insert into t1(x, y) values(7, 17); + insert into t2(x, y) values(7, 17); + insert into t1(x, y) values(8, 18); + insert into t2(x, y) values(8, 18); + insert into t1(x, y) values(9, 19); + insert into t2(x, y) values(9, 19); + + select t1.x = t2.x and t1.y = t2.y as A, t1.x, t1.y, t2.x, t2.y from t1 inner join t2 on t1.id = t2.id; + delete from t1 where x = 2; + delete from t2 where x = 2; + + select t1.x = t2.x and t1.y = t2.y as A, t1.x, t1.y, t2.x, t2.y from t1 inner join t2 on t1.id = t2.id; + delete from t1 where x > 7; + delete from t2 where x > 7; + + select t1.x = t2.x and t1.y = t2.y as A, t1.x, t1.y, t2.x, t2.y from t1 inner join t2 on t1.id = t2.id; + drop table t1; + drop table t2; +end~~ +delimiter ;~~ + +call test_01('timestamp(6)', 'myisam', 'sys_end'); +# Issue #52 +# call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call verify_vtq; + +drop procedure test_01; +drop procedure verify_vtq; diff --git a/mysql-test/suite/versioning/t/create.test b/mysql-test/suite/versioning/t/create.test new file mode 100644 index 00000000000..098f71087dc --- /dev/null +++ b/mysql-test/suite/versioning/t/create.test @@ -0,0 +1,172 @@ +-- source include/have_innodb.inc + +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 ( + XNo int unsigned, + Sys_start timestamp(6) generated always as row start, + Sys_end timestamp(6) generated always as row end, + period for system_time (Sys_start, Sys_end) +) with system versioning; +show create table t1; + +--echo # Implicit fields test +create or replace table t1 ( + XNo int unsigned +) with system versioning; +show create table t1; + +--error ER_SYS_START_MORE_THAN_ONCE +create or replace table t1 ( + XNo int unsigned, + Sys_start timestamp(6) generated always as row start, + Sys_start2 timestamp(6) generated always as row start, + Sys_end timestamp(6) generated always as row end, + period for system_time (Sys_start, Sys_end) +) with system versioning; + +--error ER_PERIOD_FOR_SYSTEM_TIME_CONTAINS_WRONG_END_COLUMN +create or replace table t1 ( + XNo int unsigned, + Sys_start timestamp(6) generated always as row start, + Sys_end2 timestamp(6) generated always as row end, + period for system_time (Sys_start, Sys_end) +) with system versioning; + +--error ER_SYS_END_MORE_THAN_ONCE +create or replace table t1 ( + XNo int unsigned, + Sys_start timestamp(6) generated always as row start, + Sys_end timestamp(6) generated always as row end, + Sys_end2 timestamp(6) generated always as row end, + period for system_time (Sys_start, Sys_end) +) with system versioning; + +--error ER_SYS_START_NOT_SPECIFIED +create or replace table t1 ( + XNo int unsigned, + period for system_time (Sys_start, Sys_end) +) with system versioning; + +--error ER_SYS_END_MORE_THAN_ONCE +create or replace table t1 ( + XNo int unsigned, + Sys_start timestamp(6) generated always as row start, + Sys_end timestamp(6) generated always as row end, + Sys_end2 timestamp(6) generated always as row end, + period for system_time (Sys_start, Sys_end) +); + +--error ER_PERIOD_FOR_SYSTEM_TIME_CONTAINS_WRONG_START_COLUMN +create or replace table t1 ( + XNo int unsigned, + Sys_start timestamp(6) generated always as row start, + Sys_end timestamp(6) generated always as row end, + period for system_time (sys_insert, sys_remove) +) with system versioning; + +--error ER_MISSING_WITH_SYSTEM_VERSIONING +create or replace table t1 ( + XNo int unsigned, + Sys_start timestamp(6) generated always as row start, + Sys_end timestamp(6) generated always as row end, + period for system_time (Sys_start, Sys_end) +); + +--error ER_SYS_START_AND_SYS_END_SAME +create or replace table t1 ( + XNo int unsigned, + Sys_start timestamp(6) generated always as row start, + Sys_end timestamp(6) generated always as row end, + period for system_time (Sys_start, Sys_start) +); + +--error ER_SYS_START_FIELD_MUST_BE_TIMESTAMP +create or replace table t1 ( + XNo int unsigned, + Sys_start int generated always as row start, + Sys_end timestamp(6) generated always as row end, + period for system_time (Sys_start, Sys_end) +) with system versioning; + +--error ER_SYS_END_FIELD_MUST_BE_TIMESTAMP +create or replace table t1 ( + XNo int unsigned, + Sys_start timestamp(6) generated always as row start, + Sys_end int generated always as row end, + period for system_time (Sys_start, Sys_end) +) with system versioning; + +--error ER_SYS_START_FIELD_MUST_BE_BIGINT +create or replace table t1 ( + XNo int unsigned, + Sys_start timestamp(6) generated always as row start, + Sys_end bigint generated always as row end, + period for system_time (Sys_start, Sys_end) +) with system versioning engine innodb; + +--error ER_SYS_START_FIELD_MUST_BE_BIGINT +create or replace table t1 ( + XNo int unsigned, + Sys_start bigint generated always as row start, + Sys_end bigint generated always as row end, + period for system_time (Sys_start, Sys_end) +) with system versioning engine innodb; + +--error ER_SYS_END_FIELD_MUST_BE_BIGINT +create or replace table t1 ( + XNo int unsigned, + Sys_start bigint unsigned generated always as row start, + Sys_end bigint generated always as row end, + period for system_time (Sys_start, Sys_end) +) with system versioning engine innodb; + +create or replace table t1 ( + A int with system versioning, + B int +); +show create table t1; + +create or replace table t1 ( + A int with system versioning, + B int +) with system versioning; +show create table t1; + +--error ER_NO_VERSIONED_FIELDS_IN_VERSIONED_TABLE +create or replace table t1 ( + A int, + B int without system versioning +); + +create or replace table t1 ( + A int, + B int without system versioning +) with system versioning; +show create table t1; + +create or replace table t1 ( + A int with system versioning, + B int without system versioning +); +show create table t1; + +create or replace table t1 ( + A int with system versioning, + B int without system versioning +) with system versioning; +show create table t1; + +--error ER_NO_VERSIONED_FIELDS_IN_VERSIONED_TABLE +create or replace table t1 ( + A int without system versioning +); + +--error ER_NO_VERSIONED_FIELDS_IN_VERSIONED_TABLE +create or replace table t1 ( + A int without system versioning +) with system versioning; + +drop table t1; diff --git a/mysql-test/suite/versioning/t/delete.test b/mysql-test/suite/versioning/t/delete.test new file mode 100644 index 00000000000..48bec973cee --- /dev/null +++ b/mysql-test/suite/versioning/t/delete.test @@ -0,0 +1,120 @@ +-- source suite/versioning/common.inc + +delimiter ~~; +create or replace procedure test_01( + sys_type varchar(255), + engine varchar(255), + fields varchar(255)) +begin + set @str= concat(' + create or replace table t1( + XNo int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); + prepare stmt from @str; execute stmt; drop prepare stmt; + insert into t1(XNo) values(0); + insert into t1(XNo) values(1); + insert into t1(XNo) values(2); + insert into t1(XNo) values(3); + insert into t1(XNo) values(4); + insert into t1(XNo) values(5); + insert into t1(XNo) values(6); + insert into t1(XNo) values(7); + insert into t1(XNo) values(8); + insert into t1(XNo) values(9); + set @str= concat('select XNo, ', + fields, " < '2038-01-19 03:14:07' + from t1 for system_time + between timestamp '0000-0-0 0:0:0' + and timestamp '2038-01-19 04:14:07'"); + prepare stmt from @str; execute stmt; + delete from t1 where XNo = 0; + execute stmt; + delete from t1 where XNo = 1; + execute stmt; + delete from t1 where XNo > 5; + create view vt1 as select XNo from t1; + select XNo from vt1; + delete from vt1 where XNo = 3; + select XNo from vt1; + execute stmt; drop prepare stmt; + drop view vt1; + drop table t1; +end~~ + +create or replace procedure test_02( + sys_type varchar(255), + engine varchar(255), + fields varchar(255)) +begin + set @str= concat('create or replace table t1 ( + x int, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); + prepare stmt from @str; execute stmt; drop prepare stmt; + insert into t1(x) values (1); + select sys_start into @sys_start from t1; + delete from t1; + select * from t1; + select x = 1 as A, sys_start = @sys_start as B, sys_end > sys_start as C + from t1 for system_time between timestamp '0-0-0' and timestamp '2038-01-19 04:14:07'; + drop table t1; +end~~ + +create or replace procedure test_03( + sys_type varchar(255), + engine varchar(255), + fields varchar(255)) +begin + set @str0= concat('( + x int, + y int, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); + set @str= concat('create or replace table t1', @str0); + prepare stmt from @str; execute stmt; drop prepare stmt; + set @str= concat('create or replace table t2', @str0); + prepare stmt from @str; execute stmt; drop prepare stmt; + insert into t1(x, y) values (1, 1), (2, 2), (3, 3), (14, 4); + insert into t2(x, y) values (11, 1), (12, 2), (13, 32), (14, 4); + delete t1, t2 from t1 join t2 where t1.y = 3 and t2.y = 32; + select x as t1_x from t1; + select x as t2_x from t2; + delete t1, t2 from t1 join t2 where t1.x = t2.x; + select x as t1_x from t1; + select x as t2_x from t2; + select x as t1_x_all from t1 for system_time between timestamp '0-0-0' and timestamp '2038-01-19 04:14:07'; + select x as t2_x_all from t2 for system_time between timestamp '0-0-0' and timestamp '2038-01-19 04:14:07'; + drop table t1; + drop table t2; +end~~ +delimiter ;~~ + +--echo # Basic + delete from view +call test_01('timestamp(6)', 'myisam', 'sys_end'); +call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call verify_vtq; + +--echo # Check sys_start, sys_end +call test_02('timestamp(6)', 'myisam', 'sys_end'); +call test_02('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call verify_vtq; + +--echo # Multi-delete +call test_03('timestamp(6)', 'myisam', 'sys_end'); +call test_03('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call verify_vtq; + +drop procedure test_01; +drop procedure test_02; +drop procedure test_03; +drop procedure verify_vtq; diff --git a/mysql-test/suite/versioning/t/insert.test b/mysql-test/suite/versioning/t/insert.test new file mode 100644 index 00000000000..e13a5d0516a --- /dev/null +++ b/mysql-test/suite/versioning/t/insert.test @@ -0,0 +1,210 @@ +-- source suite/versioning/common.inc + +delimiter ~~; +create procedure test_01( + sys_type varchar(255), + engine varchar(255), + fields varchar(255)) +begin + set @str= concat(' + create table t1( + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); + prepare stmt from @str; execute stmt; drop prepare stmt; + insert into t1(x, y) values(3, 4); + insert into t1(x, y) values(2, 3); + insert into t1 values(40, 33); + set @str= concat('select x, y, ', fields, ' from t1'); + prepare stmt from @str; execute stmt; drop prepare stmt; + drop table t1; +end~~ + +create procedure test_02( + sys_type varchar(255), + engine varchar(255), + fields varchar(255)) +begin + set @str= concat(' + create table t1( + id int unsigned auto_increment primary key, + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); + prepare stmt from @str; execute stmt; drop prepare stmt; + insert into t1(x, y) values(33, 44); + insert into t1(id, x, y) values(20, 33, 44); + insert into t1 values(40, 33, 44); + set @str= concat('select id, x, y, ', fields, ' from t1'); + prepare stmt from @str; execute stmt; drop prepare stmt; + drop table t1; +end~~ + +create procedure test_03( + sys_type varchar(255), + engine varchar(255), + fields varchar(255)) +begin + set @str= concat(' + create table t1( + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); + prepare stmt from @str; execute stmt; drop prepare stmt; + create view vt1_1 as select x, y from t1; + create view vt1_2 as select x, y, sys_end from t1; + insert into t1(x, y) values(8001, 9001); + insert into vt1_1(x, y) values(1001, 2001); + insert into vt1_1 values(1002, 2002); + insert into vt1_2(x, y) values(3001, 4001); + set @str= concat('select x, y, ', fields, ' from t1'); + prepare stmt from @str; execute stmt; drop prepare stmt; + select x, y from vt1_1; + set @str= concat('select x, y, ', fields, ' from vt1_2'); + prepare stmt from @str; execute stmt; drop prepare stmt; +end~~ + +create procedure test_04( + sys_type varchar(255), + engine varchar(255), + fields varchar(255)) +begin + set @str= concat(' + create table t1( + id bigint primary key, + a int, + b int) + with system versioning + engine ', engine); + prepare stmt from @str; execute stmt; drop prepare stmt; + insert into t1 values(1, 1, 1); + select sys_trx_start, sys_trx_end from t1 into @sys_start, @sys_end; + select id, a, b from t1; + insert into t1 values(2, 2, 2); + select id, a, b, sys_trx_start > @sys_start as C, sys_trx_end = @sys_end as D from t1 where id = 2; + drop table t1; +end~~ + +create procedure test_05( + sys_type varchar(255), + engine varchar(255), + fields varchar(255)) +begin + set @str= concat('( + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); + set @str2= concat('create table t1', @str); + prepare stmt from @str2; execute stmt; drop prepare stmt; + set @str2= concat('create table t2', @str); + prepare stmt from @str2; execute stmt; drop prepare stmt; + insert into t1(x, y) values + (1, 1000), + (2, 2000), + (3, 3000), + (4, 4000), + (5, 5000), + (6, 6000), + (7, 7000), + (8, 8000), + (9, 9000); + delete from t1 where x >= 1; + insert into t1(x, y) values + (1, 1001), + (2, 2001), + (3, 3001), + (4, 4001), + (5, 5001), + (6, 6001), + (7, 7001), + (8, 8001), + (9, 9001); + insert into t2 select x, y from t1 for system_time between timestamp '0000-0-0 0:0:0' and timestamp '9999-1-1 0:0:0'; + select x, y from t1; + select x, y from t2; + drop table t1; + drop table t2; +end~~ +delimiter ;~~ + +call test_01('timestamp(6)', 'myisam', 'sys_end'); +call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); + +call test_02('timestamp(6)', 'myisam', 'sys_end'); +call test_02('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); + +call test_03('timestamp(6)', 'myisam', 'sys_end'); +--ERROR ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER +insert into t1(x, y, sys_end) values(8001, 9001, '2015-1-1 1:1:1'); +--ERROR ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER +insert into vt1_2 values(3002, 4002, '2015-2-2 2:2:2'); +drop table t1; +drop view vt1_1; +drop view vt1_2; + +call test_03('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +--ERROR ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER +insert into t1(x, y, sys_end) values(8001, 9001, 1111111); +--ERROR ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER +insert into vt1_2 values(3002, 4002, 2222222); +drop table t1; +drop view vt1_1; +drop view vt1_2; + +call test_04('timestamp(6)', 'myisam', 'sys_end'); +call test_04('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); + +call test_05('timestamp(6)', 'myisam', 'sys_end'); +call test_05('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); + +# VTQ test + +call verify_vtq; + +create table t1( + x int unsigned, + sys_start bigint unsigned generated always as row start, + sys_end bigint unsigned generated always as row end, + period for system_time (sys_start, sys_end)) +with system versioning engine=innodb; + +create table t2(x int unsigned) engine=innodb; + +start transaction; +insert into t1(x) values(1); +commit; +call verify_vtq; + +start transaction; +insert into t2(x) values(1); +savepoint a; +insert into t1(x) values(1); +rollback to a; +commit; +call verify_vtq; + +drop table t1; +drop table t2; + +drop procedure test_01; +drop procedure test_02; +drop procedure test_03; +drop procedure test_04; +drop procedure test_05; +drop procedure verify_vtq; diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test new file mode 100644 index 00000000000..621374051bb --- /dev/null +++ b/mysql-test/suite/versioning/t/select.test @@ -0,0 +1,96 @@ +-- source suite/versioning/common.inc + +delimiter ~~; +create procedure test_01( + sys_type varchar(255), + engine varchar(255), + fields varchar(255)) +begin + set @str= concat(' + create table t1( + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); + prepare stmt from @str; execute stmt; drop prepare stmt; + insert into t1 (x, y) values + (0, 100), + (1, 101), + (2, 102), + (3, 103), + (4, 104), + (5, 105), + (6, 106), + (7, 107), + (8, 108), + (9, 109); + set @t0= now(6); + delete from t1 where x = 3; + delete from t1 where x > 7; + + insert into t1(x, y) values(3, 33); + set @str= concat('select ', fields, ' from t1 where x = 3 and y = 33 into @t1'); + prepare stmt from @str; execute stmt; drop prepare stmt; + select x, y from t1; + select x as AS_OF_x, y from t1 for system_time as of timestamp @t0; + select x as FROM_TO_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; + select x as BETWEEN_AND_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; + + drop table t1; +end~~ + +create or replace procedure test_02( + sys_type varchar(255), + engine varchar(255), + fields varchar(255)) +begin + set @str0= concat('( + x int, + y int, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); + set @str= concat('create or replace table t1', @str0); + prepare stmt from @str; execute stmt; drop prepare stmt; + set @str= concat('create or replace table t2', @str0); + prepare stmt from @str; execute stmt; drop prepare stmt; + + insert into t1 values (1, 1), (1, 2), (1, 3), (4, 4), (5, 5); + insert into t2 values (1, 2), (2, 1), (3, 1); + set @t0= now(6); + + select t1.x as IJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x; + select t1.x as LJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x; + select t1.x as RJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x; + + delete from t1; + delete from t2; + + select t1.x as IJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x + for system_time as of timestamp @t0; + select t1.x as LJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x + for system_time as of timestamp @t0; + select t1.x as RJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x + for system_time as of timestamp @t0; + + drop table t1; + drop table t2; +end~~ +delimiter ;~~ + +call test_01('timestamp(6)', 'myisam', 'sys_start'); +call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_start)'); + +call test_02('timestamp(6)', 'myisam', 'sys_start'); +call test_02('bigint unsigned', 'innodb', 'commit_ts(sys_start)'); + +call verify_vtq; + +drop procedure test_01; +drop procedure test_02; +drop procedure verify_vtq; diff --git a/mysql-test/suite/versioning/t/update.test b/mysql-test/suite/versioning/t/update.test new file mode 100644 index 00000000000..f875a41ad3f --- /dev/null +++ b/mysql-test/suite/versioning/t/update.test @@ -0,0 +1,267 @@ +-- source suite/versioning/common.inc + +delimiter ~~; +create procedure test_01( + sys_type varchar(255), + engine varchar(255), + fields varchar(255)) +begin + set @str= concat(' + create table t1( + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); + prepare stmt from @str; execute stmt; drop prepare stmt; + insert into t1(x, y) values + (1, 1000), + (2, 2000), + (3, 3000), + (4, 4000), + (5, 5000), + (6, 6000), + (7, 7000), + (8, 8000), + (9, 9000); + select x, y from t1; + update t1 set y = y + 1 where x > 7; + select x, y from t1; + select x, y from t1 for system_time + between timestamp '0000-0-0 0:0:0' + and timestamp '2038-01-19 04:14:07'; + drop table t1; +end~~ + +create procedure test_02( + sys_type varchar(255), + engine varchar(255), + fields varchar(255)) +begin + set @str= concat(' + create table t1 ( + id bigint primary key, + a int, + b int without system versioning) + with system versioning + engine ', engine); + prepare stmt from @str; execute stmt; drop prepare stmt; + insert into t1 values(1, 1, 1); + set @ins_t= now(6); + select sys_trx_start into @tmp1 from t1; + update t1 set a=11, b=11 where id=1; + select @tmp1 < sys_trx_start, a, b from t1; + + select sys_trx_start into @tmp1 from t1; + update t1 set b=1 where id=1; + select @tmp1 = sys_trx_start, b from t1; + + drop table t1; +end~~ + +create procedure test_03( + sys_type varchar(255), + engine varchar(255), + fields varchar(255)) +begin + set @str= concat(' + create table t1 ( + x int, + y int) + with system versioning + engine ', engine); + prepare stmt from @str; execute stmt; drop prepare stmt; + + insert into t1 (x, y) values (1, 1), (2, 1), (3, 1); + + start transaction; + update t1 set y= y + 1 where x = 3; + update t1 set y= y + 1 where x = 3; + commit; + + select x, y from t1 for system_time + between timestamp '0000-0-0 0:0:0' + and timestamp '2038-01-19 04:14:07'; + + drop table t1; +end~~ + +create procedure test_04( + sys_type varchar(255), + engine varchar(255), + fields varchar(255)) +begin + set @str= concat(' + create table t1 ( + id int primary key auto_increment, + x int) + with system versioning + engine ', engine); + prepare stmt from @str; execute stmt; drop prepare stmt; + + set @t0= now(6); + insert into t1 (x) values (1); + set @t1= now(6); + update t1 set x= 2 where id = 1; + set @t2= now(6); + update t1 set x= 3 where id = 1; + + select x from t1 for system_time as of timestamp @t0; + select x from t1 for system_time as of timestamp @t1; + select x from t1 for system_time as of timestamp @t2; + select x from t1 for system_time as of timestamp now(6); + + drop table t1; +end~~ + +create procedure test_05( + sys_type varchar(255), + engine varchar(255), + fields varchar(255)) +begin + set @str= concat(' + create table t1( + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end), + primary key(x, y)) + with system versioning + engine ', engine); + prepare stmt from @str; execute stmt; drop prepare stmt; + insert into t1(x, y) values + (1, 1000), + (2, 2000), + (3, 3000), + (4, 4000), + (5, 5000), + (6, 6000), + (7, 7000), + (8, 8000), + (9, 9000); + insert into t1(x, y) values(3, 3000) on duplicate key update y = y+1; + insert into t1(x, y) values(4, 4000) on duplicate key update y = y+1; + insert into t1(x, y) values(4, 4001) on duplicate key update y = y+1; + insert into t1(x, y) values(4, 4444) on duplicate key update y = y+1; + select x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp '9999-1-1 0:0:0'; + select x, y from t1; + drop table t1; +end~~ + +create procedure test_06( + sys_type varchar(255), + engine varchar(255), + fields varchar(255)) +begin + set @str= concat('( + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); + set @str2= concat('create table t1', @str); + prepare stmt from @str2; execute stmt; drop prepare stmt; + set @str2= concat('create table t2', @str); + prepare stmt from @str2; execute stmt; drop prepare stmt; + insert into t1(x, y) values + (1, 1000), + (2, 2000), + (3, 3000), + (4, 4000), + (5, 5000), + (6, 6000), + (7, 7000), + (8, 8000), + (9, 9000); + insert into t2(x, y) values + (1, 1010), + (2, 2010), + (3, 3010), + (4, 4010), + (5, 5010), + (6, 6010), + (7, 7010), + (8, 8010), + (9, 9010); + update t1, t2 set t1.y = t1.x + t1.y, t2.y = t2.x + t2.y where t1.x > 7 and t2.x < 7; + select x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp '9999-1-1 0:0:0'; + select x, y from t1; + select x, y from t2 for system_time between timestamp '0-0-0 0:0:0' and timestamp '9999-1-1 0:0:0'; + select x, y from t2; + drop table t1; + drop table t2; +end~~ + +create procedure test_07( + sys_type varchar(255), + engine varchar(255), + fields varchar(255)) +begin + set @str= concat('( + id bigint primary key, + name varchar(128) with system versioning, + salary bigint) + engine ', engine); + + set @str2= concat('create table t1', @str); + prepare stmt from @str2; execute stmt; drop prepare stmt; + set @str2= concat('create table t2', @str); + prepare stmt from @str2; execute stmt; drop prepare stmt; + + insert into t1 values (1, "Jeremy", 3000); + insert into t2 values (1, "Jeremy", 4000); + + select sys_trx_start into @tmp1 from t1; + select sys_trx_start into @tmp2 from t2; + update t1, t2 set t1.name= "Jerry", t2.name= "Jerry" where t1.id = t2.id and t1.name = "Jeremy"; + select @tmp1 < sys_trx_start as A1, name from t1; + select @tmp2 < sys_trx_start as A2, name from t2; + + select sys_trx_start into @tmp1 from t1; + select sys_trx_start into @tmp2 from t2; + update t1, t2 set t1.salary= 2500, t2.salary= 2500 where t1.id = t2.id and t1.name = "Jerry"; + select @tmp1 = sys_trx_start as B1, salary from t1; + select @tmp2 = sys_trx_start as B2, salary from t2; + + drop table t1; + drop table t2; +end~~ +delimiter ;~~ + +call test_01('timestamp(6)', 'myisam', 'sys_end'); +call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); + +call test_02('timestamp(6)', 'myisam', 'sys_end'); +call test_02('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); + +call test_03('timestamp(6)', 'myisam', 'sys_end'); +call test_03('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); + +call test_04('timestamp(6)', 'myisam', 'sys_end'); +call test_04('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); + +call test_05('timestamp(6)', 'myisam', 'sys_end'); +call test_05('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); + +call test_06('timestamp(6)', 'myisam', 'sys_end'); +call test_06('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); + +call test_07('timestamp(6)', 'myisam', 'sys_end'); +# Issue #53 +# call test_07('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); + +call verify_vtq; + +drop procedure test_01; +drop procedure test_02; +drop procedure test_03; +drop procedure test_04; +drop procedure test_05; +drop procedure test_06; +drop procedure test_07; +drop procedure verify_vtq; -- cgit v1.2.1 From 44e581ebfccf055db164de865494d47766b2348b Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 18 Oct 2016 12:09:27 +0000 Subject: Tests: removed from main suite --- mysql-test/r/auto_increment.result | 59 ---------- mysql-test/r/create.result | 185 ------------------------------ mysql-test/r/delete.result | 190 ------------------------------- mysql-test/r/insert.result | 212 ----------------------------------- mysql-test/r/insert_select.result | 133 ---------------------- mysql-test/r/insert_update.result | 116 ------------------- mysql-test/r/multi_update.result | 203 --------------------------------- mysql-test/r/select.result | 65 ----------- mysql-test/r/select_jcl6.result | 65 ----------- mysql-test/r/select_pkeycache.result | 65 ----------- mysql-test/r/update.result | 143 ----------------------- mysql-test/t/auto_increment.test | 34 ------ mysql-test/t/create.test | 157 -------------------------- mysql-test/t/delete.opt | 1 - mysql-test/t/delete.test | 85 -------------- mysql-test/t/insert.opt | 1 - mysql-test/t/insert.test | 183 ------------------------------ mysql-test/t/insert_select.opt | 1 - mysql-test/t/insert_select.test | 83 -------------- mysql-test/t/insert_update.opt | 1 - mysql-test/t/insert_update.test | 73 ------------ mysql-test/t/multi_update.opt | 1 - mysql-test/t/multi_update.test | 115 +------------------ mysql-test/t/select.test | 34 ------ mysql-test/t/update.opt | 1 - mysql-test/t/update.test | 90 --------------- 26 files changed, 1 insertion(+), 2295 deletions(-) delete mode 100644 mysql-test/t/delete.opt delete mode 100644 mysql-test/t/insert.opt delete mode 100644 mysql-test/t/insert_select.opt delete mode 100644 mysql-test/t/insert_update.opt delete mode 100644 mysql-test/t/multi_update.opt delete mode 100644 mysql-test/t/update.opt diff --git a/mysql-test/r/auto_increment.result b/mysql-test/r/auto_increment.result index bb684d1930f..12cbf294b69 100644 --- a/mysql-test/r/auto_increment.result +++ b/mysql-test/r/auto_increment.result @@ -537,62 +537,3 @@ pk -5 1 drop table t1; -# -# System Versioning Support -# -# -CREATE TABLE t1(id INT UNSIGNED AUTO_INCREMENT, x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end), PRIMARY KEY (id)) WITH SYSTEM VERSIONING; -CREATE TABLE T1(id INT UNSIGNED AUTO_INCREMENT, x INT UNSIGNED, y INT UNSIGNED, PRIMARY KEY (id)); -INSERT INTO t1(x, y) VALUES(1, 11); -INSERT INTO T1(x, y) VALUES(1, 11); -INSERT INTO t1(x, y) VALUES(2, 12); -INSERT INTO T1(x, y) VALUES(2, 12); -INSERT INTO t1(x, y) VALUES(3, 13); -INSERT INTO T1(x, y) VALUES(3, 13); -INSERT INTO t1(x, y) VALUES(4, 14); -INSERT INTO T1(x, y) VALUES(4, 14); -INSERT INTO t1(x, y) VALUES(5, 15); -INSERT INTO T1(x, y) VALUES(5, 15); -INSERT INTO t1(x, y) VALUES(6, 16); -INSERT INTO T1(x, y) VALUES(6, 16); -INSERT INTO t1(x, y) VALUES(7, 17); -INSERT INTO T1(x, y) VALUES(7, 17); -INSERT INTO t1(x, y) VALUES(8, 18); -INSERT INTO T1(x, y) VALUES(8, 18); -INSERT INTO t1(x, y) VALUES(9, 19); -INSERT INTO T1(x, y) VALUES(9, 19); -SELECT t1.x = T1.x AND t1.y = T1.y, t1.x, t1.y, T1.x, T1.y FROM t1 INNER JOIN T1 ON(t1.id = T1.id); -t1.x = T1.x AND t1.y = T1.y x y x y -1 1 11 1 11 -1 2 12 2 12 -1 3 13 3 13 -1 4 14 4 14 -1 5 15 5 15 -1 6 16 6 16 -1 7 17 7 17 -1 8 18 8 18 -1 9 19 9 19 -DELETE FROM t1 WHERE x=2; -DELETE FROM T1 WHERE x=2; -SELECT t1.x = T1.x AND t1.y = T1.y, t1.x, t1.y, T1.x, T1.y FROM t1 INNER JOIN T1 ON(t1.id = T1.id); -t1.x = T1.x AND t1.y = T1.y x y x y -1 1 11 1 11 -1 3 13 3 13 -1 4 14 4 14 -1 5 15 5 15 -1 6 16 6 16 -1 7 17 7 17 -1 8 18 8 18 -1 9 19 9 19 -DELETE FROM t1 WHERE x>7; -DELETE FROM T1 WHERE x>7; -SELECT t1.x = T1.x AND t1.y = T1.y, t1.x, t1.y, T1.x, T1.y FROM t1 INNER JOIN T1 ON(t1.id = T1.id); -t1.x = T1.x AND t1.y = T1.y x y x y -1 1 11 1 11 -1 3 13 3 13 -1 4 14 4 14 -1 5 15 5 15 -1 6 16 6 16 -1 7 17 7 17 -DROP TABLE t1; -DROP TABLE T1; diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 70037b4466e..2c67d33b3e7 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -1931,188 +1931,3 @@ create table t1 (i int, j int, key(i), key(i)) as select 1 as i, 2 as j; Warnings: Note 1831 Duplicate index `i_2`. This is deprecated and will be disallowed in a future release drop table t1; -# -# Test for SYSTEM VERSIONING CREATE -# -create table t1 ( -XNo INT UNSIGNED, -Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, -Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, -PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) -) WITH SYSTEM VERSIONING; -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `XNo` int(10) unsigned DEFAULT NULL, - `Sys_start` timestamp(6) NOT NULL GENERATED AS ROW START, - `Sys_end` timestamp(6) NOT NULL GENERATED AS ROW END, - PERIOD FOR SYSTEM_TIME (`Sys_start`, `Sys_end`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING -drop table if exists t1; -# Versioning fields are set implicitly. -create table t1 ( -XNo INT UNSIGNED -) WITH SYSTEM VERSIONING; -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `XNo` int(10) unsigned DEFAULT NULL, - `sys_trx_start` timestamp(6) NOT NULL GENERATED AS ROW START, - `sys_trx_end` timestamp(6) NOT NULL GENERATED AS ROW END, - PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING -drop table if exists t1; -create table t1 ( -XNo INT UNSIGNED, -Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, -Sys_start2 TIMESTAMP(6) GENERATED ALWAYS AS ROW START, -Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, -PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) -) WITH SYSTEM VERSIONING; -ERROR HY000: 'Generated as row start' specified more than once -create table t1 ( -XNo INT UNSIGNED, -Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, -Sys_end2 TIMESTAMP(6) GENERATED ALWAYS AS ROW END, -PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) -) WITH SYSTEM VERSIONING; -ERROR HY000: Second column in 'period for system time' must be equal to 'generated as row end' column -create table t1 ( -XNo INT UNSIGNED, -Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, -Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, -Sys_end2 TIMESTAMP(6) GENERATED ALWAYS AS ROW END, -PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) -) WITH SYSTEM VERSIONING; -ERROR HY000: Generated as row end specified more than once -create table t1 ( -XNo INT UNSIGNED, -PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) -) WITH SYSTEM VERSIONING; -ERROR HY000: 'Generated as row start' not specified -create table t1 ( -XNo INT UNSIGNED, -Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, -Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, -Sys_end2 TIMESTAMP(6) GENERATED ALWAYS AS ROW END, -PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) -); -ERROR HY000: Generated as row end specified more than once -create table t1 ( -XNo INT UNSIGNED, -Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, -Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, -PERIOD FOR SYSTEM_TIME (Sys_insert, Sys_remove) -) WITH SYSTEM VERSIONING; -ERROR HY000: First column in 'period for system time' must be equal to 'generated as row start' column -create table t1 ( -XNo INT UNSIGNED, -Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, -Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, -PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) -); -ERROR HY000: 'With system versioning' is missing -create table t1 ( -XNo INT UNSIGNED, -Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, -Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, -PERIOD FOR SYSTEM_TIME (Sys_start, Sys_start) -); -ERROR HY000: 'Period for system_time' must contain two different columns -create table t1 ( -XNo INT UNSIGNED, -Sys_start INT GENERATED ALWAYS AS ROW START, -Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, -PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) -) WITH SYSTEM VERSIONING; -ERROR HY000: System start field must be of type TIMESTAMP -create table t1 ( -XNo INT UNSIGNED, -Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, -Sys_end INT GENERATED ALWAYS AS ROW END, -PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) -) WITH SYSTEM VERSIONING; -ERROR HY000: System end field must be of type TIMESTAMP -CREATE TABLE t1 ( -A INT WITH SYSTEM VERSIONING, -B INT -); -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `A` int(11) DEFAULT NULL, - `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, - `sys_trx_start` timestamp(6) NOT NULL GENERATED AS ROW START, - `sys_trx_end` timestamp(6) NOT NULL GENERATED AS ROW END, - PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING -DROP TABLE t1; -CREATE TABLE t1 ( -A INT WITH SYSTEM VERSIONING, -B INT -) WITH SYSTEM VERSIONING; -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `A` int(11) DEFAULT NULL, - `B` int(11) DEFAULT NULL, - `sys_trx_start` timestamp(6) NOT NULL GENERATED AS ROW START, - `sys_trx_end` timestamp(6) NOT NULL GENERATED AS ROW END, - PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING -DROP TABLE t1; -CREATE TABLE t1 ( -A INT, -B INT WITHOUT SYSTEM VERSIONING -); -ERROR HY000: Every field specified unversioned in versioned table -CREATE TABLE t1 ( -A INT, -B INT WITHOUT SYSTEM VERSIONING -) WITH SYSTEM VERSIONING; -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `A` int(11) DEFAULT NULL, - `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, - `sys_trx_start` timestamp(6) NOT NULL GENERATED AS ROW START, - `sys_trx_end` timestamp(6) NOT NULL GENERATED AS ROW END, - PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING -DROP TABLE t1; -CREATE TABLE t1 ( -A INT WITH SYSTEM VERSIONING, -B INT WITHOUT SYSTEM VERSIONING -); -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `A` int(11) DEFAULT NULL, - `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, - `sys_trx_start` timestamp(6) NOT NULL GENERATED AS ROW START, - `sys_trx_end` timestamp(6) NOT NULL GENERATED AS ROW END, - PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING -DROP TABLE t1; -CREATE TABLE t1 ( -A INT WITH SYSTEM VERSIONING, -B INT WITHOUT SYSTEM VERSIONING -) WITH SYSTEM VERSIONING; -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `A` int(11) DEFAULT NULL, - `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, - `sys_trx_start` timestamp(6) NOT NULL GENERATED AS ROW START, - `sys_trx_end` timestamp(6) NOT NULL GENERATED AS ROW END, - PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING -DROP TABLE t1; -CREATE TABLE t1 ( -A INT WITHOUT SYSTEM VERSIONING -); -ERROR HY000: Every field specified unversioned in versioned table -CREATE TABLE t1 ( -A INT WITHOUT SYSTEM VERSIONING -) WITH SYSTEM VERSIONING; -ERROR HY000: Every field specified unversioned in versioned table diff --git a/mysql-test/r/delete.result b/mysql-test/r/delete.result index 4cb396511c1..ed3683d52f9 100644 --- a/mysql-test/r/delete.result +++ b/mysql-test/r/delete.result @@ -525,193 +525,3 @@ DELETE v2 FROM v2; ERROR HY000: Can not delete from join view 'test.v2' DROP VIEW v2, v1; DROP TABLE t1, t2; -# -# System Versioning Support -# -# -set @@session.time_zone='+00:00'; -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; -create procedure test_01( -sys_type varchar(255), -engine varchar(255), -fields varchar(255)) -begin -set @str= concat(' - create table t1( - XNo int unsigned, - sys_start ', sys_type, ' generated always as row start, - sys_end ', sys_type, ' generated always as row end, - period for system_time (sys_start, sys_end)) - with system versioning - engine ', engine); -prepare stmt from @str; execute stmt; drop prepare stmt; -insert into t1(XNo) values(0); -insert into t1(XNo) values(1); -insert into t1(XNo) values(2); -insert into t1(XNo) values(3); -insert into t1(XNo) values(4); -insert into t1(XNo) values(5); -insert into t1(XNo) values(6); -insert into t1(XNo) values(7); -insert into t1(XNo) values(8); -insert into t1(XNo) values(9); -set @str= concat('select XNo, ', -fields, " < '2038-01-19 03:14:07' - from t1 for system_time - between timestamp '0000-0-0 0:0:0' - and timestamp '2038-01-19 04:14:07'"); -prepare stmt from @str; execute stmt; -delete from t1 where XNo = 0; -execute stmt; -delete from t1 where XNo = 1; -execute stmt; -delete from t1 where XNo > 5; -create view vt1 as select XNo from t1; -select XNo from vt1; -delete from vt1 where XNo = 3; -select XNo from vt1; -execute stmt; drop prepare stmt; -drop view vt1; -drop table t1; -end~~ -call test_01('timestamp(6)', 'myisam', 'sys_end'); -XNo sys_end < '2038-01-19 03:14:07' -0 0 -1 0 -2 0 -3 0 -4 0 -5 0 -6 0 -7 0 -8 0 -9 0 -XNo sys_end < '2038-01-19 03:14:07' -0 1 -1 0 -2 0 -3 0 -4 0 -5 0 -6 0 -7 0 -8 0 -9 0 -XNo sys_end < '2038-01-19 03:14:07' -0 1 -1 1 -2 0 -3 0 -4 0 -5 0 -6 0 -7 0 -8 0 -9 0 -XNo -2 -3 -4 -5 -XNo -2 -4 -5 -XNo sys_end < '2038-01-19 03:14:07' -0 1 -1 1 -2 0 -3 1 -4 0 -5 0 -6 1 -7 1 -8 1 -9 1 -call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); -XNo commit_ts(sys_end) < '2038-01-19 03:14:07' -0 0 -1 0 -2 0 -3 0 -4 0 -5 0 -6 0 -7 0 -8 0 -9 0 -XNo commit_ts(sys_end) < '2038-01-19 03:14:07' -0 1 -1 0 -2 0 -3 0 -4 0 -5 0 -6 0 -7 0 -8 0 -9 0 -XNo commit_ts(sys_end) < '2038-01-19 03:14:07' -0 1 -1 1 -2 0 -3 0 -4 0 -5 0 -6 0 -7 0 -8 0 -9 0 -XNo -2 -3 -4 -5 -XNo -2 -4 -5 -XNo commit_ts(sys_end) < '2038-01-19 03:14:07' -0 1 -1 1 -2 0 -3 1 -4 0 -5 0 -6 1 -7 1 -8 1 -9 1 -drop procedure test_01; -create procedure verify_vtq() -begin -set @i= 0; -select -@i:= @i + 1 as No, -trx_id > 0 as A, -begin_ts > '1-1-1 0:0:0' as B, -commit_ts > begin_ts as C, -concurr_trx is null as D -from information_schema.innodb_vtq -where trx_id > @start_trx_id; -select ifnull(max(trx_id), 0) -into @start_trx_id -from information_schema.innodb_vtq; -end~~ -call verify_vtq; -No A B C D -1 1 1 1 1 -2 1 1 1 1 -3 1 1 1 1 -4 1 1 1 1 -5 1 1 1 1 -6 1 1 1 1 -7 1 1 1 1 -8 1 1 1 1 -9 1 1 1 1 -10 1 1 1 1 -11 1 1 1 1 -12 1 1 1 1 -13 1 1 1 1 -14 1 1 1 1 -drop procedure verify_vtq; diff --git a/mysql-test/r/insert.result b/mysql-test/r/insert.result index b0e1b0d67a7..c9e3dc7b253 100644 --- a/mysql-test/r/insert.result +++ b/mysql-test/r/insert.result @@ -717,215 +717,3 @@ insert ignore into t1 values (1,12); Warnings: Warning 1062 Duplicate entry '1' for key 'f1' DROP TABLE t1; -# -# System Versioning Support -# -# -set @@session.time_zone='+00:00'; -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; -create procedure test_01( -sys_type varchar(255), -engine varchar(255), -fields varchar(255)) -begin -set @str= concat(' - create table t1( - x int unsigned, - y int unsigned, - sys_start ', sys_type, ' generated always as row start, - sys_end ', sys_type, ' generated always as row end, - period for system_time (sys_start, sys_end)) - with system versioning - engine ', engine); -prepare stmt from @str; execute stmt; drop prepare stmt; -insert into t1(x, y) values(3, 4); -insert into t1(x, y) values(2, 3); -insert into t1 values(40, 33); -set @str= concat('select x, y, ', fields, ' from t1'); -prepare stmt from @str; execute stmt; drop prepare stmt; -drop table t1; -end~~ -call test_01('timestamp(6)', 'myisam', 'sys_end'); -x y sys_end -3 4 2038-01-19 03:14:07.000000 -2 3 2038-01-19 03:14:07.000000 -40 33 2038-01-19 03:14:07.000000 -call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); -x y commit_ts(sys_end) -3 4 2038-01-19 03:14:07.000000 -2 3 2038-01-19 03:14:07.000000 -40 33 2038-01-19 03:14:07.000000 -drop procedure test_01; -create procedure test_02( -sys_type varchar(255), -engine varchar(255), -fields varchar(255)) -begin -set @str= concat(' - create table t1( - id int unsigned auto_increment primary key, - x int unsigned, - y int unsigned, - sys_start ', sys_type, ' generated always as row start, - sys_end ', sys_type, ' generated always as row end, - period for system_time (sys_start, sys_end)) - with system versioning - engine ', engine); -prepare stmt from @str; execute stmt; drop prepare stmt; -insert into t1(x, y) values(33, 44); -insert into t1(id, x, y) values(20, 33, 44); -insert into t1 values(40, 33, 44); -set @str= concat('select id, x, y, ', fields, ' from t1'); -prepare stmt from @str; execute stmt; drop prepare stmt; -drop table t1; -end~~ -call test_02('timestamp(6)', 'myisam', 'sys_end'); -id x y sys_end -1 33 44 2038-01-19 03:14:07.000000 -20 33 44 2038-01-19 03:14:07.000000 -40 33 44 2038-01-19 03:14:07.000000 -call test_02('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); -id x y commit_ts(sys_end) -1 33 44 2038-01-19 03:14:07.000000 -20 33 44 2038-01-19 03:14:07.000000 -40 33 44 2038-01-19 03:14:07.000000 -drop procedure test_02; -create procedure test_03( -sys_type varchar(255), -engine varchar(255), -fields varchar(255)) -begin -set @str= concat(' - create table t1( - x int unsigned, - y int unsigned, - sys_start ', sys_type, ' generated always as row start, - sys_end ', sys_type, ' generated always as row end, - period for system_time (sys_start, sys_end)) - with system versioning - engine ', engine); -prepare stmt from @str; execute stmt; drop prepare stmt; -create view vt1_1 as select x, y from t1; -create view vt1_2 as select x, y, sys_end from t1; -insert into t1(x, y) values(8001, 9001); -insert into vt1_1(x, y) values(1001, 2001); -insert into vt1_1 values(1002, 2002); -insert into vt1_2(x, y) values(3001, 4001); -set @str= concat('select x, y, ', fields, ' from t1'); -prepare stmt from @str; execute stmt; drop prepare stmt; -select x, y from vt1_1; -set @str= concat('select x, y, ', fields, ' from vt1_2'); -prepare stmt from @str; execute stmt; drop prepare stmt; -end~~ -call test_03('timestamp(6)', 'myisam', 'sys_end'); -x y sys_end -8001 9001 2038-01-19 03:14:07.000000 -1001 2001 2038-01-19 03:14:07.000000 -1002 2002 2038-01-19 03:14:07.000000 -3001 4001 2038-01-19 03:14:07.000000 -x y -8001 9001 -1001 2001 -1002 2002 -3001 4001 -x y sys_end -8001 9001 2038-01-19 03:14:07.000000 -1001 2001 2038-01-19 03:14:07.000000 -1002 2002 2038-01-19 03:14:07.000000 -3001 4001 2038-01-19 03:14:07.000000 -insert into t1(x, y, sys_end) values(8001, 9001, '2015-1-1 1:1:1'); -ERROR HY000: Generated field for System Versioning cannot be set by user -insert into vt1_2 values(3002, 4002, '2015-2-2 2:2:2'); -ERROR HY000: Generated field for System Versioning cannot be set by user -drop table t1; -drop view vt1_1; -drop view vt1_2; -call test_03('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); -x y commit_ts(sys_end) -8001 9001 2038-01-19 03:14:07.000000 -1001 2001 2038-01-19 03:14:07.000000 -1002 2002 2038-01-19 03:14:07.000000 -3001 4001 2038-01-19 03:14:07.000000 -x y -8001 9001 -1001 2001 -1002 2002 -3001 4001 -x y commit_ts(sys_end) -8001 9001 2038-01-19 03:14:07.000000 -1001 2001 2038-01-19 03:14:07.000000 -1002 2002 2038-01-19 03:14:07.000000 -3001 4001 2038-01-19 03:14:07.000000 -insert into t1(x, y, sys_end) values(8001, 9001, 1111111); -ERROR HY000: Generated field for System Versioning cannot be set by user -insert into vt1_2 values(3002, 4002, 2222222); -ERROR HY000: Generated field for System Versioning cannot be set by user -drop table t1; -drop view vt1_1; -drop view vt1_2; -drop procedure test_03; -create procedure verify_vtq() -begin -set @i= 0; -select -@i:= @i + 1 as No, -trx_id > 0 as A, -begin_ts > '1-1-1 0:0:0' as B, -commit_ts > begin_ts as C, -concurr_trx is null as D -from information_schema.innodb_vtq -where trx_id > @start_trx_id; -select ifnull(max(trx_id), 0) -into @start_trx_id -from information_schema.innodb_vtq; -end~~ -call verify_vtq; -No A B C D -1 1 1 1 1 -2 1 1 1 1 -3 1 1 1 1 -4 1 1 1 1 -5 1 1 1 1 -6 1 1 1 1 -7 1 1 1 1 -8 1 1 1 1 -9 1 1 1 1 -10 1 1 1 1 -create table t1( -x int unsigned, -sys_start bigint unsigned generated always as row start, -sys_end bigint unsigned generated always as row end, -period for system_time (sys_start, sys_end)) -with system versioning engine=innodb; -create table t2(x int unsigned) engine=innodb; -start transaction; -insert into t1(x) values(1); -commit; -call verify_vtq; -No A B C D -1 1 1 1 1 -start transaction; -insert into t2(x) values(1); -savepoint a; -insert into t1(x) values(1); -rollback to a; -commit; -call verify_vtq; -No A B C D -drop table t1; -drop table t2; -drop procedure verify_vtq; -CREATE TABLE t1( -id BIGINT PRIMARY KEY, -A INT, -B INT -) WITH SYSTEM VERSIONING; -INSERT INTO t1 VALUES(1, 1, 1); -DROP TABLE t1; -CREATE TABLE t1( -id BIGINT PRIMARY KEY, -A INT, -B INT -) WITH SYSTEM VERSIONING ENGINE=INNODB; -INSERT INTO t1 VALUES(1, 1, 1); -DROP TABLE t1; diff --git a/mysql-test/r/insert_select.result b/mysql-test/r/insert_select.result index 3d38a934c71..1a3a38b1f35 100644 --- a/mysql-test/r/insert_select.result +++ b/mysql-test/r/insert_select.result @@ -856,136 +856,3 @@ INSERT IGNORE INTO t1 SELECT t1.a FROM t1,t1 t2,t1 t3,t1 t4,t1 t5,t1 t6,t1 t7; SET GLOBAL myisam_data_pointer_size = @old_myisam_data_pointer_size; DROP TABLE t1; End of 5.1 tests -# -# System Versioning Support -# -# -set @@session.time_zone='+00:00'; -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; -create procedure test_01( -sys_type varchar(255), -engine varchar(255), -fields varchar(255)) -begin -set @str= concat('( - x int unsigned, - y int unsigned, - sys_start ', sys_type, ' generated always as row start, - sys_end ', sys_type, ' generated always as row end, - period for system_time (sys_start, sys_end)) - with system versioning - engine ', engine); -set @str2= concat('create table t1', @str); -prepare stmt from @str2; execute stmt; drop prepare stmt; -set @str2= concat('create table t2', @str); -prepare stmt from @str2; execute stmt; drop prepare stmt; -insert into t1(x, y) values -(1, 1000), -(2, 2000), -(3, 3000), -(4, 4000), -(5, 5000), -(6, 6000), -(7, 7000), -(8, 8000), -(9, 9000); -delete from t1 where x >= 1; -insert into t1(x, y) values -(1, 1001), -(2, 2001), -(3, 3001), -(4, 4001), -(5, 5001), -(6, 6001), -(7, 7001), -(8, 8001), -(9, 9001); -insert into t2 select x, y from t1 for system_time between timestamp '0000-0-0 0:0:0' and timestamp '9999-1-1 0:0:0'; -select x, y from t1; -select x, y from t2; -drop table t1; -drop table t2; -end~~ -call test_01('timestamp(6)', 'myisam', 'sys_end'); -x y -1 1001 -2 2001 -3 3001 -4 4001 -5 5001 -6 6001 -7 7001 -8 8001 -9 9001 -x y -1 1000 -2 2000 -3 3000 -4 4000 -5 5000 -6 6000 -7 7000 -8 8000 -9 9000 -1 1001 -2 2001 -3 3001 -4 4001 -5 5001 -6 6001 -7 7001 -8 8001 -9 9001 -call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); -x y -1 1001 -2 2001 -3 3001 -4 4001 -5 5001 -6 6001 -7 7001 -8 8001 -9 9001 -x y -1 1000 -2 2000 -3 3000 -4 4000 -5 5000 -6 6000 -7 7000 -8 8000 -9 9000 -1 1001 -2 2001 -3 3001 -4 4001 -5 5001 -6 6001 -7 7001 -8 8001 -9 9001 -drop procedure test_01; -create procedure verify_vtq() -begin -set @i= 0; -select -@i:= @i + 1 as No, -trx_id > 0 as A, -begin_ts > '1-1-1 0:0:0' as B, -commit_ts > begin_ts as C, -concurr_trx is null as D -from information_schema.innodb_vtq -where trx_id > @start_trx_id; -select ifnull(max(trx_id), 0) -into @start_trx_id -from information_schema.innodb_vtq; -end~~ -call verify_vtq; -No A B C D -1 1 1 1 1 -2 1 1 1 1 -3 1 1 1 1 -4 1 1 1 1 -drop procedure verify_vtq; diff --git a/mysql-test/r/insert_update.result b/mysql-test/r/insert_update.result index e8567afdd45..e8e6e16fe5a 100644 --- a/mysql-test/r/insert_update.result +++ b/mysql-test/r/insert_update.result @@ -412,119 +412,3 @@ select if( @stamp1 = @stamp2, "correct", "wrong"); if( @stamp1 = @stamp2, "correct", "wrong") correct drop table t1; -# -# System Versioning Support -# -# -set @@session.time_zone='+00:00'; -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; -create procedure test_01( -sys_type varchar(255), -engine varchar(255), -fields varchar(255)) -begin -set @str= concat(' - create table t1( - x int unsigned, - y int unsigned, - sys_start ', sys_type, ' generated always as row start, - sys_end ', sys_type, ' generated always as row end, - period for system_time (sys_start, sys_end), - primary key(x, y)) - with system versioning - engine ', engine); -prepare stmt from @str; execute stmt; drop prepare stmt; -insert into t1(x, y) values -(1, 1000), -(2, 2000), -(3, 3000), -(4, 4000), -(5, 5000), -(6, 6000), -(7, 7000), -(8, 8000), -(9, 9000); -insert into t1(x, y) values(3, 3000) on duplicate key update y = y+1; -insert into t1(x, y) values(4, 4000) on duplicate key update y = y+1; -insert into t1(x, y) values(4, 4001) on duplicate key update y = y+1; -insert into t1(x, y) values(4, 4444) on duplicate key update y = y+1; -select x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp '9999-1-1 0:0:0'; -select x, y from t1; -drop table t1; -end~~ -call test_01('timestamp(6)', 'myisam', 'sys_end'); -x y -1 1000 -2 2000 -3 3001 -4 4002 -5 5000 -6 6000 -7 7000 -8 8000 -9 9000 -3 3000 -4 4000 -4 4001 -4 4444 -x y -1 1000 -2 2000 -3 3001 -4 4002 -4 4444 -5 5000 -6 6000 -7 7000 -8 8000 -9 9000 -call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); -x y -1 1000 -2 2000 -3 3000 -3 3001 -4 4000 -4 4001 -4 4002 -4 4444 -5 5000 -6 6000 -7 7000 -8 8000 -9 9000 -x y -1 1000 -2 2000 -3 3001 -4 4002 -4 4444 -5 5000 -6 6000 -7 7000 -8 8000 -9 9000 -drop procedure test_01; -create procedure verify_vtq() -begin -set @i= 0; -select -@i:= @i + 1 as No, -trx_id > 0 as A, -begin_ts > '1-1-1 0:0:0' as B, -commit_ts > begin_ts as C, -concurr_trx is null as D -from information_schema.innodb_vtq -where trx_id > @start_trx_id; -select ifnull(max(trx_id), 0) -into @start_trx_id -from information_schema.innodb_vtq; -end~~ -call verify_vtq; -No A B C D -1 1 1 1 1 -2 1 1 1 1 -3 1 1 1 1 -4 1 1 1 1 -5 1 1 1 1 -drop procedure verify_vtq; diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result index bb68029a490..6b60e155005 100644 --- a/mysql-test/r/multi_update.result +++ b/mysql-test/r/multi_update.result @@ -1056,206 +1056,3 @@ Note 1592 Unsafe statement written to the binary log using statement format sinc DROP TABLE table_11757486; SET SESSION SQL_MODE=default; end of 10.0 tests -# -# System Versioning Support -# -# -set @@session.time_zone='+00:00'; -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; -create procedure test_01( -sys_type varchar(255), -engine varchar(255), -fields varchar(255)) -begin -set @str= concat('( - x int unsigned, - y int unsigned, - sys_start ', sys_type, ' generated always as row start, - sys_end ', sys_type, ' generated always as row end, - period for system_time (sys_start, sys_end)) - with system versioning - engine ', engine); -set @str2= concat('create table t1', @str); -prepare stmt from @str2; execute stmt; drop prepare stmt; -set @str2= concat('create table t2', @str); -prepare stmt from @str2; execute stmt; drop prepare stmt; -insert into t1(x, y) values -(1, 1000), -(2, 2000), -(3, 3000), -(4, 4000), -(5, 5000), -(6, 6000), -(7, 7000), -(8, 8000), -(9, 9000); -insert into t2(x, y) values -(1, 1010), -(2, 2010), -(3, 3010), -(4, 4010), -(5, 5010), -(6, 6010), -(7, 7010), -(8, 8010), -(9, 9010); -update t1, t2 set t1.y = t1.x + t1.y, t2.y = t2.x + t2.y where t1.x > 7 and t2.x < 7; -select x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp '9999-1-1 0:0:0'; -select x, y from t1; -select x, y from t2 for system_time between timestamp '0-0-0 0:0:0' and timestamp '9999-1-1 0:0:0'; -select x, y from t2; -drop table t1; -drop table t2; -end~~ -call test_01('timestamp(6)', 'myisam', 'sys_end'); -x y -1 1000 -2 2000 -3 3000 -4 4000 -5 5000 -6 6000 -7 7000 -8 8008 -9 9009 -8 8000 -9 9000 -x y -1 1000 -2 2000 -3 3000 -4 4000 -5 5000 -6 6000 -7 7000 -8 8008 -9 9009 -x y -1 1011 -2 2012 -3 3013 -4 4014 -5 5015 -6 6016 -7 7010 -8 8010 -9 9010 -1 1010 -2 2010 -3 3010 -4 4010 -5 5010 -6 6010 -x y -1 1011 -2 2012 -3 3013 -4 4014 -5 5015 -6 6016 -7 7010 -8 8010 -9 9010 -call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); -x y -1 1000 -2 2000 -3 3000 -4 4000 -5 5000 -6 6000 -7 7000 -8 8008 -9 9009 -8 8000 -9 9000 -x y -1 1000 -2 2000 -3 3000 -4 4000 -5 5000 -6 6000 -7 7000 -8 8008 -9 9009 -x y -1 1011 -2 2012 -3 3013 -4 4014 -5 5015 -6 6016 -7 7010 -8 8010 -9 9010 -1 1010 -2 2010 -3 3010 -4 4010 -5 5010 -6 6010 -x y -1 1011 -2 2012 -3 3013 -4 4014 -5 5015 -6 6016 -7 7010 -8 8010 -9 9010 -drop procedure test_01; -create procedure verify_vtq() -begin -set @i= 0; -select -@i:= @i + 1 as No, -trx_id > 0 as A, -begin_ts > '1-1-1 0:0:0' as B, -commit_ts > begin_ts as C, -concurr_trx is null as D -from information_schema.innodb_vtq -where trx_id > @start_trx_id; -select ifnull(max(trx_id), 0) -into @start_trx_id -from information_schema.innodb_vtq; -end~~ -call verify_vtq; -No A B C D -1 1 1 1 1 -2 1 1 1 1 -3 1 1 1 1 -drop procedure verify_vtq; -CREATE TABLE t1 ( -id BIGINT PRIMARY KEY, -name VARCHAR(128) WITH SYSTEM VERSIONING, -salary BIGINT -); -INSERT INTO t1 VALUES (1, "Jeremy", 3000); -CREATE TABLE t2 ( -id BIGINT PRIMARY KEY, -name VARCHAR(128) WITH SYSTEM VERSIONING, -salary BIGINT -); -INSERT INTO t2 VALUES (1, "Jeremy", 4000); -SELECT sys_trx_start INTO @tmp1 FROM t1; -SELECT sys_trx_start INTO @tmp2 FROM t2; -UPDATE t1, t2 SET t1.name="Jerry", t2.name="Jerry" WHERE t1.id=t2.id AND t1.name="Jeremy"; -SELECT @tmp1 < sys_trx_start, name FROM t1; -@tmp1 < sys_trx_start name -1 Jerry -SELECT @tmp2 < sys_trx_start, name FROM t2; -@tmp2 < sys_trx_start name -1 Jerry -SELECT sys_trx_start INTO @tmp1 FROM t1; -SELECT sys_trx_start INTO @tmp2 FROM t2; -UPDATE t1, t2 SET t1.salary=2500, t2.salary=2500 WHERE t1.id=t2.id AND t1.name="Jerry"; -SELECT @tmp1 = sys_trx_start, salary FROM t1; -@tmp1 = sys_trx_start salary -1 2500 -SELECT @tmp2 = sys_trx_start, salary FROM t2; -@tmp2 = sys_trx_start salary -1 2500 -DROP TABLE t1; -DROP TABLE t2; diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index ebcc1155fc9..c1640b6c707 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -5548,68 +5548,3 @@ select (SELECT name FROM t1 WHERE name='tom' AND pw=PASSWORD(@undefined)); NULL drop table t1; End of 10.0 tests -# -# System Versioning Support -# -# -CREATE TABLE t1( x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; -INSERT INTO t1(x, y) VALUES -(0, 100), -(1, 101), -(2, 102), -(3, 103), -(4, 104), -(5, 105), -(6, 106), -(7, 107), -(8, 108), -(9, 109); -DELETE FROM t1 WHERE x = 3; -DELETE FROM t1 WHERE x > 7; -INSERT INTO t1(x, y) VALUES(3, 33); -SELECT @time := Sys_start FROM t1 WHERE x = 3 AND y = 33 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; -@time := Sys_start -Sys_start -SELECT x, y FROM t1; -x y -0 100 -1 101 -2 102 -4 104 -5 105 -6 106 -7 107 -3 33 -SET @query=CONCAT('SELECT x, y FROM t1 FOR SYSTEM_TIME FROM TIMESTAMP \'0-0-0 0:0:0\' TO TIMESTAMP \'', @time, '\''); -PREPARE stmt_t1 FROM @query; -EXECUTE stmt_t1; -x y -0 100 -1 101 -2 102 -3 103 -4 104 -5 105 -6 106 -7 107 -8 108 -9 109 -SET @query=CONCAT('SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP \'0-0-0 0:0:0\' AND TIMESTAMP \'', @time, '\''); -PREPARE stmt_t1 FROM @query; -EXECUTE stmt_t1; -x y -0 100 -1 101 -2 102 -3 103 -4 104 -5 105 -6 106 -7 107 -8 108 -9 109 -3 33 -SET @time=NULL; -SET @query=NULL; -DEALLOCATE PREPARE stmt_t1; -DROP TABLE t1; diff --git a/mysql-test/r/select_jcl6.result b/mysql-test/r/select_jcl6.result index be93151ea6f..9cf4fd85dea 100644 --- a/mysql-test/r/select_jcl6.result +++ b/mysql-test/r/select_jcl6.result @@ -5559,71 +5559,6 @@ select (SELECT name FROM t1 WHERE name='tom' AND pw=PASSWORD(@undefined)); NULL drop table t1; End of 10.0 tests -# -# System Versioning Support -# -# -CREATE TABLE t1( x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; -INSERT INTO t1(x, y) VALUES -(0, 100), -(1, 101), -(2, 102), -(3, 103), -(4, 104), -(5, 105), -(6, 106), -(7, 107), -(8, 108), -(9, 109); -DELETE FROM t1 WHERE x = 3; -DELETE FROM t1 WHERE x > 7; -INSERT INTO t1(x, y) VALUES(3, 33); -SELECT @time := Sys_start FROM t1 WHERE x = 3 AND y = 33 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; -@time := Sys_start -Sys_start -SELECT x, y FROM t1; -x y -0 100 -1 101 -2 102 -4 104 -5 105 -6 106 -7 107 -3 33 -SET @query=CONCAT('SELECT x, y FROM t1 FOR SYSTEM_TIME FROM TIMESTAMP \'0-0-0 0:0:0\' TO TIMESTAMP \'', @time, '\''); -PREPARE stmt_t1 FROM @query; -EXECUTE stmt_t1; -x y -0 100 -1 101 -2 102 -3 103 -4 104 -5 105 -6 106 -7 107 -8 108 -9 109 -SET @query=CONCAT('SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP \'0-0-0 0:0:0\' AND TIMESTAMP \'', @time, '\''); -PREPARE stmt_t1 FROM @query; -EXECUTE stmt_t1; -x y -0 100 -1 101 -2 102 -3 103 -4 104 -5 105 -6 106 -7 107 -8 108 -9 109 -3 33 -SET @time=NULL; -SET @query=NULL; -DEALLOCATE PREPARE stmt_t1; -DROP TABLE t1; set join_cache_level=default; show variables like 'join_cache_level'; Variable_name Value diff --git a/mysql-test/r/select_pkeycache.result b/mysql-test/r/select_pkeycache.result index ebcc1155fc9..c1640b6c707 100644 --- a/mysql-test/r/select_pkeycache.result +++ b/mysql-test/r/select_pkeycache.result @@ -5548,68 +5548,3 @@ select (SELECT name FROM t1 WHERE name='tom' AND pw=PASSWORD(@undefined)); NULL drop table t1; End of 10.0 tests -# -# System Versioning Support -# -# -CREATE TABLE t1( x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; -INSERT INTO t1(x, y) VALUES -(0, 100), -(1, 101), -(2, 102), -(3, 103), -(4, 104), -(5, 105), -(6, 106), -(7, 107), -(8, 108), -(9, 109); -DELETE FROM t1 WHERE x = 3; -DELETE FROM t1 WHERE x > 7; -INSERT INTO t1(x, y) VALUES(3, 33); -SELECT @time := Sys_start FROM t1 WHERE x = 3 AND y = 33 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; -@time := Sys_start -Sys_start -SELECT x, y FROM t1; -x y -0 100 -1 101 -2 102 -4 104 -5 105 -6 106 -7 107 -3 33 -SET @query=CONCAT('SELECT x, y FROM t1 FOR SYSTEM_TIME FROM TIMESTAMP \'0-0-0 0:0:0\' TO TIMESTAMP \'', @time, '\''); -PREPARE stmt_t1 FROM @query; -EXECUTE stmt_t1; -x y -0 100 -1 101 -2 102 -3 103 -4 104 -5 105 -6 106 -7 107 -8 108 -9 109 -SET @query=CONCAT('SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP \'0-0-0 0:0:0\' AND TIMESTAMP \'', @time, '\''); -PREPARE stmt_t1 FROM @query; -EXECUTE stmt_t1; -x y -0 100 -1 101 -2 102 -3 103 -4 104 -5 105 -6 106 -7 107 -8 108 -9 109 -3 33 -SET @time=NULL; -SET @query=NULL; -DEALLOCATE PREPARE stmt_t1; -DROP TABLE t1; diff --git a/mysql-test/r/update.result b/mysql-test/r/update.result index e0e58985adc..73ebb73e313 100644 --- a/mysql-test/r/update.result +++ b/mysql-test/r/update.result @@ -719,146 +719,3 @@ Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 drop table t1, t2; # End of MariaDB 10.0 tests -# -# System Versioning Support -# -# -set @@session.time_zone='+00:00'; -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; -create procedure test_01( -sys_type varchar(255), -engine varchar(255), -fields varchar(255)) -begin -set @str= concat(' - create table t1( - x int unsigned, - y int unsigned, - sys_start ', sys_type, ' generated always as row start, - sys_end ', sys_type, ' generated always as row end, - period for system_time (sys_start, sys_end)) - with system versioning - engine ', engine); -prepare stmt from @str; execute stmt; drop prepare stmt; -insert into t1(x, y) values -(1, 1000), -(2, 2000), -(3, 3000), -(4, 4000), -(5, 5000), -(6, 6000), -(7, 7000), -(8, 8000), -(9, 9000); -select x, y from t1; -update t1 set y = y + 1 where x > 7; -select x, y from t1; -select x, y from t1 for system_time -between timestamp '0000-0-0 0:0:0' - and timestamp '2038-01-19 04:14:07'; -drop table t1; -end~~ -call test_01('timestamp(6)', 'myisam', 'sys_end'); -x y -1 1000 -2 2000 -3 3000 -4 4000 -5 5000 -6 6000 -7 7000 -8 8000 -9 9000 -x y -1 1000 -2 2000 -3 3000 -4 4000 -5 5000 -6 6000 -7 7000 -8 8001 -9 9001 -x y -1 1000 -2 2000 -3 3000 -4 4000 -5 5000 -6 6000 -7 7000 -8 8001 -9 9001 -8 8000 -9 9000 -call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); -x y -1 1000 -2 2000 -3 3000 -4 4000 -5 5000 -6 6000 -7 7000 -8 8000 -9 9000 -x y -1 1000 -2 2000 -3 3000 -4 4000 -5 5000 -6 6000 -7 7000 -8 8001 -9 9001 -x y -1 1000 -2 2000 -3 3000 -4 4000 -5 5000 -6 6000 -7 7000 -8 8001 -9 9001 -8 8000 -9 9000 -drop procedure test_01; -create procedure verify_vtq() -begin -set @i= 0; -select -@i:= @i + 1 as No, -trx_id > 0 as A, -begin_ts > '1-1-1 0:0:0' as B, -commit_ts > begin_ts as C, -concurr_trx is null as D -from information_schema.innodb_vtq -where trx_id > @start_trx_id; -select ifnull(max(trx_id), 0) -into @start_trx_id -from information_schema.innodb_vtq; -end~~ -call verify_vtq; -No A B C D -1 1 1 1 1 -2 1 1 1 1 -drop procedure verify_vtq; -CREATE TABLE t1 ( -id BIGINT PRIMARY KEY, -A INT, -B INT WITHOUT SYSTEM VERSIONING -) WITH SYSTEM VERSIONING; -INSERT INTO t1 VALUES(1, 1, 1); -SELECT sys_trx_start INTO @tmp1 FROM t1; -UPDATE t1 SET A=11, B=11 WHERE id=1; -SELECT @tmp1 < sys_trx_start, A, B FROM t1; -@tmp1 < sys_trx_start A B -1 11 11 -SELECT sys_trx_start INTO @tmp1 FROM t1; -UPDATE t1 SET B=1 WHERE id=1; -SELECT @tmp1 = sys_trx_start, B FROM t1; -@tmp1 = sys_trx_start B -1 1 -DROP TABLE t1; diff --git a/mysql-test/t/auto_increment.test b/mysql-test/t/auto_increment.test index dca4b026c80..7f0ab5dc169 100644 --- a/mysql-test/t/auto_increment.test +++ b/mysql-test/t/auto_increment.test @@ -397,37 +397,3 @@ insert into t1 values(null); select last_insert_id(); select * from t1; drop table t1; - ---echo # ---echo # System Versioning Support ---echo # ---echo # -CREATE TABLE t1(id INT UNSIGNED AUTO_INCREMENT, x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end), PRIMARY KEY (id)) WITH SYSTEM VERSIONING; -CREATE TABLE T1(id INT UNSIGNED AUTO_INCREMENT, x INT UNSIGNED, y INT UNSIGNED, PRIMARY KEY (id)); -INSERT INTO t1(x, y) VALUES(1, 11); -INSERT INTO T1(x, y) VALUES(1, 11); -INSERT INTO t1(x, y) VALUES(2, 12); -INSERT INTO T1(x, y) VALUES(2, 12); -INSERT INTO t1(x, y) VALUES(3, 13); -INSERT INTO T1(x, y) VALUES(3, 13); -INSERT INTO t1(x, y) VALUES(4, 14); -INSERT INTO T1(x, y) VALUES(4, 14); -INSERT INTO t1(x, y) VALUES(5, 15); -INSERT INTO T1(x, y) VALUES(5, 15); -INSERT INTO t1(x, y) VALUES(6, 16); -INSERT INTO T1(x, y) VALUES(6, 16); -INSERT INTO t1(x, y) VALUES(7, 17); -INSERT INTO T1(x, y) VALUES(7, 17); -INSERT INTO t1(x, y) VALUES(8, 18); -INSERT INTO T1(x, y) VALUES(8, 18); -INSERT INTO t1(x, y) VALUES(9, 19); -INSERT INTO T1(x, y) VALUES(9, 19); -SELECT t1.x = T1.x AND t1.y = T1.y, t1.x, t1.y, T1.x, T1.y FROM t1 INNER JOIN T1 ON(t1.id = T1.id); -DELETE FROM t1 WHERE x=2; -DELETE FROM T1 WHERE x=2; -SELECT t1.x = T1.x AND t1.y = T1.y, t1.x, t1.y, T1.x, T1.y FROM t1 INNER JOIN T1 ON(t1.id = T1.id); -DELETE FROM t1 WHERE x>7; -DELETE FROM T1 WHERE x>7; -SELECT t1.x = T1.x AND t1.y = T1.y, t1.x, t1.y, T1.x, T1.y FROM t1 INNER JOIN T1 ON(t1.id = T1.id); -DROP TABLE t1; -DROP TABLE T1; diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index ebdd3794176..6461204f06e 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -1781,160 +1781,3 @@ create table t1; # create table t1 (i int, j int, key(i), key(i)) as select 1 as i, 2 as j; drop table t1; - -# -# Create table SYSTEM VERSIONING -# ---echo # ---echo # Test for SYSTEM VERSIONING CREATE ---echo # - -create table t1 ( - XNo INT UNSIGNED, - Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, - Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, - PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) -) WITH SYSTEM VERSIONING; -SHOW CREATE TABLE t1; - -drop table if exists t1; - ---echo # Versioning fields are set implicitly. -create table t1 ( - XNo INT UNSIGNED -) WITH SYSTEM VERSIONING; -SHOW CREATE TABLE t1; - -drop table if exists t1; - ---error ER_SYS_START_MORE_THAN_ONCE -create table t1 ( - XNo INT UNSIGNED, - Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, - Sys_start2 TIMESTAMP(6) GENERATED ALWAYS AS ROW START, - Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, - PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) -) WITH SYSTEM VERSIONING; - ---error ER_PERIOD_FOR_SYSTEM_TIME_CONTAINS_WRONG_END_COLUMN -create table t1 ( - XNo INT UNSIGNED, - Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, - Sys_end2 TIMESTAMP(6) GENERATED ALWAYS AS ROW END, - PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) -) WITH SYSTEM VERSIONING; - ---error ER_SYS_END_MORE_THAN_ONCE -create table t1 ( - XNo INT UNSIGNED, - Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, - Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, - Sys_end2 TIMESTAMP(6) GENERATED ALWAYS AS ROW END, - PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) -) WITH SYSTEM VERSIONING; - ---error ER_SYS_START_NOT_SPECIFIED -create table t1 ( - XNo INT UNSIGNED, - PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) -) WITH SYSTEM VERSIONING; - ---error ER_SYS_END_MORE_THAN_ONCE -create table t1 ( - XNo INT UNSIGNED, - Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, - Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, - Sys_end2 TIMESTAMP(6) GENERATED ALWAYS AS ROW END, - PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) -); - ---error ER_PERIOD_FOR_SYSTEM_TIME_CONTAINS_WRONG_START_COLUMN -create table t1 ( - XNo INT UNSIGNED, - Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, - Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, - PERIOD FOR SYSTEM_TIME (Sys_insert, Sys_remove) -) WITH SYSTEM VERSIONING; - ---error ER_MISSING_WITH_SYSTEM_VERSIONING -create table t1 ( - XNo INT UNSIGNED, - Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, - Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, - PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) -); - ---error ER_SYS_START_AND_SYS_END_SAME -create table t1 ( - XNo INT UNSIGNED, - Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, - Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, - PERIOD FOR SYSTEM_TIME (Sys_start, Sys_start) -); - ---error ER_SYS_START_FIELD_MUST_BE_TIMESTAMP -create table t1 ( - XNo INT UNSIGNED, - Sys_start INT GENERATED ALWAYS AS ROW START, - Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, - PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) -) WITH SYSTEM VERSIONING; - ---error ER_SYS_END_FIELD_MUST_BE_TIMESTAMP -create table t1 ( - XNo INT UNSIGNED, - Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, - Sys_end INT GENERATED ALWAYS AS ROW END, - PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) -) WITH SYSTEM VERSIONING; - -CREATE TABLE t1 ( - A INT WITH SYSTEM VERSIONING, - B INT -); -SHOW CREATE TABLE t1; -DROP TABLE t1; - -CREATE TABLE t1 ( - A INT WITH SYSTEM VERSIONING, - B INT -) WITH SYSTEM VERSIONING; -SHOW CREATE TABLE t1; -DROP TABLE t1; - ---error ER_NO_VERSIONED_FIELDS_IN_VERSIONED_TABLE -CREATE TABLE t1 ( - A INT, - B INT WITHOUT SYSTEM VERSIONING -); - -CREATE TABLE t1 ( - A INT, - B INT WITHOUT SYSTEM VERSIONING -) WITH SYSTEM VERSIONING; -SHOW CREATE TABLE t1; -DROP TABLE t1; - -CREATE TABLE t1 ( - A INT WITH SYSTEM VERSIONING, - B INT WITHOUT SYSTEM VERSIONING -); -SHOW CREATE TABLE t1; -DROP TABLE t1; - -CREATE TABLE t1 ( - A INT WITH SYSTEM VERSIONING, - B INT WITHOUT SYSTEM VERSIONING -) WITH SYSTEM VERSIONING; -SHOW CREATE TABLE t1; -DROP TABLE t1; - ---error ER_NO_VERSIONED_FIELDS_IN_VERSIONED_TABLE -CREATE TABLE t1 ( - A INT WITHOUT SYSTEM VERSIONING -); - ---error ER_NO_VERSIONED_FIELDS_IN_VERSIONED_TABLE -CREATE TABLE t1 ( - A INT WITHOUT SYSTEM VERSIONING -) WITH SYSTEM VERSIONING; diff --git a/mysql-test/t/delete.opt b/mysql-test/t/delete.opt deleted file mode 100644 index 32a25eea24f..00000000000 --- a/mysql-test/t/delete.opt +++ /dev/null @@ -1 +0,0 @@ ---loose-innodb-vtq diff --git a/mysql-test/t/delete.test b/mysql-test/t/delete.test index 00e06f27243..c82420640c2 100644 --- a/mysql-test/t/delete.test +++ b/mysql-test/t/delete.test @@ -582,88 +582,3 @@ DELETE v2 FROM v2; DROP VIEW v2, v1; DROP TABLE t1, t2; - -# -# SQL DELETE for SYSTEM VERSIONING -# ---echo # ---echo # System Versioning Support ---echo # ---echo # - --- source include/have_innodb.inc -set @@session.time_zone='+00:00'; -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; - -delimiter ~~; -create procedure test_01( - sys_type varchar(255), - engine varchar(255), - fields varchar(255)) -begin - set @str= concat(' - create table t1( - XNo int unsigned, - sys_start ', sys_type, ' generated always as row start, - sys_end ', sys_type, ' generated always as row end, - period for system_time (sys_start, sys_end)) - with system versioning - engine ', engine); - prepare stmt from @str; execute stmt; drop prepare stmt; - insert into t1(XNo) values(0); - insert into t1(XNo) values(1); - insert into t1(XNo) values(2); - insert into t1(XNo) values(3); - insert into t1(XNo) values(4); - insert into t1(XNo) values(5); - insert into t1(XNo) values(6); - insert into t1(XNo) values(7); - insert into t1(XNo) values(8); - insert into t1(XNo) values(9); - set @str= concat('select XNo, ', - fields, " < '2038-01-19 03:14:07' - from t1 for system_time - between timestamp '0000-0-0 0:0:0' - and timestamp '2038-01-19 04:14:07'"); - prepare stmt from @str; execute stmt; - delete from t1 where XNo = 0; - execute stmt; - delete from t1 where XNo = 1; - execute stmt; - delete from t1 where XNo > 5; - create view vt1 as select XNo from t1; - select XNo from vt1; - delete from vt1 where XNo = 3; - select XNo from vt1; - execute stmt; drop prepare stmt; - drop view vt1; - drop table t1; -end~~ -delimiter ;~~ - -call test_01('timestamp(6)', 'myisam', 'sys_end'); -call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); -drop procedure test_01; - -# VTQ test - -delimiter ~~; -create procedure verify_vtq() -begin - set @i= 0; - select - @i:= @i + 1 as No, - trx_id > 0 as A, - begin_ts > '1-1-1 0:0:0' as B, - commit_ts > begin_ts as C, - concurr_trx is null as D - from information_schema.innodb_vtq - where trx_id > @start_trx_id; - select ifnull(max(trx_id), 0) - into @start_trx_id - from information_schema.innodb_vtq; -end~~ -delimiter ;~~ - -call verify_vtq; -drop procedure verify_vtq; diff --git a/mysql-test/t/insert.opt b/mysql-test/t/insert.opt deleted file mode 100644 index 32a25eea24f..00000000000 --- a/mysql-test/t/insert.opt +++ /dev/null @@ -1 +0,0 @@ ---loose-innodb-vtq diff --git a/mysql-test/t/insert.test b/mysql-test/t/insert.test index ed4fb5ecc68..206c5553100 100644 --- a/mysql-test/t/insert.test +++ b/mysql-test/t/insert.test @@ -573,186 +573,3 @@ insert ignore into t1 values (1,12) on duplicate key update f2=13; set @@old_mode=""; insert ignore into t1 values (1,12); DROP TABLE t1; - ---echo # ---echo # System Versioning Support ---echo # ---echo # - --- source include/have_innodb.inc -set @@session.time_zone='+00:00'; -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; - -delimiter ~~; -create procedure test_01( - sys_type varchar(255), - engine varchar(255), - fields varchar(255)) -begin - set @str= concat(' - create table t1( - x int unsigned, - y int unsigned, - sys_start ', sys_type, ' generated always as row start, - sys_end ', sys_type, ' generated always as row end, - period for system_time (sys_start, sys_end)) - with system versioning - engine ', engine); - prepare stmt from @str; execute stmt; drop prepare stmt; - insert into t1(x, y) values(3, 4); - insert into t1(x, y) values(2, 3); - insert into t1 values(40, 33); - set @str= concat('select x, y, ', fields, ' from t1'); - prepare stmt from @str; execute stmt; drop prepare stmt; - drop table t1; -end~~ -delimiter ;~~ - -call test_01('timestamp(6)', 'myisam', 'sys_end'); -call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); -drop procedure test_01; - -delimiter ~~; -create procedure test_02( - sys_type varchar(255), - engine varchar(255), - fields varchar(255)) -begin - set @str= concat(' - create table t1( - id int unsigned auto_increment primary key, - x int unsigned, - y int unsigned, - sys_start ', sys_type, ' generated always as row start, - sys_end ', sys_type, ' generated always as row end, - period for system_time (sys_start, sys_end)) - with system versioning - engine ', engine); - prepare stmt from @str; execute stmt; drop prepare stmt; - insert into t1(x, y) values(33, 44); - insert into t1(id, x, y) values(20, 33, 44); - insert into t1 values(40, 33, 44); - set @str= concat('select id, x, y, ', fields, ' from t1'); - prepare stmt from @str; execute stmt; drop prepare stmt; - drop table t1; -end~~ -delimiter ;~~ - -call test_02('timestamp(6)', 'myisam', 'sys_end'); -call test_02('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); -drop procedure test_02; - -delimiter ~~; -create procedure test_03( - sys_type varchar(255), - engine varchar(255), - fields varchar(255)) -begin - set @str= concat(' - create table t1( - x int unsigned, - y int unsigned, - sys_start ', sys_type, ' generated always as row start, - sys_end ', sys_type, ' generated always as row end, - period for system_time (sys_start, sys_end)) - with system versioning - engine ', engine); - prepare stmt from @str; execute stmt; drop prepare stmt; - create view vt1_1 as select x, y from t1; - create view vt1_2 as select x, y, sys_end from t1; - insert into t1(x, y) values(8001, 9001); - insert into vt1_1(x, y) values(1001, 2001); - insert into vt1_1 values(1002, 2002); - insert into vt1_2(x, y) values(3001, 4001); - set @str= concat('select x, y, ', fields, ' from t1'); - prepare stmt from @str; execute stmt; drop prepare stmt; - select x, y from vt1_1; - set @str= concat('select x, y, ', fields, ' from vt1_2'); - prepare stmt from @str; execute stmt; drop prepare stmt; -end~~ -delimiter ;~~ - -call test_03('timestamp(6)', 'myisam', 'sys_end'); ---ERROR ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER -insert into t1(x, y, sys_end) values(8001, 9001, '2015-1-1 1:1:1'); ---ERROR ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER -insert into vt1_2 values(3002, 4002, '2015-2-2 2:2:2'); -drop table t1; -drop view vt1_1; -drop view vt1_2; - -call test_03('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); ---ERROR ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER -insert into t1(x, y, sys_end) values(8001, 9001, 1111111); ---ERROR ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER -insert into vt1_2 values(3002, 4002, 2222222); -drop table t1; -drop view vt1_1; -drop view vt1_2; -drop procedure test_03; - -# VTQ test - -delimiter ~~; -create procedure verify_vtq() -begin - set @i= 0; - select - @i:= @i + 1 as No, - trx_id > 0 as A, - begin_ts > '1-1-1 0:0:0' as B, - commit_ts > begin_ts as C, - concurr_trx is null as D - from information_schema.innodb_vtq - where trx_id > @start_trx_id; - select ifnull(max(trx_id), 0) - into @start_trx_id - from information_schema.innodb_vtq; -end~~ -delimiter ;~~ - -call verify_vtq; - -create table t1( - x int unsigned, - sys_start bigint unsigned generated always as row start, - sys_end bigint unsigned generated always as row end, - period for system_time (sys_start, sys_end)) -with system versioning engine=innodb; - -create table t2(x int unsigned) engine=innodb; - -start transaction; -insert into t1(x) values(1); -commit; -call verify_vtq; - -start transaction; -insert into t2(x) values(1); -savepoint a; -insert into t1(x) values(1); -rollback to a; -commit; -call verify_vtq; - -drop table t1; -drop table t2; -drop procedure verify_vtq; - -# Check whether it is possible to insert rows in a versioned table -# with implicit fields without crash. -CREATE TABLE t1( - id BIGINT PRIMARY KEY, - A INT, - B INT -) WITH SYSTEM VERSIONING; -INSERT INTO t1 VALUES(1, 1, 1); -DROP TABLE t1; - -CREATE TABLE t1( - id BIGINT PRIMARY KEY, - A INT, - B INT -) WITH SYSTEM VERSIONING ENGINE=INNODB; -INSERT INTO t1 VALUES(1, 1, 1); -DROP TABLE t1; diff --git a/mysql-test/t/insert_select.opt b/mysql-test/t/insert_select.opt deleted file mode 100644 index 32a25eea24f..00000000000 --- a/mysql-test/t/insert_select.opt +++ /dev/null @@ -1 +0,0 @@ ---loose-innodb-vtq diff --git a/mysql-test/t/insert_select.test b/mysql-test/t/insert_select.test index d2826fceec8..fda89f18d99 100644 --- a/mysql-test/t/insert_select.test +++ b/mysql-test/t/insert_select.test @@ -425,86 +425,3 @@ SET GLOBAL myisam_data_pointer_size = @old_myisam_data_pointer_size; DROP TABLE t1; --echo End of 5.1 tests - ---echo # ---echo # System Versioning Support ---echo # ---echo # - --- source include/have_innodb.inc -set @@session.time_zone='+00:00'; -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; - -delimiter ~~; -create procedure test_01( - sys_type varchar(255), - engine varchar(255), - fields varchar(255)) -begin - set @str= concat('( - x int unsigned, - y int unsigned, - sys_start ', sys_type, ' generated always as row start, - sys_end ', sys_type, ' generated always as row end, - period for system_time (sys_start, sys_end)) - with system versioning - engine ', engine); - set @str2= concat('create table t1', @str); - prepare stmt from @str2; execute stmt; drop prepare stmt; - set @str2= concat('create table t2', @str); - prepare stmt from @str2; execute stmt; drop prepare stmt; - insert into t1(x, y) values - (1, 1000), - (2, 2000), - (3, 3000), - (4, 4000), - (5, 5000), - (6, 6000), - (7, 7000), - (8, 8000), - (9, 9000); - delete from t1 where x >= 1; - insert into t1(x, y) values - (1, 1001), - (2, 2001), - (3, 3001), - (4, 4001), - (5, 5001), - (6, 6001), - (7, 7001), - (8, 8001), - (9, 9001); - insert into t2 select x, y from t1 for system_time between timestamp '0000-0-0 0:0:0' and timestamp '9999-1-1 0:0:0'; - select x, y from t1; - select x, y from t2; - drop table t1; - drop table t2; -end~~ -delimiter ;~~ - -call test_01('timestamp(6)', 'myisam', 'sys_end'); -call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); -drop procedure test_01; - -# VTQ test - -delimiter ~~; -create procedure verify_vtq() -begin - set @i= 0; - select - @i:= @i + 1 as No, - trx_id > 0 as A, - begin_ts > '1-1-1 0:0:0' as B, - commit_ts > begin_ts as C, - concurr_trx is null as D - from information_schema.innodb_vtq - where trx_id > @start_trx_id; - select ifnull(max(trx_id), 0) - into @start_trx_id - from information_schema.innodb_vtq; -end~~ -delimiter ;~~ - -call verify_vtq; -drop procedure verify_vtq; diff --git a/mysql-test/t/insert_update.opt b/mysql-test/t/insert_update.opt deleted file mode 100644 index 32a25eea24f..00000000000 --- a/mysql-test/t/insert_update.opt +++ /dev/null @@ -1 +0,0 @@ ---loose-innodb-vtq diff --git a/mysql-test/t/insert_update.test b/mysql-test/t/insert_update.test index f2b571fba7e..7234973eeb8 100644 --- a/mysql-test/t/insert_update.test +++ b/mysql-test/t/insert_update.test @@ -311,76 +311,3 @@ insert into t1(f1) values(1) on duplicate key update f1=1; select @stamp2:=f2 from t1; select if( @stamp1 = @stamp2, "correct", "wrong"); drop table t1; - ---echo # ---echo # System Versioning Support ---echo # ---echo # - --- source include/have_innodb.inc -set @@session.time_zone='+00:00'; -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; - -delimiter ~~; -create procedure test_01( - sys_type varchar(255), - engine varchar(255), - fields varchar(255)) -begin - set @str= concat(' - create table t1( - x int unsigned, - y int unsigned, - sys_start ', sys_type, ' generated always as row start, - sys_end ', sys_type, ' generated always as row end, - period for system_time (sys_start, sys_end), - primary key(x, y)) - with system versioning - engine ', engine); - prepare stmt from @str; execute stmt; drop prepare stmt; - insert into t1(x, y) values - (1, 1000), - (2, 2000), - (3, 3000), - (4, 4000), - (5, 5000), - (6, 6000), - (7, 7000), - (8, 8000), - (9, 9000); - insert into t1(x, y) values(3, 3000) on duplicate key update y = y+1; - insert into t1(x, y) values(4, 4000) on duplicate key update y = y+1; - insert into t1(x, y) values(4, 4001) on duplicate key update y = y+1; - insert into t1(x, y) values(4, 4444) on duplicate key update y = y+1; - select x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp '9999-1-1 0:0:0'; - select x, y from t1; - drop table t1; -end~~ -delimiter ;~~ - -call test_01('timestamp(6)', 'myisam', 'sys_end'); -call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); -drop procedure test_01; - -# VTQ test - -delimiter ~~; -create procedure verify_vtq() -begin - set @i= 0; - select - @i:= @i + 1 as No, - trx_id > 0 as A, - begin_ts > '1-1-1 0:0:0' as B, - commit_ts > begin_ts as C, - concurr_trx is null as D - from information_schema.innodb_vtq - where trx_id > @start_trx_id; - select ifnull(max(trx_id), 0) - into @start_trx_id - from information_schema.innodb_vtq; -end~~ -delimiter ;~~ - -call verify_vtq; -drop procedure verify_vtq; diff --git a/mysql-test/t/multi_update.opt b/mysql-test/t/multi_update.opt deleted file mode 100644 index 32a25eea24f..00000000000 --- a/mysql-test/t/multi_update.opt +++ /dev/null @@ -1 +0,0 @@ ---loose-innodb-vtq diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test index 3ee7ab3bcf4..4ed90369c27 100644 --- a/mysql-test/t/multi_update.test +++ b/mysql-test/t/multi_update.test @@ -986,7 +986,7 @@ drop table t1,t2,t3; --echo end of 5.5 tests -#--source include/have_xtradb.inc +--source include/have_xtradb.inc --echo --echo # Bug mdev-5970 @@ -1035,116 +1035,3 @@ DROP TABLE table_11757486; SET SESSION SQL_MODE=default; --echo end of 10.0 tests - ---echo # ---echo # System Versioning Support ---echo # ---echo # - --- source include/have_innodb.inc -set @@session.time_zone='+00:00'; -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; - -delimiter ~~; -create procedure test_01( - sys_type varchar(255), - engine varchar(255), - fields varchar(255)) -begin - set @str= concat('( - x int unsigned, - y int unsigned, - sys_start ', sys_type, ' generated always as row start, - sys_end ', sys_type, ' generated always as row end, - period for system_time (sys_start, sys_end)) - with system versioning - engine ', engine); - set @str2= concat('create table t1', @str); - prepare stmt from @str2; execute stmt; drop prepare stmt; - set @str2= concat('create table t2', @str); - prepare stmt from @str2; execute stmt; drop prepare stmt; - insert into t1(x, y) values - (1, 1000), - (2, 2000), - (3, 3000), - (4, 4000), - (5, 5000), - (6, 6000), - (7, 7000), - (8, 8000), - (9, 9000); - insert into t2(x, y) values - (1, 1010), - (2, 2010), - (3, 3010), - (4, 4010), - (5, 5010), - (6, 6010), - (7, 7010), - (8, 8010), - (9, 9010); - update t1, t2 set t1.y = t1.x + t1.y, t2.y = t2.x + t2.y where t1.x > 7 and t2.x < 7; - select x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp '9999-1-1 0:0:0'; - select x, y from t1; - select x, y from t2 for system_time between timestamp '0-0-0 0:0:0' and timestamp '9999-1-1 0:0:0'; - select x, y from t2; - drop table t1; - drop table t2; -end~~ -delimiter ;~~ - -call test_01('timestamp(6)', 'myisam', 'sys_end'); -call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); -drop procedure test_01; - -# VTQ test - -delimiter ~~; -create procedure verify_vtq() -begin - set @i= 0; - select - @i:= @i + 1 as No, - trx_id > 0 as A, - begin_ts > '1-1-1 0:0:0' as B, - commit_ts > begin_ts as C, - concurr_trx is null as D - from information_schema.innodb_vtq - where trx_id > @start_trx_id; - select ifnull(max(trx_id), 0) - into @start_trx_id - from information_schema.innodb_vtq; -end~~ -delimiter ;~~ - -call verify_vtq; -drop procedure verify_vtq; - -CREATE TABLE t1 ( - id BIGINT PRIMARY KEY, - name VARCHAR(128) WITH SYSTEM VERSIONING, - salary BIGINT -); -INSERT INTO t1 VALUES (1, "Jeremy", 3000); - -CREATE TABLE t2 ( - id BIGINT PRIMARY KEY, - name VARCHAR(128) WITH SYSTEM VERSIONING, - salary BIGINT -); -INSERT INTO t2 VALUES (1, "Jeremy", 4000); - -SELECT sys_trx_start INTO @tmp1 FROM t1; -SELECT sys_trx_start INTO @tmp2 FROM t2; -UPDATE t1, t2 SET t1.name="Jerry", t2.name="Jerry" WHERE t1.id=t2.id AND t1.name="Jeremy"; -SELECT @tmp1 < sys_trx_start, name FROM t1; -SELECT @tmp2 < sys_trx_start, name FROM t2; - -SELECT sys_trx_start INTO @tmp1 FROM t1; -SELECT sys_trx_start INTO @tmp2 FROM t2; -UPDATE t1, t2 SET t1.salary=2500, t2.salary=2500 WHERE t1.id=t2.id AND t1.name="Jerry"; -SELECT @tmp1 = sys_trx_start, salary FROM t1; -SELECT @tmp2 = sys_trx_start, salary FROM t2; - -DROP TABLE t1; -DROP TABLE t2; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 8f3055850b9..d216b003c78 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -4671,37 +4671,3 @@ select (SELECT name FROM t1 WHERE name='tom' AND pw=PASSWORD(@undefined)); drop table t1; --echo End of 10.0 tests - ---echo # ---echo # System Versioning Support ---echo # ---echo # -CREATE TABLE t1( x INT UNSIGNED, y INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, Sys_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end)) WITH SYSTEM VERSIONING; -INSERT INTO t1(x, y) VALUES - (0, 100), - (1, 101), - (2, 102), - (3, 103), - (4, 104), - (5, 105), - (6, 106), - (7, 107), - (8, 108), - (9, 109); -DELETE FROM t1 WHERE x = 3; -DELETE FROM t1 WHERE x > 7; ---real_sleep 1 -INSERT INTO t1(x, y) VALUES(3, 33); ---replace_column 1 Sys_start -SELECT @time := Sys_start FROM t1 WHERE x = 3 AND y = 33 FOR SYSTEM_TIME BETWEEN TIMESTAMP '0-0-0 0:0:0' AND TIMESTAMP '2038-01-19 04:14:07'; -SELECT x, y FROM t1; -SET @query=CONCAT('SELECT x, y FROM t1 FOR SYSTEM_TIME FROM TIMESTAMP \'0-0-0 0:0:0\' TO TIMESTAMP \'', @time, '\''); -PREPARE stmt_t1 FROM @query; -EXECUTE stmt_t1; -SET @query=CONCAT('SELECT x, y FROM t1 FOR SYSTEM_TIME BETWEEN TIMESTAMP \'0-0-0 0:0:0\' AND TIMESTAMP \'', @time, '\''); -PREPARE stmt_t1 FROM @query; -EXECUTE stmt_t1; -SET @time=NULL; -SET @query=NULL; -DEALLOCATE PREPARE stmt_t1; -DROP TABLE t1; diff --git a/mysql-test/t/update.opt b/mysql-test/t/update.opt deleted file mode 100644 index 32a25eea24f..00000000000 --- a/mysql-test/t/update.opt +++ /dev/null @@ -1 +0,0 @@ ---loose-innodb-vtq diff --git a/mysql-test/t/update.test b/mysql-test/t/update.test index 41d59199e47..e5ef0b11127 100644 --- a/mysql-test/t/update.test +++ b/mysql-test/t/update.test @@ -654,93 +654,3 @@ show status like 'Handler_read%'; drop table t1, t2; --echo # End of MariaDB 10.0 tests - ---echo # ---echo # System Versioning Support ---echo # ---echo # - --- source include/have_innodb.inc -set @@session.time_zone='+00:00'; -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; - -delimiter ~~; -create procedure test_01( - sys_type varchar(255), - engine varchar(255), - fields varchar(255)) -begin - set @str= concat(' - create table t1( - x int unsigned, - y int unsigned, - sys_start ', sys_type, ' generated always as row start, - sys_end ', sys_type, ' generated always as row end, - period for system_time (sys_start, sys_end)) - with system versioning - engine ', engine); - prepare stmt from @str; execute stmt; drop prepare stmt; - insert into t1(x, y) values - (1, 1000), - (2, 2000), - (3, 3000), - (4, 4000), - (5, 5000), - (6, 6000), - (7, 7000), - (8, 8000), - (9, 9000); - select x, y from t1; - update t1 set y = y + 1 where x > 7; - select x, y from t1; - select x, y from t1 for system_time - between timestamp '0000-0-0 0:0:0' - and timestamp '2038-01-19 04:14:07'; - drop table t1; -end~~ -delimiter ;~~ - -call test_01('timestamp(6)', 'myisam', 'sys_end'); -call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); -drop procedure test_01; - -# VTQ test - -delimiter ~~; -create procedure verify_vtq() -begin - set @i= 0; - select - @i:= @i + 1 as No, - trx_id > 0 as A, - begin_ts > '1-1-1 0:0:0' as B, - commit_ts > begin_ts as C, - concurr_trx is null as D - from information_schema.innodb_vtq - where trx_id > @start_trx_id; - select ifnull(max(trx_id), 0) - into @start_trx_id - from information_schema.innodb_vtq; -end~~ -delimiter ;~~ - -call verify_vtq; -drop procedure verify_vtq; - -CREATE TABLE t1 ( - id BIGINT PRIMARY KEY, - A INT, - B INT WITHOUT SYSTEM VERSIONING -) WITH SYSTEM VERSIONING; - -INSERT INTO t1 VALUES(1, 1, 1); - -SELECT sys_trx_start INTO @tmp1 FROM t1; -UPDATE t1 SET A=11, B=11 WHERE id=1; -SELECT @tmp1 < sys_trx_start, A, B FROM t1; - -SELECT sys_trx_start INTO @tmp1 FROM t1; -UPDATE t1 SET B=1 WHERE id=1; -SELECT @tmp1 = sys_trx_start, B FROM t1; - -DROP TABLE t1; -- cgit v1.2.1 From 01c9d1c97fdfc5b72e967aaac0ebf29a039bd3d5 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 18 Oct 2016 16:35:52 +0000 Subject: SQL: SP idempotency fix Fixes #52 --- .../suite/versioning/r/auto_increment.result | 38 +++++++++++++++++++ mysql-test/suite/versioning/t/auto_increment.test | 3 +- sql/sql_select.cc | 44 +++++++++++++--------- 3 files changed, 66 insertions(+), 19 deletions(-) diff --git a/mysql-test/suite/versioning/r/auto_increment.result b/mysql-test/suite/versioning/r/auto_increment.result index bd1c3f9828e..9dc0075d06d 100644 --- a/mysql-test/suite/versioning/r/auto_increment.result +++ b/mysql-test/suite/versioning/r/auto_increment.result @@ -93,7 +93,45 @@ A x y x y 1 5 15 5 15 1 6 16 6 16 1 7 17 7 17 +call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +A x y x y +1 1 11 1 11 +1 2 12 2 12 +1 3 13 3 13 +1 4 14 4 14 +1 5 15 5 15 +1 6 16 6 16 +1 7 17 7 17 +1 8 18 8 18 +1 9 19 9 19 +A x y x y +1 1 11 1 11 +1 3 13 3 13 +1 4 14 4 14 +1 5 15 5 15 +1 6 16 6 16 +1 7 17 7 17 +1 8 18 8 18 +1 9 19 9 19 +A x y x y +1 1 11 1 11 +1 3 13 3 13 +1 4 14 4 14 +1 5 15 5 15 +1 6 16 6 16 +1 7 17 7 17 call verify_vtq; No A B C D +1 1 1 1 1 +2 1 1 1 1 +3 1 1 1 1 +4 1 1 1 1 +5 1 1 1 1 +6 1 1 1 1 +7 1 1 1 1 +8 1 1 1 1 +9 1 1 1 1 +10 1 1 1 1 +11 1 1 1 1 drop procedure test_01; drop procedure verify_vtq; diff --git a/mysql-test/suite/versioning/t/auto_increment.test b/mysql-test/suite/versioning/t/auto_increment.test index 4872428ff7d..dac46caed06 100644 --- a/mysql-test/suite/versioning/t/auto_increment.test +++ b/mysql-test/suite/versioning/t/auto_increment.test @@ -60,8 +60,7 @@ end~~ delimiter ;~~ call test_01('timestamp(6)', 'myisam', 'sys_end'); -# Issue #52 -# call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); call verify_vtq; drop procedure test_01; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index eec6f742d9d..4e7ca4663b1 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -701,44 +701,54 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LE if (select_lex->saved_where) { DBUG_ASSERT(thd->stmt_arena->is_sp_execute()); - *where_expr= select_lex->saved_where; + /* 2. this copy_andor_structure() is also required by the same reason */ + *where_expr= select_lex->saved_where->copy_andor_structure(thd); } else if (thd->stmt_arena->is_sp_execute()) { if (thd->stmt_arena->is_stmt_execute()) // SP executed second time (STMT_EXECUTED) *where_expr= 0; else if (*where_expr) // SP executed first time (STMT_INITIALIZED_FOR_SP) - /* copy_andor_structure() is required since this andor tree + /* 1. copy_andor_structure() is required since this andor tree is modified later (and on shorter arena) */ select_lex->saved_where= (*where_expr)->copy_andor_structure(thd); } - for (table= tables; table; table= table->next_local) + /* We have to save also non-versioned on_expr since we may have + conjuction of versioned + non-versioned */ + if (thd->stmt_arena->is_sp_execute()) { - if (table->table && table->table->versioned()) + for (table= tables; table; table= table->next_local) { - COND** dst_cond= where_expr; + if (!table->table) + continue; + if (table->saved_on_expr) // same logic as saved_where { - DBUG_ASSERT(thd->stmt_arena->is_sp_execute()); if (table->on_expr) - { - table->on_expr= table->saved_on_expr; - dst_cond= &table->on_expr; - } + table->on_expr= table->saved_on_expr->copy_andor_structure(thd); else - { // on_expr was moved to WHERE (see below: Add ON expression to the WHERE) - *dst_cond= and_items(thd, + *where_expr= and_items(thd, *where_expr, - table->saved_on_expr); - } + table->saved_on_expr->copy_andor_structure(thd)); + } + else if (table->on_expr && + thd->stmt_arena->state == Query_arena::STMT_INITIALIZED_FOR_SP) + { + table->saved_on_expr= table->on_expr->copy_andor_structure(thd); } - else if (table->on_expr) + } + } + + for (table= tables; table; table= table->next_local) + { + if (table->table && table->table->versioned()) + { + COND** dst_cond= where_expr; + if (table->on_expr) { dst_cond= &table->on_expr; - if (thd->stmt_arena->state == Query_arena::STMT_INITIALIZED_FOR_SP) - table->saved_on_expr= table->on_expr->copy_andor_structure(thd); } Field *fstart= table->table->vers_start_field(); -- cgit v1.2.1 From 5dea51657d8c27361c012db0c9bcdc30f657e0ae Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Thu, 20 Oct 2016 09:12:41 +0000 Subject: IB: optimized update for non-versioned fields Fixes #53 --- mysql-test/suite/versioning/r/update.result | 37 +++++++++++++++-------- mysql-test/suite/versioning/t/auto_increment.test | 1 + mysql-test/suite/versioning/t/update.test | 15 +++++---- storage/innobase/handler/ha_innodb.cc | 18 ++++++++++- storage/innobase/include/row0upd.h | 1 + storage/innobase/row/row0ins.cc | 4 +-- storage/innobase/row/row0mysql.cc | 3 +- storage/innobase/row/row0upd.cc | 2 ++ 8 files changed, 57 insertions(+), 24 deletions(-) diff --git a/mysql-test/suite/versioning/r/update.result b/mysql-test/suite/versioning/r/update.result index 06fb2186d7d..ff0874799b0 100644 --- a/mysql-test/suite/versioning/r/update.result +++ b/mysql-test/suite/versioning/r/update.result @@ -56,19 +56,19 @@ begin set @str= concat(' create table t1 ( id bigint primary key, - a int, - b int without system versioning) + x int, + y int without system versioning) with system versioning engine ', engine); prepare stmt from @str; execute stmt; drop prepare stmt; insert into t1 values(1, 1, 1); set @ins_t= now(6); select sys_trx_start into @tmp1 from t1; -update t1 set a=11, b=11 where id=1; -select @tmp1 < sys_trx_start, a, b from t1; +update t1 set x= 11, y= 11 where id = 1; +select @tmp1 < sys_trx_start as A1, x, y from t1; select sys_trx_start into @tmp1 from t1; -update t1 set b=1 where id=1; -select @tmp1 = sys_trx_start, b from t1; +update t1 set y= 1 where id = 1; +select @tmp1 = sys_trx_start as A2, x from t1; drop table t1; end~~ create procedure test_03( @@ -292,15 +292,15 @@ x y 8 8000 9 9000 call test_02('timestamp(6)', 'myisam', 'sys_end'); -@tmp1 < sys_trx_start a b +A1 x y 1 11 11 -@tmp1 = sys_trx_start b -1 1 +A2 x +1 11 call test_02('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); -@tmp1 < sys_trx_start a b +A1 x y 1 11 11 -@tmp1 = sys_trx_start b -0 1 +A2 x +1 11 call test_03('timestamp(6)', 'myisam', 'sys_end'); x y 1 1 @@ -489,6 +489,15 @@ B1 salary 1 2500 B2 salary 1 2500 +call test_07('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +A1 name +1 Jerry +A2 name +1 Jerry +B1 salary +1 2500 +B2 salary +1 2500 call verify_vtq; No A B C D 1 1 1 1 1 @@ -509,6 +518,10 @@ No A B C D 16 1 1 1 1 17 1 1 1 1 18 1 1 1 1 +19 1 1 1 1 +20 1 1 1 1 +21 1 1 1 1 +22 1 1 1 1 drop procedure test_01; drop procedure test_02; drop procedure test_03; diff --git a/mysql-test/suite/versioning/t/auto_increment.test b/mysql-test/suite/versioning/t/auto_increment.test index dac46caed06..978a0eec9d4 100644 --- a/mysql-test/suite/versioning/t/auto_increment.test +++ b/mysql-test/suite/versioning/t/auto_increment.test @@ -65,3 +65,4 @@ call verify_vtq; drop procedure test_01; drop procedure verify_vtq; + diff --git a/mysql-test/suite/versioning/t/update.test b/mysql-test/suite/versioning/t/update.test index f875a41ad3f..9ca7fee4126 100644 --- a/mysql-test/suite/versioning/t/update.test +++ b/mysql-test/suite/versioning/t/update.test @@ -43,20 +43,20 @@ begin set @str= concat(' create table t1 ( id bigint primary key, - a int, - b int without system versioning) + x int, + y int without system versioning) with system versioning engine ', engine); prepare stmt from @str; execute stmt; drop prepare stmt; insert into t1 values(1, 1, 1); set @ins_t= now(6); select sys_trx_start into @tmp1 from t1; - update t1 set a=11, b=11 where id=1; - select @tmp1 < sys_trx_start, a, b from t1; + update t1 set x= 11, y= 11 where id = 1; + select @tmp1 < sys_trx_start as A1, x, y from t1; select sys_trx_start into @tmp1 from t1; - update t1 set b=1 where id=1; - select @tmp1 = sys_trx_start, b from t1; + update t1 set y= 1 where id = 1; + select @tmp1 = sys_trx_start as A2, x from t1; drop table t1; end~~ @@ -252,8 +252,7 @@ call test_06('timestamp(6)', 'myisam', 'sys_end'); call test_06('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); call test_07('timestamp(6)', 'myisam', 'sys_end'); -# Issue #53 -# call test_07('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_07('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); call verify_vtq; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 8d0a742fa89..8eed719d748 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -8959,6 +8959,8 @@ calc_row_difference( /* We use upd_buff to convert changed fields */ buf = (byte*) upd_buff; + prebuilt->upd_node->versioned = false; + for (i = 0; i < table->s->fields; i++) { field = table->field[i]; bool is_virtual = innobase_is_v_fld(field); @@ -9199,6 +9201,13 @@ calc_row_difference( } n_changed++; + if (!prebuilt->upd_node->versioned && + DICT_TF2_FLAG_IS_SET(prebuilt->table, DICT_TF2_VERSIONED) && + !(field->flags & WITHOUT_SYSTEM_VERSIONING_FLAG)) + { + prebuilt->upd_node->versioned = true; + } + /* If an FTS indexed column was changed by this UPDATE then we need to inform the FTS sub-system. @@ -9303,6 +9312,13 @@ calc_row_difference( innodb_table, ufield, &trx->fts_next_doc_id); ++n_changed; + + if (!prebuilt->upd_node->versioned && + DICT_TF2_FLAG_IS_SET(prebuilt->table, DICT_TF2_VERSIONED) && + !(field->flags & WITHOUT_SYSTEM_VERSIONING_FLAG)) + { + prebuilt->upd_node->versioned = true; + } } else { /* We have a Doc ID column, but none of FTS indexed columns are touched, nor the Doc ID column, so set @@ -9486,7 +9502,7 @@ ha_innobase::update_row( error = row_update_for_mysql((byte*) old_row, m_prebuilt); - if (error == DB_SUCCESS && DICT_TF2_FLAG_IS_SET(m_prebuilt->table, DICT_TF2_VERSIONED)) { + if (error == DB_SUCCESS && m_prebuilt->upd_node->versioned) { if (trx->id != static_cast(table->vers_start_field()->val_int())) error = row_insert_for_mysql((byte*) old_row, m_prebuilt, true); } diff --git a/storage/innobase/include/row0upd.h b/storage/innobase/include/row0upd.h index 359d243a0cd..d035e346c1e 100644 --- a/storage/innobase/include/row0upd.h +++ b/storage/innobase/include/row0upd.h @@ -582,6 +582,7 @@ struct upd_node_t{ compilation; speeds up execution: UPD_NODE_NO_ORD_CHANGE and UPD_NODE_NO_SIZE_CHANGE, ORed */ + bool versioned;/* update is versioned */ /*----------------------*/ /* Local storage for this graph node */ ulint state; /*!< node execution state */ diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 12a41d97a41..604656c8944 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -2854,7 +2854,7 @@ row_ins_sec_index_entry_low( cursor.thr = thr; cursor.rtr_info = NULL; - ut_ad(thr_get_trx(thr)->id != 0); + ut_ad(trx && trx->id != 0 || thr_get_trx(thr)->id != 0); mtr_start(&mtr); mtr.set_named_space(index->space); @@ -3890,7 +3890,7 @@ void vers_notify_vtq(trx_t* trx) timeval begin_ts, commit_ts; begin_ts.tv_sec = trx->start_time; begin_ts.tv_usec = trx->start_time_micro; - ut_usectime((ulint *)&commit_ts.tv_sec, (ulint *)&commit_ts.tv_usec); + ut_usectime((ulong*)&commit_ts.tv_sec, (ulong*)&commit_ts.tv_usec); dict_table_copy_types(row, dict_sys->sys_vtq); set_row_field_8(row, DICT_FLD__SYS_VTQ__TRX_ID, trx->id, heap); diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index c1a4871a9ff..7a4f2719ba5 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -1957,7 +1957,8 @@ row_update_for_mysql_using_upd_graph( prebuilt->clust_pcur); } - if (DICT_TF2_FLAG_IS_SET(node->table, DICT_TF2_VERSIONED)) + if (DICT_TF2_FLAG_IS_SET(node->table, DICT_TF2_VERSIONED) && + (node->is_delete || node->versioned)) { /* System Versioning: modify update vector to set sys_trx_start (or sys_trx_end in case of DELETE) diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index 92af465aa49..cc86a8c419b 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -442,6 +442,8 @@ upd_node_create( node->common.type = QUE_NODE_UPDATE; node->state = UPD_NODE_UPDATE_CLUSTERED; node->heap = mem_heap_create(128); + node->cmpl_info = 0; + node->versioned = false; node->magic_n = UPD_NODE_MAGIC_N; return(node); -- cgit v1.2.1 From 70168978fc75cea702f10edae34074a7c66c5690 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 25 Oct 2016 10:42:26 +0000 Subject: Scripts: Travis-CI for natsys/trunk --- .travis.yml | 18 ++++++++---------- README.md | 2 +- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index c2fa7283e9a..267f479eb8f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,10 @@ # vim ft=yaml # travis-ci.org definition +branches: + only: + - natsys/trunk + # non-container builds don't have enough RAM to reliably compile sudo: required dist: trusty @@ -68,13 +72,7 @@ script: - export MYSQL_BUILD_CC=/usr/bin/gcc-${GCC_VERSION} MYSQL_BUILD_CXX=/usr/bin/g++-${GCC_VERSION} - ${MYSQL_BUILD_CC} --version ; ${MYSQL_BUILD_CXX} --version - cd "${TRAVIS_BUILD_DIR}" - - env DEB_BUILD_OPTIONS="parallel=3" debian/autobake-deb.sh; - -notifications: - irc: - channels: - - "chat.freenode.net#maria" - on_success: never # [always|never|change] - on_failure: never - template: - - "%{repository}/%{branch} (%{commit} - %{author}): %{build_url}: %{message}" + - cmake -DCMAKE_BUILD_TYPE=Debug -DWITH_INNOBASE_STORAGE_ENGINE=yes -DWITH_JEMALLOC=yes -DSECURITY_HARDENED=no -DWITH_PIC=no -DCMAKE_CXX_FLAGS_DEBUG="-g -O0" -DCMAKE_C_FLAGS_DEBUG="-g -O0" + - make -j $(grep -c processor /proc/cpuinfo) + - cd ./mysql-test + - ./mtr --suite=versioning --force --max-test-fail=0 diff --git a/README.md b/README.md index f34e6a43b71..2488f4a6d84 100644 --- a/README.md +++ b/README.md @@ -67,4 +67,4 @@ https://github.com/MariaDB/server Code status: ------------ -* [![tests status](https://secure.travis-ci.org/MariaDB/server.png?branch=10.2)](https://travis-ci.org/MariaDB/server) travis-ci.org (10.2 branch) +* [![tests status](https://travis-ci.org/natsys/mariadb_10.2.svg?branch=natsys%2Ftrunk)](https://travis-ci.org/natsys/mariadb_10.2) travis-ci.org (natsys/trunk) -- cgit v1.2.1 From e0942286313f78e497a36394111b4546d5a20ed0 Mon Sep 17 00:00:00 2001 From: Kosov Eugene Date: Thu, 20 Oct 2016 23:05:55 +0300 Subject: SQL: hide implicitly added columns from SELECT * --- include/mysql_com.h | 1 + mysql-test/suite/versioning/r/select.result | 16 + mysql-test/suite/versioning/t/select.test | 16 + sql/field.h | 3 + sql/field.h.orig | 4160 +++++++++++++++++++++++++++ sql/handler.cc | 4 +- sql/sql_base.cc | 8 + sql/sql_table.cc | 2 + sql/table.cc | 3 + 9 files changed, 4211 insertions(+), 2 deletions(-) create mode 100644 sql/field.h.orig diff --git a/include/mysql_com.h b/include/mysql_com.h index 904a64b08f8..d52bd8eaada 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -193,6 +193,7 @@ enum enum_indicator_type #define WITHOUT_SYSTEM_VERSIONING_FLAG (1 << 29) /* column that doesn't support system versioning when table itself supports it*/ +#define HIDDEN_FLAG (1 << 31) /* hide from SELECT * */ #define REFRESH_GRANT (1ULL << 0) /* Refresh grant tables */ #define REFRESH_LOG (1ULL << 1) /* Start on new log file */ diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index a691019c80c..94dcb243e65 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -241,6 +241,21 @@ RJ2_x1 y1 x2 y2 1 3 1 2 NULL NULL 2 1 NULL NULL 3 1 +create table t1( +A int +) with system versioning engine=myisam; +insert into t1 values(1); +select * from t1; +A +1 +create or replace table t1( +A int +) with system versioning engine=innodb; +insert into t1 values(1); +select * from t1; +A +1 +drop table t1; call verify_vtq; No A B C D 1 1 1 1 1 @@ -251,6 +266,7 @@ No A B C D 6 1 1 1 1 7 1 1 1 1 8 1 1 1 1 +9 1 1 1 1 drop procedure test_01; drop procedure test_02; drop procedure verify_vtq; diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index 621374051bb..0aa4f561882 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -89,6 +89,22 @@ call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_start)'); call test_02('timestamp(6)', 'myisam', 'sys_start'); call test_02('bigint unsigned', 'innodb', 'commit_ts(sys_start)'); +# Test wildcard expansion on hidden fields. +create table t1( + A int +) with system versioning engine=myisam; +insert into t1 values(1); +select * from t1; + +create or replace table t1( + A int +) with system versioning engine=innodb; +insert into t1 values(1); +select * from t1; + +drop table t1; +# End test wildcard expansion. + call verify_vtq; drop procedure test_01; diff --git a/sql/field.h b/sql/field.h index a52fb656b39..e50595df11a 100644 --- a/sql/field.h +++ b/sql/field.h @@ -4281,6 +4281,8 @@ bool check_expression(Virtual_column_info *vcol, const char *name, #define FIELDFLAG_BITFIELD 512U // mangled with decimals! #define FIELDFLAG_BLOB 1024U // mangled with decimals! #define FIELDFLAG_GEOM 2048U // mangled with decimals! +// Do not show field in SELECT *. Hope GEOM field is never hidden. +#define FIELDFLAG_HIDDEN 2048U #define FIELDFLAG_TREAT_BIT_AS_CHAR 4096U /* use Field_bit_as_char */ #define FIELDFLAG_LONG_DECIMAL 8192U @@ -4312,5 +4314,6 @@ bool check_expression(Virtual_column_info *vcol, const char *name, #define f_bit_as_char(x) ((x) & FIELDFLAG_TREAT_BIT_AS_CHAR) #define f_is_hex_escape(x) ((x) & FIELDFLAG_HEX_ESCAPE) #define f_without_system_versioning(x) ((x) & FIELDFLAG_WITHOUT_SYSTEM_VERSIONING) +#define f_hidden(x) ((x) & FIELDFLAG_HIDDEN) #endif /* FIELD_INCLUDED */ diff --git a/sql/field.h.orig b/sql/field.h.orig new file mode 100644 index 00000000000..03d9ba06ac4 --- /dev/null +++ b/sql/field.h.orig @@ -0,0 +1,4160 @@ +#ifndef FIELD_INCLUDED +#define FIELD_INCLUDED +/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. + Copyright (c) 2008, 2017, MariaDB Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/* + Because of the function make_new_field() all field classes that have static + variables must declare the size_of() member function. +*/ + +#ifdef USE_PRAGMA_INTERFACE +#pragma interface /* gcc class implementation */ +#endif + +#include "mysqld.h" /* system_charset_info */ +#include "table.h" /* TABLE */ +#include "sql_string.h" /* String */ +#include "my_decimal.h" /* my_decimal */ +#include "sql_error.h" /* Sql_condition */ +#include "compat56.h" +#include "sql_type.h" /* Type_std_attributes */ + +class Send_field; +class Copy_field; +class Protocol; +class Create_field; +class Relay_log_info; +class Field; +class Column_statistics; +class Column_statistics_collected; +class Item_func; +class Item_bool_func; +class Item_equal; + +enum enum_check_fields +{ + CHECK_FIELD_IGNORE, + CHECK_FIELD_WARN, + CHECK_FIELD_ERROR_FOR_NULL +}; + +/* + Common declarations for Field and Item +*/ +class Value_source +{ +protected: + + // Parameters for warning and note generation + class Warn_filter + { + bool m_want_warning_edom; + bool m_want_note_truncated_spaces; + public: + Warn_filter(bool want_warning_edom, bool want_note_truncated_spaces) : + m_want_warning_edom(want_warning_edom), + m_want_note_truncated_spaces(want_note_truncated_spaces) + { } + Warn_filter(const THD *thd); + bool want_warning_edom() const + { return m_want_warning_edom; } + bool want_note_truncated_spaces() const + { return m_want_note_truncated_spaces; } + }; + class Warn_filter_all: public Warn_filter + { + public: + Warn_filter_all() :Warn_filter(true, true) { } + }; + + class Converter_double_to_longlong + { + protected: + bool m_error; + longlong m_result; + public: + Converter_double_to_longlong(double nr, bool unsigned_flag); + longlong result() const { return m_result; } + bool error() const { return m_error; } + void push_warning(THD *thd, double nr, bool unsigned_flag); + }; + class Converter_double_to_longlong_with_warn: + public Converter_double_to_longlong + { + public: + Converter_double_to_longlong_with_warn(THD *thd, double nr, + bool unsigned_flag) + :Converter_double_to_longlong(nr, unsigned_flag) + { + if (m_error) + push_warning(thd, nr, unsigned_flag); + } + Converter_double_to_longlong_with_warn(double nr, bool unsigned_flag) + :Converter_double_to_longlong(nr, unsigned_flag) + { + if (m_error) + push_warning(current_thd, nr, unsigned_flag); + } + }; + + // String-to-number converters + class Converter_string_to_number + { + protected: + char *m_end_of_num; // Where the low-level conversion routine stopped + int m_error; // The error code returned by the low-level routine + bool m_edom; // If EDOM-alike error happened during conversion + /** + Check string-to-number conversion and produce a warning if + - could not convert any digits (EDOM-alike error) + - found garbage at the end of the string + - found extra spaces at the end (a note) + See also Field_num::check_edom_and_truncation() for a similar function. + + @param thd - the thread that will be used to generate warnings. + Can be NULL (which means current_thd will be used + if a warning is really necessary). + @param type - name of the data type + (e.g. "INTEGER", "DECIMAL", "DOUBLE") + @param cs - character set of the original string + @param str - the original string + @param end - the end of the string + @param allow_notes - tells if trailing space notes should be displayed + or suppressed. + + Unlike Field_num::check_edom_and_truncation(), this function does not + distinguish between EDOM and truncation and reports the same warning for + both cases. Perhaps we should eventually print different warnings, + to make the explicit CAST work closer to the implicit cast in + Field_xxx::store(). + */ + void check_edom_and_truncation(THD *thd, Warn_filter filter, + const char *type, + CHARSET_INFO *cs, + const char *str, + size_t length) const; + public: + int error() const { return m_error; } + }; + + class Converter_strntod: public Converter_string_to_number + { + double m_result; + public: + Converter_strntod(CHARSET_INFO *cs, const char *str, size_t length) + { + m_result= my_strntod(cs, (char *) str, length, &m_end_of_num, &m_error); + // strntod() does not set an error if the input string was empty + m_edom= m_error !=0 || str == m_end_of_num; + } + double result() const { return m_result; } + }; + + class Converter_string_to_longlong: public Converter_string_to_number + { + protected: + longlong m_result; + public: + longlong result() const { return m_result; } + }; + + class Converter_strntoll: public Converter_string_to_longlong + { + public: + Converter_strntoll(CHARSET_INFO *cs, const char *str, size_t length) + { + m_result= my_strntoll(cs, str, length, 10, &m_end_of_num, &m_error); + /* + All non-zero errors means EDOM error. + strntoll() does not set an error if the input string was empty. + Check it here. + Notice the different with the same condition in Converter_strntoll10. + */ + m_edom= m_error != 0 || str == m_end_of_num; + } + }; + + class Converter_strtoll10: public Converter_string_to_longlong + { + public: + Converter_strtoll10(CHARSET_INFO *cs, const char *str, size_t length) + { + m_end_of_num= (char *) str + length; + m_result= (*(cs->cset->strtoll10))(cs, str, &m_end_of_num, &m_error); + /* + Negative error means "good negative number". + Only a positive m_error value means a real error. + strtoll10() sets error to MY_ERRNO_EDOM in case of an empty string, + so we don't have to additionally catch empty strings here. + */ + m_edom= m_error > 0; + } + }; + + class Converter_str2my_decimal: public Converter_string_to_number + { + public: + Converter_str2my_decimal(uint mask, + CHARSET_INFO *cs, const char *str, size_t length, + my_decimal *buf) + { + m_error= str2my_decimal(mask, str, length, cs, + buf, (const char **) &m_end_of_num); + // E_DEC_TRUNCATED means a very minor truncation: '1e-100' -> 0 + m_edom= m_error && m_error != E_DEC_TRUNCATED; + } + }; + + + // String-to-number converters with automatic warning generation + class Converter_strntod_with_warn: public Converter_strntod + { + public: + Converter_strntod_with_warn(THD *thd, Warn_filter filter, + CHARSET_INFO *cs, + const char *str, size_t length) + :Converter_strntod(cs, str, length) + { + check_edom_and_truncation(thd, filter, "DOUBLE", cs, str, length); + } + }; + + class Converter_strntoll_with_warn: public Converter_strntoll + { + public: + Converter_strntoll_with_warn(THD *thd, Warn_filter filter, + CHARSET_INFO *cs, + const char *str, size_t length) + :Converter_strntoll(cs, str, length) + { + check_edom_and_truncation(thd, filter, "INTEGER", cs, str, length); + } + }; + + class Converter_strtoll10_with_warn: public Converter_strtoll10 + { + public: + Converter_strtoll10_with_warn(THD *thd, Warn_filter filter, + CHARSET_INFO *cs, + const char *str, size_t length) + :Converter_strtoll10(cs, str, length) + { + check_edom_and_truncation(thd, filter, "INTEGER", cs, str, length); + } + }; + + class Converter_str2my_decimal_with_warn: public Converter_str2my_decimal + { + public: + Converter_str2my_decimal_with_warn(THD *thd, Warn_filter filter, + uint mask, CHARSET_INFO *cs, + const char *str, size_t length, + my_decimal *buf) + :Converter_str2my_decimal(mask, cs, str, length, buf) + { + check_edom_and_truncation(thd, filter, "DECIMAL", cs, str, length); + } + }; + + + // String-to-number convertion methods for the old code compatibility + longlong longlong_from_string_with_check(CHARSET_INFO *cs, const char *cptr, + const char *end) const + { + /* + TODO: Give error if we wanted a signed integer and we got an unsigned + one + + Notice, longlong_from_string_with_check() honors thd->no_error, because + it's used to handle queries like this: + SELECT COUNT(@@basedir); + and is called when Item_func_get_system_var::update_null_value() + suppresses warnings and then calls val_int(). + The other methods {double|decimal}_from_string_with_check() ignore + thd->no_errors, because they are not used for update_null_value() + and they always allow all kind of warnings. + */ + THD *thd= current_thd; + return Converter_strtoll10_with_warn(thd, Warn_filter(thd), + cs, cptr, end - cptr).result(); + } + + double double_from_string_with_check(CHARSET_INFO *cs, const char *cptr, + const char *end) const + { + return Converter_strntod_with_warn(NULL, Warn_filter_all(), + cs, cptr, end - cptr).result(); + } + my_decimal *decimal_from_string_with_check(my_decimal *decimal_value, + CHARSET_INFO *cs, + const char *cptr, + const char *end) + { + Converter_str2my_decimal_with_warn(NULL, Warn_filter_all(), + E_DEC_FATAL_ERROR & ~E_DEC_BAD_NUM, + cs, cptr, end - cptr, decimal_value); + return decimal_value; + } + + longlong longlong_from_hex_hybrid(const char *str, uint32 length) + { + const char *end= str + length; + const char *ptr= end - MY_MIN(length, sizeof(longlong)); + ulonglong value= 0; + for ( ; ptr != end ; ptr++) + value= (value << 8) + (ulonglong) (uchar) *ptr; + return (longlong) value; + } + + longlong longlong_from_string_with_check(const String *str) const + { + return longlong_from_string_with_check(str->charset(), + str->ptr(), str->end()); + } + double double_from_string_with_check(const String *str) const + { + return double_from_string_with_check(str->charset(), + str->ptr(), str->end()); + } + my_decimal *decimal_from_string_with_check(my_decimal *decimal_value, + const String *str) + { + return decimal_from_string_with_check(decimal_value, str->charset(), + str->ptr(), str->end()); + } + // End of String-to-number conversion methods + +public: + /* + The enumeration Subst_constraint is currently used only in implementations + of the virtual function subst_argument_checker. + */ + enum Subst_constraint + { + ANY_SUBST, /* Any substitution for a field is allowed */ + IDENTITY_SUBST /* Substitution for a field is allowed if any two + different values of the field type are not equal */ + }; + /* + Item context attributes. + Comparison functions pass their attributes to propagate_equal_fields(). + For exmple, for string comparison, the collation of the comparison + operation is important inside propagate_equal_fields(). + */ + class Context + { + /* + Which type of propagation is allowed: + - ANY_SUBST (loose equality, according to the collation), or + - IDENTITY_SUBST (strict binary equality). + */ + Subst_constraint m_subst_constraint; + /* + Comparison type. + Impostant only when ANY_SUBSTS. + */ + Item_result m_compare_type; + /* + Collation of the comparison operation. + Important only when ANY_SUBST. + */ + CHARSET_INFO *m_compare_collation; + public: + Context(Subst_constraint subst, Item_result type, CHARSET_INFO *cs) + :m_subst_constraint(subst), + m_compare_type(type), + m_compare_collation(cs) { } + Subst_constraint subst_constraint() const { return m_subst_constraint; } + Item_result compare_type() const + { + DBUG_ASSERT(m_subst_constraint == ANY_SUBST); + return m_compare_type; + } + CHARSET_INFO *compare_collation() const + { + DBUG_ASSERT(m_subst_constraint == ANY_SUBST); + return m_compare_collation; + } + }; + class Context_identity: public Context + { // Use this to request only exact value, no invariants. + public: + Context_identity() + :Context(IDENTITY_SUBST, STRING_RESULT, &my_charset_bin) { } + }; + class Context_boolean: public Context + { // Use this when an item is [a part of] a boolean expression + public: + Context_boolean() :Context(ANY_SUBST, INT_RESULT, &my_charset_bin) { } + }; +}; + + +#define STORAGE_TYPE_MASK 7 +#define COLUMN_FORMAT_MASK 7 +#define COLUMN_FORMAT_SHIFT 3 + +/* The length of the header part for each virtual column in the .frm file */ +#define FRM_VCOL_OLD_HEADER_SIZE(b) (3 + MY_TEST(b)) +#define FRM_VCOL_NEW_BASE_SIZE 16 +#define FRM_VCOL_NEW_HEADER_SIZE 6 + +class Count_distinct_field; + +struct ha_field_option_struct; + +struct st_cache_field; +int field_conv(Field *to,Field *from); +int truncate_double(double *nr, uint field_length, uint dec, + bool unsigned_flag, double max_value); + +inline uint get_enum_pack_length(int elements) +{ + return elements < 256 ? 1 : 2; +} + +inline uint get_set_pack_length(int elements) +{ + uint len= (elements + 7) / 8; + return len > 4 ? 8 : len; +} + + +/** + Tests if field type is temporal and has date part, + i.e. represents DATE, DATETIME or TIMESTAMP types in SQL. + + @param type Field type, as returned by field->type(). + @retval true If field type is temporal type with date part. + @retval false If field type is not temporal type with date part. +*/ +inline bool is_temporal_type_with_date(enum_field_types type) +{ + switch (type) + { + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_TIMESTAMP: + return true; + case MYSQL_TYPE_DATETIME2: + case MYSQL_TYPE_TIMESTAMP2: + DBUG_ASSERT(0); // field->real_type() should not get to here. + default: + return false; + } +} + + +/** + Recognizer for concrete data type (called real_type for some reason), + returning true if it is one of the TIMESTAMP types. +*/ +inline bool is_timestamp_type(enum_field_types type) +{ + return type == MYSQL_TYPE_TIMESTAMP || type == MYSQL_TYPE_TIMESTAMP2; +} + + +/** + Convert temporal real types as retuned by field->real_type() + to field type as returned by field->type(). + + @param real_type Real type. + @retval Field type. +*/ +inline enum_field_types real_type_to_type(enum_field_types real_type) +{ + switch (real_type) + { + case MYSQL_TYPE_TIME2: + return MYSQL_TYPE_TIME; + case MYSQL_TYPE_DATETIME2: + return MYSQL_TYPE_DATETIME; + case MYSQL_TYPE_TIMESTAMP2: + return MYSQL_TYPE_TIMESTAMP; + case MYSQL_TYPE_NEWDATE: + return MYSQL_TYPE_DATE; + /* Note: NEWDECIMAL is a type, not only a real_type */ + default: return real_type; + } +} + + +static inline enum enum_mysql_timestamp_type +mysql_type_to_time_type(enum enum_field_types mysql_type) +{ + switch(mysql_type) { + case MYSQL_TYPE_TIME2: + case MYSQL_TYPE_TIME: return MYSQL_TIMESTAMP_TIME; + case MYSQL_TYPE_TIMESTAMP2: + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_DATETIME2: + case MYSQL_TYPE_DATETIME: return MYSQL_TIMESTAMP_DATETIME; + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_DATE: return MYSQL_TIMESTAMP_DATE; + default: return MYSQL_TIMESTAMP_ERROR; + } +} + + +/** + Tests if field type is temporal, i.e. represents + DATE, TIME, DATETIME or TIMESTAMP types in SQL. + + @param type Field type, as returned by field->type(). + @retval true If field type is temporal + @retval false If field type is not temporal +*/ +inline bool is_temporal_type(enum_field_types type) +{ + return mysql_type_to_time_type(type) != MYSQL_TIMESTAMP_ERROR; +} + + +/** + Tests if field type is temporal and has time part, + i.e. represents TIME, DATETIME or TIMESTAMP types in SQL. + + @param type Field type, as returned by field->type(). + @retval true If field type is temporal type with time part. + @retval false If field type is not temporal type with time part. +*/ +inline bool is_temporal_type_with_time(enum_field_types type) +{ + switch (type) + { + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_TIMESTAMP: + return true; + default: + return false; + } +} + +enum enum_vcol_info_type +{ + VCOL_GENERATED_VIRTUAL, VCOL_GENERATED_STORED, + VCOL_DEFAULT, VCOL_CHECK_FIELD, VCOL_CHECK_TABLE +}; + +static inline const char *vcol_type_name(enum_vcol_info_type type) +{ + switch (type) + { + case VCOL_GENERATED_VIRTUAL: + case VCOL_GENERATED_STORED: + return "GENERATED ALWAYS AS"; + case VCOL_DEFAULT: + return "DEFAULT"; + case VCOL_CHECK_FIELD: + case VCOL_CHECK_TABLE: + return "CHECK"; + } + return 0; +} + +/* + Flags for Virtual_column_info. If none is set, the expression must be + a constant with no side-effects, so it's calculated at CREATE TABLE time, + stored in table->record[2], and not recalculated for every statement. +*/ +#define VCOL_FIELD_REF 1 +#define VCOL_NON_DETERMINISTIC 2 +#define VCOL_SESSION_FUNC 4 /* uses session data, e.g. USER or DAYNAME */ +#define VCOL_TIME_FUNC 8 +#define VCOL_IMPOSSIBLE 16 + +#define VCOL_NOT_STRICTLY_DETERMINISTIC \ + (VCOL_NON_DETERMINISTIC | VCOL_TIME_FUNC | VCOL_SESSION_FUNC) + +/* + Virtual_column_info is the class to contain additional + characteristics that is specific for a virtual/computed + field such as: + - the defining expression that is evaluated to compute the value + of the field + - whether the field is to be stored in the database + - whether the field is used in a partitioning expression +*/ + +class Virtual_column_info: public Sql_alloc +{ +private: + /* + The following data is only updated by the parser and read + when a Create_field object is created/initialized. + */ + enum_field_types field_type; /* Real field type*/ + /* Flag indicating that the field used in a partitioning expression */ + bool in_partitioning_expr; + +public: + /* Flag indicating that the field is physically stored in the database */ + bool stored_in_db; + bool utf8; /* Already in utf8 */ + Item *expr; + LEX_STRING name; /* Name of constraint */ + uint flags; + + Virtual_column_info() + : field_type((enum enum_field_types)MYSQL_TYPE_VIRTUAL), + in_partitioning_expr(FALSE), stored_in_db(FALSE), + utf8(TRUE), expr(NULL), flags(0) + { + name.str= NULL; + name.length= 0; + }; + ~Virtual_column_info() {} + enum_field_types get_real_type() const + { + return field_type; + } + void set_field_type(enum_field_types fld_type) + { + /* Calling this function can only be done once. */ + field_type= fld_type; + } + bool is_stored() const + { + return stored_in_db; + } + void set_stored_in_db_flag(bool stored) + { + stored_in_db= stored; + } + bool is_in_partitioning_expr() const + { + return in_partitioning_expr; + } + void mark_as_in_partitioning_expr() + { + in_partitioning_expr= TRUE; + } + inline bool is_equal(const Virtual_column_info* vcol) const; + void print(String*); +}; + +class Field: public Value_source +{ + Field(const Item &); /* Prevent use of these */ + void operator=(Field &); +protected: + int save_in_field_str(Field *to) + { + StringBuffer result(charset()); + val_str(&result); + return to->store(result.ptr(), result.length(), charset()); + } + static void do_field_int(Copy_field *copy); + static void do_field_real(Copy_field *copy); + static void do_field_string(Copy_field *copy); + static void do_field_temporal(Copy_field *copy); + static void do_field_decimal(Copy_field *copy); +public: + static void *operator new(size_t size, MEM_ROOT *mem_root) throw () + { return alloc_root(mem_root, size); } + static void *operator new(size_t size) throw () + { return thd_alloc(current_thd, size); } + static void operator delete(void *ptr_arg, size_t size) { TRASH(ptr_arg, size); } + static void operator delete(void *ptr, MEM_ROOT *mem_root) + { DBUG_ASSERT(0); } + + /** + Used by System Versioning. + */ + virtual bool set_max() + { DBUG_ASSERT(0); return false; } + + /** + Used by System Versioning. + */ + virtual bool is_max() + { DBUG_ASSERT(0); return false; } + + uchar *ptr; // Position to field in record + /** + Byte where the @c NULL bit is stored inside a record. If this Field is a + @c NOT @c NULL field, this member is @c NULL. + */ + uchar *null_ptr; + /* + Note that you can use table->in_use as replacement for current_thd member + only inside of val_*() and store() members (e.g. you can't use it in cons) + */ + TABLE *table; // Pointer for table + TABLE *orig_table; // Pointer to original table + const char * const *table_name; + const char *field_name; + /** reference to the list of options or NULL */ + engine_option_value *option_list; + ha_field_option_struct *option_struct; /* structure with parsed options */ + LEX_STRING comment; + /* Field is part of the following keys */ + key_map key_start, part_of_key, part_of_key_not_clustered; + + /* + Bitmap of indexes that have records ordered by col1, ... this_field, ... + + For example, INDEX (col(prefix_n)) is not present in col.part_of_sortkey. + */ + key_map part_of_sortkey; + /* + We use three additional unireg types for TIMESTAMP to overcome limitation + of current binary format of .frm file. We'd like to be able to support + NOW() as default and on update value for such fields but unable to hold + this info anywhere except unireg_check field. This issue will be resolved + in more clean way with transition to new text based .frm format. + See also comment for Field_timestamp::Field_timestamp(). + */ + enum utype { + NONE=0, + NEXT_NUMBER=15, // AUTO_INCREMENT + TIMESTAMP_OLD_FIELD=18, // TIMESTAMP created before 4.1.3 + TIMESTAMP_DN_FIELD=21, // TIMESTAMP DEFAULT NOW() + TIMESTAMP_UN_FIELD=22, // TIMESTAMP ON UPDATE NOW() + TIMESTAMP_DNUN_FIELD=23 // TIMESTAMP DEFAULT NOW() ON UPDATE NOW() + }; + enum geometry_type + { + GEOM_GEOMETRY = 0, GEOM_POINT = 1, GEOM_LINESTRING = 2, GEOM_POLYGON = 3, + GEOM_MULTIPOINT = 4, GEOM_MULTILINESTRING = 5, GEOM_MULTIPOLYGON = 6, + GEOM_GEOMETRYCOLLECTION = 7 + }; + enum imagetype { itRAW, itMBR}; + + utype unireg_check; + uint32 field_length; // Length of field + uint32 flags; + uint16 field_index; // field number in fields array + uchar null_bit; // Bit used to test null bit + /** + If true, this field was created in create_tmp_field_from_item from a NULL + value. This means that the type of the field is just a guess, and the type + may be freely coerced to another type. + + @see create_tmp_field_from_item + @see Item_type_holder::get_real_type + + */ + bool is_created_from_null_item; + + /* TRUE in Field objects created for column min/max values */ + bool is_stat_field; + + /* + Selectivity of the range condition over this field. + When calculating this selectivity a range predicate + is taken into account only if: + - it is extracted from the WHERE clause + - it depends only on the table the field belongs to + */ + double cond_selectivity; + + /* + The next field in the class of equal fields at the top AND level + of the WHERE clause + */ + Field *next_equal_field; + + /* + This structure is used for statistical data on the column + that has been read from the statistical table column_stat + */ + Column_statistics *read_stats; + /* + This structure is used for statistical data on the column that + is collected by the function collect_statistics_for_table + */ + Column_statistics_collected *collected_stats; + + /* + This is additional data provided for any computed(virtual) field, + default function or check constraint. + In particular it includes a pointer to the item by which this field + can be computed from other fields. + */ + Virtual_column_info *vcol_info, *check_constraint, *default_value; + + Field(uchar *ptr_arg,uint32 length_arg,uchar *null_ptr_arg, + uchar null_bit_arg, utype unireg_check_arg, + const char *field_name_arg); + virtual ~Field() {} + + DTCollation dtcollation() const + { + return DTCollation(charset(), derivation(), repertoire()); + } + Type_std_attributes type_std_attributes() const + { + return Type_std_attributes(field_length, decimals(), + MY_TEST(flags & UNSIGNED_FLAG), + dtcollation()); + } + + /** + Convenience definition of a copy function returned by + Field::get_copy_func() + */ + typedef void Copy_func(Copy_field*); + virtual Copy_func *get_copy_func(const Field *from) const= 0; + /* Store functions returns 1 on overflow and -1 on fatal error */ + virtual int store_field(Field *from) { return from->save_in_field(this); } + virtual int save_in_field(Field *to)= 0; + /** + Check if it is possible just copy the value + of the field 'from' to the field 'this', e.g. for + INSERT INTO t1 (field1) SELECT field2 FROM t2; + @param from - The field to copy from + @retval true - it is possible to just copy value of 'from' to 'this' + @retval false - conversion is needed + */ + virtual bool memcpy_field_possible(const Field *from) const= 0; + virtual int store(const char *to, uint length,CHARSET_INFO *cs)=0; + virtual int store_hex_hybrid(const char *str, uint length); + virtual int store(double nr)=0; + virtual int store(longlong nr, bool unsigned_val)=0; + virtual int store_decimal(const my_decimal *d)=0; + virtual int store_time_dec(MYSQL_TIME *ltime, uint dec); + int store_time(MYSQL_TIME *ltime) + { return store_time_dec(ltime, TIME_SECOND_PART_DIGITS); } + int store(const char *to, uint length, CHARSET_INFO *cs, + enum_check_fields check_level); + int store(const LEX_STRING *ls, CHARSET_INFO *cs) + { return store(ls->str, ls->length, cs); } + virtual double val_real(void)=0; + virtual longlong val_int(void)=0; + virtual bool val_bool(void)= 0; + virtual my_decimal *val_decimal(my_decimal *); + inline String *val_str(String *str) { return val_str(str, str); } + /* + val_str(buf1, buf2) gets two buffers and should use them as follows: + if it needs a temp buffer to convert result to string - use buf1 + example Field_tiny::val_str() + if the value exists as a string already - use buf2 + example Field_string::val_str() + consequently, buf2 may be created as 'String buf;' - no memory + will be allocated for it. buf1 will be allocated to hold a + value if it's too small. Using allocated buffer for buf2 may result in + an unnecessary free (and later, may be an alloc). + This trickery is used to decrease a number of malloc calls. + */ + virtual String *val_str(String*,String *)=0; + String *val_int_as_str(String *val_buffer, bool unsigned_flag); + fast_field_copier get_fast_field_copier(const Field *from); + /* + str_needs_quotes() returns TRUE if the value returned by val_str() needs + to be quoted when used in constructing an SQL query. + */ + virtual bool str_needs_quotes() { return FALSE; } + virtual Item_result result_type () const=0; + virtual Item_result cmp_type () const { return result_type(); } + virtual const Type_handler *cast_to_int_type_handler() const + { + return Type_handler::get_handler_by_field_type(type()); + } + static bool type_can_have_key_part(enum_field_types); + static enum_field_types field_type_merge(enum_field_types, enum_field_types); + virtual bool eq(Field *field) + { + return (ptr == field->ptr && null_ptr == field->null_ptr && + null_bit == field->null_bit && field->type() == type()); + } + virtual bool eq_def(const Field *field) const; + + /* + pack_length() returns size (in bytes) used to store field data in memory + (i.e. it returns the maximum size of the field in a row of the table, + which is located in RAM). + */ + virtual uint32 pack_length() const { return (uint32) field_length; } + + /* + pack_length_in_rec() returns size (in bytes) used to store field data on + storage (i.e. it returns the maximal size of the field in a row of the + table, which is located on disk). + */ + virtual uint32 pack_length_in_rec() const { return pack_length(); } + virtual bool compatible_field_size(uint metadata, Relay_log_info *rli, + uint16 mflags, int *order); + virtual uint pack_length_from_metadata(uint field_metadata) + { + DBUG_ENTER("Field::pack_length_from_metadata"); + DBUG_RETURN(field_metadata); + } + virtual uint row_pack_length() const { return 0; } + virtual int save_field_metadata(uchar *first_byte) + { return do_save_field_metadata(first_byte); } + + /* + data_length() return the "real size" of the data in memory. + */ + virtual uint32 data_length() { return pack_length(); } + virtual uint32 sort_length() const { return pack_length(); } + + /* + Get the number bytes occupied by the value in the field. + CHAR values are stripped of trailing spaces. + Flexible values are stripped of their length. + */ + virtual uint32 value_length() + { + uint len; + if (!zero_pack() && + (type() == MYSQL_TYPE_STRING && + (len= pack_length()) >= 4 && len < 256)) + { + uchar *str, *end; + for (str= ptr, end= str+len; end > str && end[-1] == ' '; end--) {} + len=(uint) (end-str); + return len; + } + return data_length(); + } + + /** + Get the maximum size of the data in packed format. + + @return Maximum data length of the field when packed using the + Field::pack() function. + */ + virtual uint32 max_data_length() const { + return pack_length(); + }; + + virtual int reset(void) { bzero(ptr,pack_length()); return 0; } + virtual void reset_fields() {} + const uchar *ptr_in_record(const uchar *record) const + { + my_ptrdiff_t l_offset= (my_ptrdiff_t) (record - table->record[0]); + return ptr + l_offset; + } + virtual void set_default(); + + bool has_update_default_function() const + { + return flags & ON_UPDATE_NOW_FLAG; + } + bool has_default_now_unireg_check() const + { + return unireg_check == TIMESTAMP_DN_FIELD + || unireg_check == TIMESTAMP_DNUN_FIELD; + } + + /* + Mark the field as having a value supplied by the client, thus it should + not be auto-updated. + */ + void set_has_explicit_value() + { + bitmap_set_bit(&table->has_value_set, field_index); + } + bool has_explicit_value() + { + return bitmap_is_set(&table->has_value_set, field_index); + } + virtual bool set_explicit_default(Item *value); + + /** + Evaluates the @c UPDATE default function, if one exists, and stores the + result in the record buffer. If no such function exists for the column, + or the function is not valid for the column's data type, invoking this + function has no effect. + */ + virtual int evaluate_update_default_function() { return 0; } + + virtual bool binary() const { return 1; } + virtual bool zero_pack() const { return 1; } + virtual enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } + virtual uint32 key_length() const { return pack_length(); } + virtual enum_field_types type() const =0; + virtual enum_field_types real_type() const { return type(); } + virtual enum_field_types binlog_type() const + { + /* + Binlog stores field->type() as type code by default. For example, + it puts MYSQL_TYPE_STRING in case of CHAR, VARCHAR, SET and ENUM, + with extra data type details put into metadata. + + Binlog behaviour slightly differs between various MySQL and MariaDB + versions for the temporal data types TIME, DATETIME and TIMESTAMP. + + MySQL prior to 5.6 uses MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME + and MYSQL_TYPE_TIMESTAMP type codes in binlog and stores no + additional metadata. + + MariaDB-5.3 implements new versions for TIME, DATATIME, TIMESTAMP + with fractional second precision, but uses the old format for the + types TIME(0), DATETIME(0), TIMESTAMP(0), and it still stores + MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME and MYSQL_TYPE_TIMESTAMP in binlog, + with no additional metadata. + So row-based replication between temporal data types of + different precision is not possible in MariaDB. + + MySQL-5.6 also implements a new version of TIME, DATETIME, TIMESTAMP + which support fractional second precision 0..6, and use the new + format even for the types TIME(0), DATETIME(0), TIMESTAMP(0). + For these new data types, MySQL-5.6 stores new type codes + MYSQL_TYPE_TIME2, MYSQL_TYPE_DATETIME2, MYSQL_TYPE_TIMESTAMP2 in binlog, + with fractional precision 0..6 put into metadata. + This makes it in theory possible to do row-based replication between + columns of different fractional precision (e.g. from TIME(1) on master + to TIME(6) on slave). However, it's not currently fully implemented yet. + MySQL-5.6 can only do row-based replication from the old types + TIME, DATETIME, TIMESTAMP (represented by MYSQL_TYPE_TIME, + MYSQL_TYPE_DATETIME and MYSQL_TYPE_TIMESTAMP type codes in binlog) + to the new corresponding types TIME(0), DATETIME(0), TIMESTAMP(0). + + Note: MariaDB starting from the version 10.0 understands the new + MySQL-5.6 type codes MYSQL_TYPE_TIME2, MYSQL_TYPE_DATETIME2, + MYSQL_TYPE_TIMESTAMP2. When started over MySQL-5.6 tables both on + master and on slave, MariaDB-10.0 can also do row-based replication + from the old types TIME, DATETIME, TIMESTAMP to the new MySQL-5.6 + types TIME(0), DATETIME(0), TIMESTAMP(0). + + Note: perhaps binlog should eventually be modified to store + real_type() instead of type() for all column types. + */ + return type(); + } + inline int cmp(const uchar *str) { return cmp(ptr,str); } + virtual int cmp_max(const uchar *a, const uchar *b, uint max_len) + { return cmp(a, b); } + virtual int cmp(const uchar *,const uchar *)=0; + virtual int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0U) + { return memcmp(a,b,pack_length()); } + virtual int cmp_offset(uint row_offset) + { return cmp(ptr,ptr+row_offset); } + virtual int cmp_binary_offset(uint row_offset) + { return cmp_binary(ptr, ptr+row_offset); }; + virtual int key_cmp(const uchar *a,const uchar *b) + { return cmp(a, b); } + virtual int key_cmp(const uchar *str, uint length) + { return cmp(ptr,str); } + /* + Update the value m of the 'min_val' field with the current value v + of this field if force_update is set to TRUE or if v < m. + Return TRUE if the value has been updated. + */ + virtual bool update_min(Field *min_val, bool force_update) + { + bool update_fl= force_update || cmp(ptr, min_val->ptr) < 0; + if (update_fl) + { + min_val->set_notnull(); + memcpy(min_val->ptr, ptr, pack_length()); + } + return update_fl; + } + /* + Update the value m of the 'max_val' field with the current value v + of this field if force_update is set to TRUE or if v > m. + Return TRUE if the value has been updated. + */ + virtual bool update_max(Field *max_val, bool force_update) + { + bool update_fl= force_update || cmp(ptr, max_val->ptr) > 0; + if (update_fl) + { + max_val->set_notnull(); + memcpy(max_val->ptr, ptr, pack_length()); + } + return update_fl; + } + virtual void store_field_value(uchar *val, uint len) + { + memcpy(ptr, val, len); + } + virtual uint decimals() const { return 0; } + /* + Caller beware: sql_type can change str.Ptr, so check + ptr() to see if it changed if you are using your own buffer + in str and restore it with set() if needed + */ + virtual void sql_type(String &str) const =0; + virtual uint size_of() const =0; // For new field + inline bool is_null(my_ptrdiff_t row_offset= 0) const + { + /* + The table may have been marked as containing only NULL values + for all fields if it is a NULL-complemented row of an OUTER JOIN + or if the query is an implicitly grouped query (has aggregate + functions but no GROUP BY clause) with no qualifying rows. If + this is the case (in which TABLE::null_row is true), the field + is considered to be NULL. + + Note that if a table->null_row is set then also all null_bits are + set for the row. + + In the case of the 'result_field' for GROUP BY, table->null_row might + refer to the *next* row in the table (when the algorithm is: read the + next row, see if any of group column values have changed, send the + result - grouped - row to the client if yes). So, table->null_row might + be wrong, but such a result_field is always nullable (that's defined by + original_field->maybe_null()) and we trust its null bit. + */ + return null_ptr ? null_ptr[row_offset] & null_bit : table->null_row; + } + inline bool is_real_null(my_ptrdiff_t row_offset= 0) const + { return null_ptr && (null_ptr[row_offset] & null_bit); } + inline bool is_null_in_record(const uchar *record) const + { + if (maybe_null_in_table()) + return record[(uint) (null_ptr - table->record[0])] & null_bit; + return 0; + } + inline void set_null(my_ptrdiff_t row_offset= 0) + { if (null_ptr) null_ptr[row_offset]|= null_bit; } + inline void set_notnull(my_ptrdiff_t row_offset= 0) + { if (null_ptr) null_ptr[row_offset]&= (uchar) ~null_bit; } + inline bool maybe_null(void) const + { return null_ptr != 0 || table->maybe_null; } + + /* @return true if this field is NULL-able (even if temporarily) */ + inline bool real_maybe_null(void) const { return null_ptr != 0; } + uint null_offset(const uchar *record) const + { return (uint) (null_ptr - record); } + /* + For a NULL-able field (that can actually store a NULL value in a table) + null_ptr points to the "null bitmap" in the table->record[0] header. For + NOT NULL fields it is either 0 or points outside table->record[0] into the + table->triggers->extra_null_bitmap (so that the field can store a NULL + value temporarily, only in memory) + */ + bool maybe_null_in_table() const + { return null_ptr >= table->record[0] && null_ptr <= ptr; } + + uint null_offset() const + { return null_offset(table->record[0]); } + void set_null_ptr(uchar *p_null_ptr, uint p_null_bit) + { + null_ptr= p_null_ptr; + null_bit= p_null_bit; + } + + bool stored_in_db() const { return !vcol_info || vcol_info->stored_in_db; } + + inline THD *get_thd() const + { return likely(table) ? table->in_use : current_thd; } + + enum { + LAST_NULL_BYTE_UNDEF= 0 + }; + + /* + Find the position of the last null byte for the field. + + SYNOPSIS + last_null_byte() + + DESCRIPTION + Return a pointer to the last byte of the null bytes where the + field conceptually is placed. + + RETURN VALUE + The position of the last null byte relative to the beginning of + the record. If the field does not use any bits of the null + bytes, the value 0 (LAST_NULL_BYTE_UNDEF) is returned. + */ + size_t last_null_byte() const { + size_t bytes= do_last_null_byte(); + DBUG_PRINT("debug", ("last_null_byte() ==> %ld", (long) bytes)); + DBUG_ASSERT(bytes <= table->s->null_bytes); + return bytes; + } + + void make_sort_key(uchar *buff, uint length); + virtual void make_field(Send_field *); + virtual void sort_string(uchar *buff,uint length)=0; + virtual bool optimize_range(uint idx, uint part); + virtual void free() {} + virtual Field *make_new_field(MEM_ROOT *root, TABLE *new_table, + bool keep_type); + virtual Field *new_key_field(MEM_ROOT *root, TABLE *new_table, + uchar *new_ptr, uint32 length, + uchar *new_null_ptr, uint new_null_bit); + Field *clone(MEM_ROOT *mem_root, TABLE *new_table); + Field *clone(MEM_ROOT *mem_root, TABLE *new_table, my_ptrdiff_t diff, + bool stat_flag= FALSE); + Field *clone(MEM_ROOT *mem_root, my_ptrdiff_t diff); + inline void move_field(uchar *ptr_arg,uchar *null_ptr_arg,uchar null_bit_arg) + { + ptr=ptr_arg; null_ptr=null_ptr_arg; null_bit=null_bit_arg; + } + inline void move_field(uchar *ptr_arg) { ptr=ptr_arg; } + inline uchar *record_ptr() // record[0] or wherever the field was moved to + { + my_ptrdiff_t offset= table->s->field[field_index]->ptr - table->s->default_values; + return ptr - offset; + } + virtual void move_field_offset(my_ptrdiff_t ptr_diff) + { + ptr=ADD_TO_PTR(ptr,ptr_diff, uchar*); + if (null_ptr) + null_ptr=ADD_TO_PTR(null_ptr,ptr_diff,uchar*); + } + virtual void get_image(uchar *buff, uint length, CHARSET_INFO *cs) + { memcpy(buff,ptr,length); } + virtual void set_image(const uchar *buff,uint length, CHARSET_INFO *cs) + { memcpy(ptr,buff,length); } + + + /* + Copy a field part into an output buffer. + + SYNOPSIS + Field::get_key_image() + buff [out] output buffer + length output buffer size + type itMBR for geometry blobs, otherwise itRAW + + DESCRIPTION + This function makes a copy of field part of size equal to or + less than "length" parameter value. + For fields of string types (CHAR, VARCHAR, TEXT) the rest of buffer + is padded by zero byte. + + NOTES + For variable length character fields (i.e. UTF-8) the "length" + parameter means a number of output buffer bytes as if all field + characters have maximal possible size (mbmaxlen). In the other words, + "length" parameter is a number of characters multiplied by + field_charset->mbmaxlen. + + RETURN + Number of copied bytes (excluding padded zero bytes -- see above). + */ + + virtual uint get_key_image(uchar *buff, uint length, imagetype type_arg) + { + get_image(buff, length, &my_charset_bin); + return length; + } + virtual void set_key_image(const uchar *buff,uint length) + { set_image(buff,length, &my_charset_bin); } + inline longlong val_int_offset(uint row_offset) + { + ptr+=row_offset; + longlong tmp=val_int(); + ptr-=row_offset; + return tmp; + } + inline longlong val_int(const uchar *new_ptr) + { + uchar *old_ptr= ptr; + longlong return_value; + ptr= (uchar*) new_ptr; + return_value= val_int(); + ptr= old_ptr; + return return_value; + } + inline String *val_str(String *str, const uchar *new_ptr) + { + uchar *old_ptr= ptr; + ptr= (uchar*) new_ptr; + val_str(str); + ptr= old_ptr; + return str; + } + virtual bool send_binary(Protocol *protocol); + + virtual uchar *pack(uchar *to, const uchar *from, uint max_length); + /** + @overload Field::pack(uchar*, const uchar*, uint, bool) + */ + uchar *pack(uchar *to, const uchar *from) + { + DBUG_ENTER("Field::pack"); + uchar *result= this->pack(to, from, UINT_MAX); + DBUG_RETURN(result); + } + + virtual const uchar *unpack(uchar* to, const uchar *from, + const uchar *from_end, uint param_data=0); + + virtual uint packed_col_length(const uchar *to, uint length) + { return length;} + virtual uint max_packed_col_length(uint max_length) + { return max_length;} + + uint offset(uchar *record) const + { + return (uint) (ptr - record); + } + void copy_from_tmp(int offset); + uint fill_cache_field(struct st_cache_field *copy); + virtual bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); + bool get_time(MYSQL_TIME *ltime) { return get_date(ltime, TIME_TIME_ONLY); } + virtual CHARSET_INFO *charset(void) const { return &my_charset_bin; } + virtual CHARSET_INFO *charset_for_protocol(void) const + { return binary() ? &my_charset_bin : charset(); } + virtual CHARSET_INFO *sort_charset(void) const { return charset(); } + virtual bool has_charset(void) const { return FALSE; } + virtual enum Derivation derivation(void) const + { return DERIVATION_IMPLICIT; } + virtual uint repertoire(void) const { return MY_REPERTOIRE_UNICODE30; } + virtual void set_derivation(enum Derivation derivation_arg, + uint repertoire_arg) + { } + virtual int set_time() { return 1; } + bool set_warning(Sql_condition::enum_warning_level, unsigned int code, + int cuted_increment) const; +protected: + bool set_warning(unsigned int code, int cuted_increment) const + { + return set_warning(Sql_condition::WARN_LEVEL_WARN, code, cuted_increment); + } + bool set_note(unsigned int code, int cuted_increment) const + { + return set_warning(Sql_condition::WARN_LEVEL_NOTE, code, cuted_increment); + } + void set_datetime_warning(Sql_condition::enum_warning_level, uint code, + const ErrConv *str, timestamp_type ts_type, + int cuted_increment) const; + void set_datetime_warning(uint code, + const ErrConv *str, timestamp_type ts_type, + int cuted_increment) const + { + set_datetime_warning(Sql_condition::WARN_LEVEL_WARN, code, str, ts_type, + cuted_increment); + } + void set_warning_truncated_wrong_value(const char *type, const char *value); + inline bool check_overflow(int op_result) + { + return (op_result == E_DEC_OVERFLOW); + } + int warn_if_overflow(int op_result); + Copy_func *get_identical_copy_func() const; +public: + void set_table_name(String *alias) + { + table_name= &alias->Ptr; + } + void init(TABLE *table_arg) + { + orig_table= table= table_arg; + set_table_name(&table_arg->alias); + } + + /* maximum possible display length */ + virtual uint32 max_display_length()= 0; + + /** + Whether a field being created is compatible with a existing one. + + Used by the ALTER TABLE code to evaluate whether the new definition + of a table is compatible with the old definition so that it can + determine if data needs to be copied over (table data change). + */ + virtual uint is_equal(Create_field *new_field); + /* convert decimal to longlong with overflow check */ + longlong convert_decimal2longlong(const my_decimal *val, bool unsigned_flag, + int *err); + /* The max. number of characters */ + virtual uint32 char_length() const + { + return field_length / charset()->mbmaxlen; + } + + virtual geometry_type get_geometry_type() + { + /* shouldn't get here. */ + DBUG_ASSERT(0); + return GEOM_GEOMETRY; + } + + ha_storage_media field_storage_type() const + { + return (ha_storage_media) + ((flags >> FIELD_FLAGS_STORAGE_MEDIA) & 3); + } + + void set_storage_type(ha_storage_media storage_type_arg) + { + DBUG_ASSERT(field_storage_type() == HA_SM_DEFAULT); + flags |= static_cast(storage_type_arg) << + FIELD_FLAGS_STORAGE_MEDIA; + } + + column_format_type column_format() const + { + return (column_format_type) + ((flags >> FIELD_FLAGS_COLUMN_FORMAT) & 3); + } + + void set_column_format(column_format_type column_format_arg) + { + DBUG_ASSERT(column_format() == COLUMN_FORMAT_TYPE_DEFAULT); + flags |= static_cast(column_format_arg) << + FIELD_FLAGS_COLUMN_FORMAT; + } + + /* + System versioning support. + */ + + bool is_generated() + { + return flags & (GENERATED_ROW_START_FLAG | GENERATED_ROW_END_FLAG); + } + + bool is_generated_row_start() + { + return flags & GENERATED_ROW_START_FLAG; + } + + bool is_generated_row_end() + { + return flags & GENERATED_ROW_END_FLAG; + } + + bool is_versioning_disabled() + { + return flags & WITHOUT_SYSTEM_VERSIONING_FLAG; + } + + /* Mark a field as auto-generated row start column. */ + void set_generated_row_start() + { + //DBUG_ASSERT((flags & GENERATED_ROW_END_FLAG) == 0); + flags |= GENERATED_ROW_START_FLAG; + } + + /* Mark a field as auto-generated row start column. */ + void set_generated_row_end() + { + //DBUG_ASSERT((flags & GENERATED_ROW_START_FLAG) == 0); + flags |= GENERATED_ROW_END_FLAG; + } + + /* Disable a field versioning for a versioned table. */ + void disable_versioning() + { + flags |= WITHOUT_SYSTEM_VERSIONING_FLAG; + } + + /* Inherit a field versioning status from the table. */ + void inherit_versioning() + { + flags &= ~WITHOUT_SYSTEM_VERSIONING_FLAG; + } + + /* + Validate a non-null field value stored in the given record + according to the current thread settings, e.g. sql_mode. + @param thd - the thread + @param record - the record to check in + */ + virtual bool validate_value_in_record(THD *thd, const uchar *record) const + { return false; } + bool validate_value_in_record_with_warn(THD *thd, const uchar *record); + key_map get_possible_keys(); + + /* Hash value */ + virtual void hash(ulong *nr, ulong *nr2); + +/** + Checks whether a string field is part of write_set. + + @return + FALSE - If field is not char/varchar/.... + - If field is char/varchar/.. and is not part of write set. + TRUE - If field is char/varchar/.. and is part of write set. +*/ + virtual bool is_varchar_and_in_write_set() const { return FALSE; } + + /* Check whether the field can be used as a join attribute in hash join */ + virtual bool hash_join_is_possible() { return TRUE; } + virtual bool eq_cmp_as_binary() { return TRUE; } + + /* Position of the field value within the interval of [min, max] */ + virtual double pos_in_interval(Field *min, Field *max) + { + return (double) 0.5; + } + + /* + Check if comparison between the field and an item unambiguously + identifies a distinct field value. + + Example1: SELECT * FROM t1 WHERE int_column=10; + This example returns distinct integer value of 10. + + Example2: SELECT * FROM t1 WHERE varchar_column=DATE'2001-01-01' + This example returns non-distinct values. + Comparison as DATE will return '2001-01-01' and '2001-01-01x', + but these two values are not equal to each other as VARCHARs. + See also the function with the same name in sql_select.cc. + */ + virtual bool test_if_equality_guarantees_uniqueness(const Item *const_item) + const; + virtual bool can_be_substituted_to_equal_item(const Context &ctx, + const Item_equal *item); + virtual Item *get_equal_const_item(THD *thd, const Context &ctx, + Item *const_item) + { + return const_item; + } + virtual bool can_optimize_keypart_ref(const Item_bool_func *cond, + const Item *item) const; + virtual bool can_optimize_hash_join(const Item_bool_func *cond, + const Item *item) const + { + return can_optimize_keypart_ref(cond, item); + } + virtual bool can_optimize_group_min_max(const Item_bool_func *cond, + const Item *const_item) const; + /** + Test if Field can use range optimizer for a standard comparison operation: + <=, <, =, <=>, >, >= + Note, this method does not cover spatial operations. + */ + virtual bool can_optimize_range(const Item_bool_func *cond, + const Item *item, + bool is_eq_func) const; + + bool can_optimize_outer_join_table_elimination(const Item_bool_func *cond, + const Item *item) const + { + // Exactly the same rules with REF access + return can_optimize_keypart_ref(cond, item); + } + + bool save_in_field_default_value(bool view_eror_processing); + bool save_in_field_ignore_value(bool view_error_processing); + + /* Mark field in read map. Updates also virtual fields */ + void register_field_in_read_map(); + + friend int cre_myisam(char * name, register TABLE *form, uint options, + ulonglong auto_increment_value); + friend class Copy_field; + friend class Item_avg_field; + friend class Item_std_field; + friend class Item_sum_num; + friend class Item_sum_sum; + friend class Item_sum_count; + friend class Item_sum_avg; + friend class Item_sum_std; + friend class Item_sum_min; + friend class Item_sum_max; + friend class Item_func_group_concat; + +private: + /* + Primitive for implementing last_null_byte(). + + SYNOPSIS + do_last_null_byte() + + DESCRIPTION + Primitive for the implementation of the last_null_byte() + function. This represents the inheritance interface and can be + overridden by subclasses. + */ + virtual size_t do_last_null_byte() const; + +/** + Retrieve the field metadata for fields. + + This default implementation returns 0 and saves 0 in the metadata_ptr + value. + + @param metadata_ptr First byte of field metadata + + @returns 0 no bytes written. +*/ + virtual int do_save_field_metadata(uchar *metadata_ptr) + { return 0; } + +protected: + uchar *pack_int(uchar *to, const uchar *from, size_t size) + { + memcpy(to, from, size); + return to + size; + } + + const uchar *unpack_int(uchar* to, const uchar *from, + const uchar *from_end, size_t size) + { + if (from + size > from_end) + return 0; + memcpy(to, from, size); + return from + size; + } + + uchar *pack_int16(uchar *to, const uchar *from) + { return pack_int(to, from, 2); } + const uchar *unpack_int16(uchar* to, const uchar *from, const uchar *from_end) + { return unpack_int(to, from, from_end, 2); } + uchar *pack_int24(uchar *to, const uchar *from) + { return pack_int(to, from, 3); } + const uchar *unpack_int24(uchar* to, const uchar *from, const uchar *from_end) + { return unpack_int(to, from, from_end, 3); } + uchar *pack_int32(uchar *to, const uchar *from) + { return pack_int(to, from, 4); } + const uchar *unpack_int32(uchar* to, const uchar *from, const uchar *from_end) + { return unpack_int(to, from, from_end, 4); } + uchar *pack_int64(uchar* to, const uchar *from) + { return pack_int(to, from, 8); } + const uchar *unpack_int64(uchar* to, const uchar *from, const uchar *from_end) + { return unpack_int(to, from, from_end, 8); } + + double pos_in_interval_val_real(Field *min, Field *max); + double pos_in_interval_val_str(Field *min, Field *max, uint data_offset); +}; + + +class Field_num :public Field { +protected: + int check_edom_and_important_data_truncation(const char *type, bool edom, + CHARSET_INFO *cs, + const char *str, uint length, + const char *end_of_num); + int check_edom_and_truncation(const char *type, bool edom, + CHARSET_INFO *cs, + const char *str, uint length, + const char *end_of_num); + int check_int(CHARSET_INFO *cs, const char *str, uint length, + const char *int_end, int error) + { + return check_edom_and_truncation("integer", + error == MY_ERRNO_EDOM || str == int_end, + cs, str, length, int_end); + } + bool get_int(CHARSET_INFO *cs, const char *from, uint len, + longlong *rnd, ulonglong unsigned_max, + longlong signed_min, longlong signed_max); + void prepend_zeros(String *value) const; + Item *get_equal_zerofill_const_item(THD *thd, const Context &ctx, + Item *const_item); +public: + const uint8 dec; + bool zerofill,unsigned_flag; // Purify cannot handle bit fields + Field_num(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, utype unireg_check_arg, + const char *field_name_arg, + uint8 dec_arg, bool zero_arg, bool unsigned_arg); + enum Item_result result_type () const { return INT_RESULT; } + enum Derivation derivation(void) const { return DERIVATION_NUMERIC; } + uint repertoire(void) const { return MY_REPERTOIRE_NUMERIC; } + CHARSET_INFO *charset(void) const { return &my_charset_numeric; } + Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item) + { + return (flags & ZEROFILL_FLAG) ? + get_equal_zerofill_const_item(thd, ctx, const_item) : + const_item; + } + void add_zerofill_and_unsigned(String &res) const; + friend class Create_field; + void make_field(Send_field *); + uint decimals() const { return (uint) dec; } + uint size_of() const { return sizeof(*this); } + bool eq_def(const Field *field) const; + Copy_func *get_copy_func(const Field *from) const + { + return do_field_int; + } + int save_in_field(Field *to) + { + return to->store(val_int(), MY_TEST(flags & UNSIGNED_FLAG)); + } + bool memcpy_field_possible(const Field *from) const + { + return real_type() == from->real_type() && + pack_length() == from->pack_length() && + !((flags & UNSIGNED_FLAG) && !(from->flags & UNSIGNED_FLAG)) && + decimals() == from->decimals(); + } + int store_decimal(const my_decimal *); + my_decimal *val_decimal(my_decimal *); + bool val_bool() { return val_int() != 0; } + uint is_equal(Create_field *new_field); + uint row_pack_length() const { return pack_length(); } + uint32 pack_length_from_metadata(uint field_metadata) { + uint32 length= pack_length(); + DBUG_PRINT("result", ("pack_length_from_metadata(%d): %u", + field_metadata, length)); + return length; + } + int store_time_dec(MYSQL_TIME *ltime, uint dec); + double pos_in_interval(Field *min, Field *max) + { + return pos_in_interval_val_real(min, max); + } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); +}; + + +class Field_str :public Field { +protected: + // TODO-10.2: Reuse DTCollation instead of these three members + CHARSET_INFO *field_charset; + enum Derivation field_derivation; + uint field_repertoire; +public: + bool can_be_substituted_to_equal_item(const Context &ctx, + const Item_equal *item_equal); + Field_str(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, utype unireg_check_arg, + const char *field_name_arg, CHARSET_INFO *charset); + Item_result result_type () const { return STRING_RESULT; } + uint decimals() const { return NOT_FIXED_DEC; } + int save_in_field(Field *to) { return save_in_field_str(to); } + bool memcpy_field_possible(const Field *from) const + { + return real_type() == from->real_type() && + pack_length() == from->pack_length() && + charset() == from->charset(); + } + int store(double nr); + int store(longlong nr, bool unsigned_val)=0; + int store_decimal(const my_decimal *); + int store(const char *to,uint length,CHARSET_INFO *cs)=0; + int store_hex_hybrid(const char *str, uint length) + { + return store(str, length, &my_charset_bin); + } + uint repertoire(void) const { return field_repertoire; } + CHARSET_INFO *charset(void) const { return field_charset; } + enum Derivation derivation(void) const { return field_derivation; } + void set_derivation(enum Derivation derivation_arg, + uint repertoire_arg) + { + field_derivation= derivation_arg; + field_repertoire= repertoire_arg; + } + bool binary() const { return field_charset == &my_charset_bin; } + uint32 max_display_length() { return field_length; } + friend class Create_field; + my_decimal *val_decimal(my_decimal *); + bool val_bool() { return val_real() != 0e0; } + virtual bool str_needs_quotes() { return TRUE; } + uint is_equal(Create_field *new_field); + bool eq_cmp_as_binary() { return MY_TEST(flags & BINARY_FLAG); } + virtual uint length_size() { return 0; } + double pos_in_interval(Field *min, Field *max) + { + return pos_in_interval_val_str(min, max, length_size()); + } + bool test_if_equality_guarantees_uniqueness(const Item *const_item) const; +}; + +/* base class for Field_string, Field_varstring and Field_blob */ + +class Field_longstr :public Field_str +{ +protected: + int report_if_important_data(const char *ptr, const char *end, + bool count_spaces); + bool check_string_copy_error(const String_copier *copier, + const char *end, CHARSET_INFO *cs); + int check_conversion_status(const String_copier *copier, + const char *end, CHARSET_INFO *cs, + bool count_spaces) + { + if (check_string_copy_error(copier, end, cs)) + return 2; + return report_if_important_data(copier->source_end_pos(), + end, count_spaces); + } + bool cmp_to_string_with_same_collation(const Item_bool_func *cond, + const Item *item) const; + bool cmp_to_string_with_stricter_collation(const Item_bool_func *cond, + const Item *item) const; +public: + Field_longstr(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, utype unireg_check_arg, + const char *field_name_arg, CHARSET_INFO *charset_arg) + :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, + field_name_arg, charset_arg) + {} + + int store_decimal(const my_decimal *d); + uint32 max_data_length() const; + + bool is_varchar_and_in_write_set() const + { + DBUG_ASSERT(table && table->write_set); + return bitmap_is_set(table->write_set, field_index); + } + bool match_collation_to_optimize_range() const { return true; } + + bool can_optimize_keypart_ref(const Item_bool_func *cond, + const Item *item) const; + bool can_optimize_hash_join(const Item_bool_func *cond, + const Item *item) const; + bool can_optimize_group_min_max(const Item_bool_func *cond, + const Item *const_item) const; + bool can_optimize_range(const Item_bool_func *cond, + const Item *item, + bool is_eq_func) const; +}; + +/* base class for float and double and decimal (old one) */ +class Field_real :public Field_num { +protected: + double get_double(const char *str, uint length, CHARSET_INFO *cs, int *err); +public: + bool not_fixed; + + Field_real(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, utype unireg_check_arg, + const char *field_name_arg, + uint8 dec_arg, bool zero_arg, bool unsigned_arg) + :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, + field_name_arg, dec_arg, zero_arg, unsigned_arg), + not_fixed(dec_arg >= FLOATING_POINT_DECIMALS) + {} + Item_result result_type () const { return REAL_RESULT; } + Copy_func *get_copy_func(const Field *from) const + { + return do_field_real; + } + int save_in_field(Field *to) { return to->store(val_real()); } + bool memcpy_field_possible(const Field *from) const + { + /* + Cannot do memcpy from a longer field to a shorter field, + e.g. a DOUBLE(53,10) into a DOUBLE(10,10). + But it should be OK the other way around. + */ + return Field_num::memcpy_field_possible(from) && + field_length >= from->field_length; + } + int store_decimal(const my_decimal *); + int store_time_dec(MYSQL_TIME *ltime, uint dec); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); + my_decimal *val_decimal(my_decimal *); + bool val_bool() { return val_real() != 0e0; } + uint32 max_display_length() { return field_length; } + uint size_of() const { return sizeof(*this); } + Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item); +}; + + +class Field_decimal :public Field_real { +public: + Field_decimal(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + uint8 dec_arg,bool zero_arg,bool unsigned_arg) + :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, + dec_arg, zero_arg, unsigned_arg) + {} + enum_field_types type() const { return MYSQL_TYPE_DECIMAL;} + enum ha_base_keytype key_type() const + { return zerofill ? HA_KEYTYPE_BINARY : HA_KEYTYPE_NUM; } + Copy_func *get_copy_func(const Field *from) const + { + return eq_def(from) ? get_identical_copy_func() : do_field_string; + } + int reset(void); + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + void overflow(bool negative); + bool zero_pack() const { return 0; } + void sql_type(String &str) const; + virtual uchar *pack(uchar* to, const uchar *from, uint max_length) + { + return Field::pack(to, from, max_length); + } +}; + + +/* New decimal/numeric field which use fixed point arithmetic */ +class Field_new_decimal :public Field_num { +private: + int do_save_field_metadata(uchar *first_byte); +public: + /* The maximum number of decimal digits can be stored */ + uint precision; + uint bin_size; + /* + Constructors take max_length of the field as a parameter - not the + precision as the number of decimal digits allowed. + So for example we need to count length from precision handling + CREATE TABLE ( DECIMAL(x,y)) + */ + Field_new_decimal(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + uint8 dec_arg, bool zero_arg, bool unsigned_arg); + Field_new_decimal(uint32 len_arg, bool maybe_null_arg, + const char *field_name_arg, uint8 dec_arg, + bool unsigned_arg); + enum_field_types type() const { return MYSQL_TYPE_NEWDECIMAL;} + enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } + Item_result result_type () const { return DECIMAL_RESULT; } + Copy_func *get_copy_func(const Field *from) const + { + // if (from->real_type() == MYSQL_TYPE_BIT) // QQ: why? + // return do_field_int; + return do_field_decimal; + } + int save_in_field(Field *to) + { + my_decimal buff; + return to->store_decimal(val_decimal(&buff)); + } + bool memcpy_field_possible(const Field *from) const + { + return Field_num::memcpy_field_possible(from) && + field_length == from->field_length; + } + int reset(void); + bool store_value(const my_decimal *decimal_value); + bool store_value(const my_decimal *decimal_value, int *native_error); + void set_value_on_overflow(my_decimal *decimal_value, bool sign); + int store(const char *to, uint length, CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + int store_time_dec(MYSQL_TIME *ltime, uint dec); + int store_decimal(const my_decimal *); + double val_real(void); + longlong val_int(void); + my_decimal *val_decimal(my_decimal *); + String *val_str(String*, String *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); + bool val_bool() + { + my_decimal decimal_value; + my_decimal *val= val_decimal(&decimal_value); + return val ? !my_decimal_is_zero(val) : 0; + } + int cmp(const uchar *, const uchar *); + void sort_string(uchar *buff, uint length); + bool zero_pack() const { return 0; } + void sql_type(String &str) const; + uint32 max_display_length() { return field_length; } + uint size_of() const { return sizeof(*this); } + uint32 pack_length() const { return (uint32) bin_size; } + uint pack_length_from_metadata(uint field_metadata); + uint row_pack_length() const { return pack_length(); } + bool compatible_field_size(uint field_metadata, Relay_log_info *rli, + uint16 mflags, int *order_var); + uint is_equal(Create_field *new_field); + virtual const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint param_data); + static Field *create_from_item(MEM_ROOT *root, Item *); + Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item); +}; + + +class Field_tiny :public Field_num { +public: + Field_tiny(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + bool zero_arg, bool unsigned_arg) + :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, + 0, zero_arg,unsigned_arg) + {} + enum_field_types type() const { return MYSQL_TYPE_TINY;} + enum ha_base_keytype key_type() const + { return unsigned_flag ? HA_KEYTYPE_BINARY : HA_KEYTYPE_INT8; } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + int reset(void) { ptr[0]=0; return 0; } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + bool send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 1; } + void sql_type(String &str) const; + uint32 max_display_length() { return 4; } + + virtual uchar *pack(uchar* to, const uchar *from, uint max_length) + { + *to= *from; + return to + 1; + } + + virtual const uchar *unpack(uchar* to, const uchar *from, + const uchar *from_end, uint param_data) + { + if (from == from_end) + return 0; + *to= *from; + return from + 1; + } +}; + + +class Field_short :public Field_num { +public: + Field_short(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + bool zero_arg, bool unsigned_arg) + :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, + 0, zero_arg,unsigned_arg) + {} + Field_short(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, + bool unsigned_arg) + :Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0, + NONE, field_name_arg, 0, 0, unsigned_arg) + {} + enum_field_types type() const { return MYSQL_TYPE_SHORT;} + enum ha_base_keytype key_type() const + { return unsigned_flag ? HA_KEYTYPE_USHORT_INT : HA_KEYTYPE_SHORT_INT;} + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + int reset(void) { ptr[0]=ptr[1]=0; return 0; } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + bool send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 2; } + void sql_type(String &str) const; + uint32 max_display_length() { return 6; } + + virtual uchar *pack(uchar* to, const uchar *from, uint max_length) + { return pack_int16(to, from); } + + virtual const uchar *unpack(uchar* to, const uchar *from, + const uchar *from_end, uint param_data) + { return unpack_int16(to, from, from_end); } +}; + +class Field_medium :public Field_num { +public: + Field_medium(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + bool zero_arg, bool unsigned_arg) + :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, + 0, zero_arg,unsigned_arg) + {} + enum_field_types type() const { return MYSQL_TYPE_INT24;} + enum ha_base_keytype key_type() const + { return unsigned_flag ? HA_KEYTYPE_UINT24 : HA_KEYTYPE_INT24; } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + int reset(void) { ptr[0]=ptr[1]=ptr[2]=0; return 0; } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + bool send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 3; } + void sql_type(String &str) const; + uint32 max_display_length() { return 8; } + + virtual uchar *pack(uchar* to, const uchar *from, uint max_length) + { + return Field::pack(to, from, max_length); + } +}; + + +class Field_long :public Field_num { +public: + Field_long(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + bool zero_arg, bool unsigned_arg) + :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, + 0, zero_arg,unsigned_arg) + {} + Field_long(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, + bool unsigned_arg) + :Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0, + NONE, field_name_arg,0,0,unsigned_arg) + {} + enum_field_types type() const { return MYSQL_TYPE_LONG;} + enum ha_base_keytype key_type() const + { return unsigned_flag ? HA_KEYTYPE_ULONG_INT : HA_KEYTYPE_LONG_INT; } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + int reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; } + double val_real(void); + longlong val_int(void); + bool send_binary(Protocol *protocol); + String *val_str(String*,String *); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 4; } + void sql_type(String &str) const; + uint32 max_display_length() { return MY_INT32_NUM_DECIMAL_DIGITS; } + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length __attribute__((unused))) + { + return pack_int32(to, from); + } + virtual const uchar *unpack(uchar* to, const uchar *from, + const uchar *from_end, + uint param_data __attribute__((unused))) + { + return unpack_int32(to, from, from_end); + } +}; + + +class Field_longlong :public Field_num { +public: + Field_longlong(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + bool zero_arg, bool unsigned_arg) + :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, + 0, zero_arg,unsigned_arg) + {} + Field_longlong(uint32 len_arg,bool maybe_null_arg, + const char *field_name_arg, + bool unsigned_arg) + :Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0, + NONE, field_name_arg,0,0,unsigned_arg) + {} + enum_field_types type() const { return MYSQL_TYPE_LONGLONG;} + enum ha_base_keytype key_type() const + { return unsigned_flag ? HA_KEYTYPE_ULONGLONG : HA_KEYTYPE_LONGLONG; } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + int reset(void) + { + ptr[0]=ptr[1]=ptr[2]=ptr[3]=ptr[4]=ptr[5]=ptr[6]=ptr[7]=0; + return 0; + } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + bool send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 8; } + void sql_type(String &str) const; + uint32 max_display_length() { return 20; } + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length __attribute__((unused))) + { + return pack_int64(to, from); + } + const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, + uint param_data __attribute__((unused))) + { + return unpack_int64(to, from, from_end); + } + + bool set_max(); + bool is_max(); +}; + + +class Field_float :public Field_real { +public: + Field_float(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + uint8 dec_arg,bool zero_arg,bool unsigned_arg) + :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, + dec_arg, zero_arg, unsigned_arg) + { + if (dec_arg >= FLOATING_POINT_DECIMALS) + dec_arg= NOT_FIXED_DEC; + } + Field_float(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg, + uint8 dec_arg) + :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0, + NONE, field_name_arg, dec_arg, 0, 0) + { + if (dec_arg >= FLOATING_POINT_DECIMALS) + dec_arg= NOT_FIXED_DEC; + } + enum_field_types type() const { return MYSQL_TYPE_FLOAT;} + enum ha_base_keytype key_type() const { return HA_KEYTYPE_FLOAT; } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + int reset(void) { bzero(ptr,sizeof(float)); return 0; } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + bool send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return sizeof(float); } + uint row_pack_length() const { return pack_length(); } + void sql_type(String &str) const; +private: + int do_save_field_metadata(uchar *first_byte); +}; + + +class Field_double :public Field_real { +public: + Field_double(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + uint8 dec_arg,bool zero_arg,bool unsigned_arg) + :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, + dec_arg, zero_arg, unsigned_arg) + { + if (dec_arg >= FLOATING_POINT_DECIMALS) + dec_arg= NOT_FIXED_DEC; + } + Field_double(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg, + uint8 dec_arg) + :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0, + NONE, field_name_arg, dec_arg, 0, 0) + { + if (dec_arg >= FLOATING_POINT_DECIMALS) + dec_arg= NOT_FIXED_DEC; + } + Field_double(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg, + uint8 dec_arg, bool not_fixed_arg) + :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0, + NONE, field_name_arg, dec_arg, 0, 0) + { + not_fixed= not_fixed_arg; + if (dec_arg >= FLOATING_POINT_DECIMALS) + dec_arg= NOT_FIXED_DEC; + } + enum_field_types type() const { return MYSQL_TYPE_DOUBLE;} + enum ha_base_keytype key_type() const { return HA_KEYTYPE_DOUBLE; } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + int reset(void) { bzero(ptr,sizeof(double)); return 0; } + double val_real(void); + longlong val_int(void) + { + Converter_double_to_longlong conv(Field_double::val_real(), false); + if (conv.error()) + conv.push_warning(get_thd(), Field_double::val_real(), false); + return conv.result(); + } + String *val_str(String*,String *); + bool send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return sizeof(double); } + uint row_pack_length() const { return pack_length(); } + void sql_type(String &str) const; +private: + int do_save_field_metadata(uchar *first_byte); +}; + + +/* Everything saved in this will disappear. It will always return NULL */ + +class Field_null :public Field_str { + static uchar null[1]; +public: + Field_null(uchar *ptr_arg, uint32 len_arg, + enum utype unireg_check_arg, const char *field_name_arg, + CHARSET_INFO *cs) + :Field_str(ptr_arg, len_arg, null, 1, + unireg_check_arg, field_name_arg, cs) + {} + enum_field_types type() const { return MYSQL_TYPE_NULL;} + Copy_func *get_copy_func(const Field *from) const + { + return do_field_string; + } + int store(const char *to, uint length, CHARSET_INFO *cs) + { null[0]=1; return 0; } + int store(double nr) { null[0]=1; return 0; } + int store(longlong nr, bool unsigned_val) { null[0]=1; return 0; } + int store_decimal(const my_decimal *d) { null[0]=1; return 0; } + int reset(void) { return 0; } + double val_real(void) { return 0.0;} + longlong val_int(void) { return 0;} + bool val_bool(void) { return false; } + my_decimal *val_decimal(my_decimal *) { return 0; } + String *val_str(String *value,String *value2) + { value2->length(0); return value2;} + int cmp(const uchar *a, const uchar *b) { return 0;} + void sort_string(uchar *buff, uint length) {} + uint32 pack_length() const { return 0; } + void sql_type(String &str) const; + uint size_of() const { return sizeof(*this); } + uint32 max_display_length() { return 4; } + void move_field_offset(my_ptrdiff_t ptr_diff) {} + bool can_optimize_keypart_ref(const Item_bool_func *cond, + const Item *item) const + { + DBUG_ASSERT(0); + return false; + } + bool can_optimize_group_min_max(const Item_bool_func *cond, + const Item *const_item) const + { + DBUG_ASSERT(0); + return false; + } +}; + + +class Field_temporal: public Field { +protected: + Item *get_equal_const_item_datetime(THD *thd, const Context &ctx, + Item *const_item); +public: + Field_temporal(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, utype unireg_check_arg, + const char *field_name_arg) + :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, + field_name_arg) + { flags|= BINARY_FLAG; } + Item_result result_type () const { return STRING_RESULT; } + int store_hex_hybrid(const char *str, uint length) + { + return store(str, length, &my_charset_bin); + } + Copy_func *get_copy_func(const Field *from) const; + int save_in_field(Field *to) + { + MYSQL_TIME ltime; + if (get_date(<ime, 0)) + return to->reset(); + return to->store_time_dec(<ime, decimals()); + } + bool memcpy_field_possible(const Field *from) const; + uint32 max_display_length() { return field_length; } + bool str_needs_quotes() { return TRUE; } + enum Derivation derivation(void) const { return DERIVATION_NUMERIC; } + uint repertoire(void) const { return MY_REPERTOIRE_NUMERIC; } + CHARSET_INFO *charset(void) const { return &my_charset_numeric; } + CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; } + bool binary() const { return true; } + enum Item_result cmp_type () const { return TIME_RESULT; } + bool val_bool() { return val_real() != 0e0; } + uint is_equal(Create_field *new_field); + bool eq_def(const Field *field) const + { + return (Field::eq_def(field) && decimals() == field->decimals()); + } + my_decimal *val_decimal(my_decimal*); + void set_warnings(Sql_condition::enum_warning_level trunc_level, + const ErrConv *str, int was_cut, timestamp_type ts_type); + double pos_in_interval(Field *min, Field *max) + { + return pos_in_interval_val_real(min, max); + } + bool can_optimize_keypart_ref(const Item_bool_func *cond, + const Item *item) const; + bool can_optimize_group_min_max(const Item_bool_func *cond, + const Item *const_item) const; + bool can_optimize_range(const Item_bool_func *cond, + const Item *item, + bool is_eq_func) const + { + return true; + } +}; + + +/** + Abstract class for: + - DATE + - DATETIME + - DATETIME(1..6) + - DATETIME(0..6) - MySQL56 version +*/ +class Field_temporal_with_date: public Field_temporal { +protected: + int store_TIME_with_warning(MYSQL_TIME *ltime, const ErrConv *str, + int was_cut, int have_smth_to_conv); + virtual void store_TIME(MYSQL_TIME *ltime) = 0; + virtual bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, + ulonglong fuzzydate) const = 0; + bool validate_MMDD(bool not_zero_date, uint month, uint day, + ulonglong fuzzydate) const + { + if (!not_zero_date) + return fuzzydate & TIME_NO_ZERO_DATE; + if (!month || !day) + return fuzzydate & TIME_NO_ZERO_IN_DATE; + return false; + } +public: + Field_temporal_with_date(uchar *ptr_arg, uint32 len_arg, + uchar *null_ptr_arg, uchar null_bit_arg, + utype unireg_check_arg, + const char *field_name_arg) + :Field_temporal(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg) + {} + int store(const char *to, uint length, CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + int store_time_dec(MYSQL_TIME *ltime, uint dec); + int store_decimal(const my_decimal *); + bool validate_value_in_record(THD *thd, const uchar *record) const; +}; + + +class Field_timestamp :public Field_temporal { +protected: + int store_TIME_with_warning(THD *, MYSQL_TIME *, const ErrConv *, + int warnings, bool have_smth_to_conv); +public: + Field_timestamp(uchar *ptr_arg, uint32 len_arg, + uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + TABLE_SHARE *share); + enum_field_types type() const { return MYSQL_TYPE_TIMESTAMP;} + enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + int store_time_dec(MYSQL_TIME *ltime, uint dec); + int store_decimal(const my_decimal *); + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + bool send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 4; } + void sql_type(String &str) const; + bool zero_pack() const { return 0; } + int set_time(); + bool set_explicit_default(Item *value); + int evaluate_update_default_function() + { + int res= 0; + if (has_update_default_function()) + res= set_time(); + return res; + } + /* Get TIMESTAMP field value as seconds since begging of Unix Epoch */ + virtual my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const; + my_time_t get_timestamp(ulong *sec_part) const + { + return get_timestamp(ptr, sec_part); + } + virtual void store_TIME(my_time_t timestamp, ulong sec_part) + { + int4store(ptr,timestamp); + } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); + uchar *pack(uchar *to, const uchar *from, + uint max_length __attribute__((unused))) + { + return pack_int32(to, from); + } + const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, + uint param_data __attribute__((unused))) + { + return unpack_int32(to, from, from_end); + } + bool validate_value_in_record(THD *thd, const uchar *record) const; + Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item) + { + return get_equal_const_item_datetime(thd, ctx, const_item); + } + uint size_of() const { return sizeof(*this); } +}; + + +/** + Abstract class for: + - TIMESTAMP(1..6) + - TIMESTAMP(0..6) - MySQL56 version +*/ +class Field_timestamp_with_dec :public Field_timestamp { +protected: + uint dec; +public: + Field_timestamp_with_dec(uchar *ptr_arg, + uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, + const char *field_name_arg, + TABLE_SHARE *share, uint dec_arg) : + Field_timestamp(ptr_arg, + MAX_DATETIME_WIDTH + dec_arg + MY_TEST(dec_arg), null_ptr_arg, + null_bit_arg, unireg_check_arg, field_name_arg, share), + dec(dec_arg) + { + DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS); + } + uint decimals() const { return dec; } + enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } + uchar *pack(uchar *to, const uchar *from, uint max_length) + { return Field::pack(to, from, max_length); } + const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, + uint param_data) + { return Field::unpack(to, from, from_end, param_data); } + void make_field(Send_field *field); + void sort_string(uchar *to, uint length) + { + DBUG_ASSERT(length == pack_length()); + memcpy(to, ptr, length); + } + bool send_binary(Protocol *protocol); + double val_real(void); + my_decimal* val_decimal(my_decimal*); + int set_time(); +}; + + +class Field_timestamp_hires :public Field_timestamp_with_dec { +public: + Field_timestamp_hires(uchar *ptr_arg, + uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, + const char *field_name_arg, + TABLE_SHARE *share, uint dec_arg) : + Field_timestamp_with_dec(ptr_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, share, dec_arg) + { + DBUG_ASSERT(dec); + } + my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const; + void store_TIME(my_time_t timestamp, ulong sec_part); + int cmp(const uchar *,const uchar *); + uint32 pack_length() const; + uint size_of() const { return sizeof(*this); } +}; + + +/** + TIMESTAMP(0..6) - MySQL56 version +*/ +class Field_timestampf :public Field_timestamp_with_dec { + int do_save_field_metadata(uchar *metadata_ptr) + { + *metadata_ptr= decimals(); + return 1; + } +public: + Field_timestampf(uchar *ptr_arg, + uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, + const char *field_name_arg, + TABLE_SHARE *share, uint dec_arg) : + Field_timestamp_with_dec(ptr_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, share, dec_arg) + {} + enum_field_types real_type() const { return MYSQL_TYPE_TIMESTAMP2; } + enum_field_types binlog_type() const { return MYSQL_TYPE_TIMESTAMP2; } + uint32 pack_length() const + { + return my_timestamp_binary_length(dec); + } + uint row_pack_length() const { return pack_length(); } + uint pack_length_from_metadata(uint field_metadata) + { + DBUG_ENTER("Field_timestampf::pack_length_from_metadata"); + uint tmp= my_timestamp_binary_length(field_metadata); + DBUG_RETURN(tmp); + } + int cmp(const uchar *a_ptr,const uchar *b_ptr) + { + return memcmp(a_ptr, b_ptr, pack_length()); + } + bool set_max(); + bool is_max(); + void store_TIME(my_time_t timestamp, ulong sec_part); + my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const; + uint size_of() const { return sizeof(*this); } +}; + + +class Field_year :public Field_tiny { +public: + Field_year(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg) + :Field_tiny(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, 1, 1) + {} + enum_field_types type() const { return MYSQL_TYPE_YEAR;} + Copy_func *get_copy_func(const Field *from) const + { + if (eq_def(from)) + return get_identical_copy_func(); + switch (from->cmp_type()) { + case STRING_RESULT: + return do_field_string; + case TIME_RESULT: + return do_field_temporal; + case DECIMAL_RESULT: + return do_field_decimal; + case REAL_RESULT: + return do_field_real; + case INT_RESULT: + break; + case ROW_RESULT: + default: + DBUG_ASSERT(0); + break; + } + return do_field_int; + } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + int store_time_dec(MYSQL_TIME *ltime, uint dec); + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); + bool send_binary(Protocol *protocol); + uint32 max_display_length() { return field_length; } + void sql_type(String &str) const; +}; + + +class Field_date :public Field_temporal_with_date { + void store_TIME(MYSQL_TIME *ltime); + bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const; +public: + Field_date(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg) + :Field_temporal_with_date(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg) {} + enum_field_types type() const { return MYSQL_TYPE_DATE;} + enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; } + int reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return Field_date::get_TIME(ltime, ptr, fuzzydate); } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + bool send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 4; } + void sql_type(String &str) const; + uchar *pack(uchar* to, const uchar *from, + uint max_length __attribute__((unused))) + { + return pack_int32(to, from); + } + const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, + uint param_data __attribute__((unused))) + { + return unpack_int32(to, from, from_end); + } + uint size_of() const { return sizeof(*this); } +}; + + +class Field_newdate :public Field_temporal_with_date { + void store_TIME(MYSQL_TIME *ltime); + bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const; +public: + Field_newdate(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg) + :Field_temporal_with_date(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg) + {} + enum_field_types type() const { return MYSQL_TYPE_DATE;} + enum_field_types real_type() const { return MYSQL_TYPE_NEWDATE; } + enum ha_base_keytype key_type() const { return HA_KEYTYPE_UINT24; } + int reset(void) { ptr[0]=ptr[1]=ptr[2]=0; return 0; } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + bool send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 3; } + void sql_type(String &str) const; + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return Field_newdate::get_TIME(ltime, ptr, fuzzydate); } + uint size_of() const { return sizeof(*this); } + Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item); +}; + + +class Field_time :public Field_temporal { + /* + when this Field_time instance is used for storing values for index lookups + (see class store_key, Field::new_key_field(), etc), the following + might be set to TO_DAYS(CURDATE()). See also Field_time::store_time_dec() + */ + long curdays; +protected: + virtual void store_TIME(MYSQL_TIME *ltime); + int store_TIME_with_warning(MYSQL_TIME *ltime, const ErrConv *str, + int was_cut, int have_smth_to_conv); + bool check_zero_in_date_with_warn(ulonglong fuzzydate); + static void do_field_time(Copy_field *copy); +public: + Field_time(uchar *ptr_arg, uint length_arg, uchar *null_ptr_arg, + uchar null_bit_arg, enum utype unireg_check_arg, + const char *field_name_arg) + :Field_temporal(ptr_arg, length_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg), curdays(0) + {} + enum_field_types type() const { return MYSQL_TYPE_TIME;} + enum ha_base_keytype key_type() const { return HA_KEYTYPE_INT24; } + Copy_func *get_copy_func(const Field *from) const + { + return from->cmp_type() == REAL_RESULT ? do_field_string : // MDEV-9344 + from->type() == MYSQL_TYPE_YEAR ? do_field_int : + from->type() == MYSQL_TYPE_BIT ? do_field_int : + eq_def(from) ? get_identical_copy_func() : + do_field_time; + } + bool memcpy_field_possible(const Field *from) const + { + return real_type() == from->real_type() && + decimals() == from->decimals(); + } + int store_time_dec(MYSQL_TIME *ltime, uint dec); + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + int store_decimal(const my_decimal *); + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); + bool send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 3; } + void sql_type(String &str) const; + uint size_of() const { return sizeof(*this); } + void set_curdays(THD *thd); + Field *new_key_field(MEM_ROOT *root, TABLE *new_table, + uchar *new_ptr, uint32 length, + uchar *new_null_ptr, uint new_null_bit); + Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item); +}; + + +/** + Abstract class for: + - TIME(1..6) + - TIME(0..6) - MySQL56 version +*/ +class Field_time_with_dec :public Field_time { +protected: + uint dec; +public: + Field_time_with_dec(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + uint dec_arg) + :Field_time(ptr_arg, MIN_TIME_WIDTH + dec_arg + MY_TEST(dec_arg), + null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg), + dec(dec_arg) + { + DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS); + } + uint decimals() const { return dec; } + enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } + longlong val_int(void); + double val_real(void); + void make_field(Send_field *); +}; + + +/** + TIME(1..6) +*/ +class Field_time_hires :public Field_time_with_dec { + longlong zero_point; + void store_TIME(MYSQL_TIME *ltime); +public: + Field_time_hires(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + uint dec_arg) + :Field_time_with_dec(ptr_arg, null_ptr_arg, + null_bit_arg, unireg_check_arg, field_name_arg, + dec_arg) + { + DBUG_ASSERT(dec); + zero_point= sec_part_shift( + ((TIME_MAX_VALUE_SECONDS+1LL)*TIME_SECOND_PART_FACTOR), dec); + } + int reset(void); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const; + uint size_of() const { return sizeof(*this); } +}; + + +/** + TIME(0..6) - MySQL56 version +*/ +class Field_timef :public Field_time_with_dec { + void store_TIME(MYSQL_TIME *ltime); + int do_save_field_metadata(uchar *metadata_ptr) + { + *metadata_ptr= decimals(); + return 1; + } +public: + Field_timef(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + uint dec_arg) + :Field_time_with_dec(ptr_arg, null_ptr_arg, + null_bit_arg, unireg_check_arg, field_name_arg, + dec_arg) + { + DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS); + } + enum_field_types real_type() const { return MYSQL_TYPE_TIME2; } + enum_field_types binlog_type() const { return MYSQL_TYPE_TIME2; } + uint32 pack_length() const + { + return my_time_binary_length(dec); + } + uint row_pack_length() const { return pack_length(); } + uint pack_length_from_metadata(uint field_metadata) + { + DBUG_ENTER("Field_timef::pack_length_from_metadata"); + uint tmp= my_time_binary_length(field_metadata); + DBUG_RETURN(tmp); + } + void sort_string(uchar *to, uint length) + { + DBUG_ASSERT(length == Field_timef::pack_length()); + memcpy(to, ptr, length); + } + int cmp(const uchar *a_ptr, const uchar *b_ptr) + { + return memcmp(a_ptr, b_ptr, pack_length()); + } + int reset(); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); + uint size_of() const { return sizeof(*this); } +}; + + +class Field_datetime :public Field_temporal_with_date { + void store_TIME(MYSQL_TIME *ltime); + bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const; +public: + Field_datetime(uchar *ptr_arg, uint length_arg, uchar *null_ptr_arg, + uchar null_bit_arg, enum utype unireg_check_arg, + const char *field_name_arg) + :Field_temporal_with_date(ptr_arg, length_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg) + { + if (unireg_check == TIMESTAMP_UN_FIELD || + unireg_check == TIMESTAMP_DNUN_FIELD) + flags|= ON_UPDATE_NOW_FLAG; + } + enum_field_types type() const { return MYSQL_TYPE_DATETIME;} + enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONGLONG; } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + bool send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 8; } + void sql_type(String &str) const; + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return Field_datetime::get_TIME(ltime, ptr, fuzzydate); } + int set_time(); + int evaluate_update_default_function() + { + int res= 0; + if (has_update_default_function()) + res= set_time(); + return res; + } + uchar *pack(uchar* to, const uchar *from, + uint max_length __attribute__((unused))) + { + return pack_int64(to, from); + } + const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, + uint param_data __attribute__((unused))) + { + return unpack_int64(to, from, from_end); + } + Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item) + { + return get_equal_const_item_datetime(thd, ctx, const_item); + } + uint size_of() const { return sizeof(*this); } +}; + + +/** + Abstract class for: + - DATETIME(1..6) + - DATETIME(0..6) - MySQL56 version +*/ +class Field_datetime_with_dec :public Field_datetime { +protected: + uint dec; +public: + Field_datetime_with_dec(uchar *ptr_arg, uchar *null_ptr_arg, + uchar null_bit_arg, enum utype unireg_check_arg, + const char *field_name_arg, uint dec_arg) + :Field_datetime(ptr_arg, MAX_DATETIME_WIDTH + dec_arg + MY_TEST(dec_arg), + null_ptr_arg, null_bit_arg, unireg_check_arg, + field_name_arg), dec(dec_arg) + { + DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS); + } + uint decimals() const { return dec; } + enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } + void make_field(Send_field *field); + bool send_binary(Protocol *protocol); + uchar *pack(uchar *to, const uchar *from, uint max_length) + { return Field::pack(to, from, max_length); } + const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, + uint param_data) + { return Field::unpack(to, from, from_end, param_data); } + void sort_string(uchar *to, uint length) + { + DBUG_ASSERT(length == pack_length()); + memcpy(to, ptr, length); + } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); +}; + + +/** + DATETIME(1..6) +*/ +class Field_datetime_hires :public Field_datetime_with_dec { + void store_TIME(MYSQL_TIME *ltime); + bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const; +public: + Field_datetime_hires(uchar *ptr_arg, uchar *null_ptr_arg, + uchar null_bit_arg, enum utype unireg_check_arg, + const char *field_name_arg, uint dec_arg) + :Field_datetime_with_dec(ptr_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, dec_arg) + { + DBUG_ASSERT(dec); + } + int cmp(const uchar *,const uchar *); + uint32 pack_length() const; + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return Field_datetime_hires::get_TIME(ltime, ptr, fuzzydate); } + uint size_of() const { return sizeof(*this); } +}; + + +/** + DATETIME(0..6) - MySQL56 version +*/ +class Field_datetimef :public Field_datetime_with_dec { + void store_TIME(MYSQL_TIME *ltime); + bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const; + int do_save_field_metadata(uchar *metadata_ptr) + { + *metadata_ptr= decimals(); + return 1; + } +public: + Field_datetimef(uchar *ptr_arg, uchar *null_ptr_arg, + uchar null_bit_arg, enum utype unireg_check_arg, + const char *field_name_arg, uint dec_arg) + :Field_datetime_with_dec(ptr_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, dec_arg) + {} + enum_field_types real_type() const { return MYSQL_TYPE_DATETIME2; } + enum_field_types binlog_type() const { return MYSQL_TYPE_DATETIME2; } + uint32 pack_length() const + { + return my_datetime_binary_length(dec); + } + uint row_pack_length() const { return pack_length(); } + uint pack_length_from_metadata(uint field_metadata) + { + DBUG_ENTER("Field_datetimef::pack_length_from_metadata"); + uint tmp= my_datetime_binary_length(field_metadata); + DBUG_RETURN(tmp); + } + int cmp(const uchar *a_ptr, const uchar *b_ptr) + { + return memcmp(a_ptr, b_ptr, pack_length()); + } + int reset(); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return Field_datetimef::get_TIME(ltime, ptr, fuzzydate); } + uint size_of() const { return sizeof(*this); } +}; + + +static inline Field_timestamp * +new_Field_timestamp(MEM_ROOT *root,uchar *ptr, uchar *null_ptr, uchar null_bit, + enum Field::utype unireg_check, const char *field_name, + TABLE_SHARE *share, uint dec) +{ + if (dec==0) + return new (root) + Field_timestamp(ptr, MAX_DATETIME_WIDTH, null_ptr, + null_bit, unireg_check, field_name, share); + if (dec >= FLOATING_POINT_DECIMALS) + dec= MAX_DATETIME_PRECISION; + return new (root) + Field_timestamp_hires(ptr, null_ptr, null_bit, unireg_check, + field_name, share, dec); +} + +static inline Field_time * +new_Field_time(MEM_ROOT *root, uchar *ptr, uchar *null_ptr, uchar null_bit, + enum Field::utype unireg_check, const char *field_name, + uint dec) +{ + if (dec == 0) + return new (root) + Field_time(ptr, MIN_TIME_WIDTH, null_ptr, null_bit, unireg_check, + field_name); + if (dec >= FLOATING_POINT_DECIMALS) + dec= MAX_DATETIME_PRECISION; + return new (root) + Field_time_hires(ptr, null_ptr, null_bit, unireg_check, field_name, dec); +} + +static inline Field_datetime * +new_Field_datetime(MEM_ROOT *root, uchar *ptr, uchar *null_ptr, uchar null_bit, + enum Field::utype unireg_check, + const char *field_name, uint dec) +{ + if (dec == 0) + return new (root) + Field_datetime(ptr, MAX_DATETIME_WIDTH, null_ptr, null_bit, + unireg_check, field_name); + if (dec >= FLOATING_POINT_DECIMALS) + dec= MAX_DATETIME_PRECISION; + return new (root) + Field_datetime_hires(ptr, null_ptr, null_bit, + unireg_check, field_name, dec); +} + +class Field_string :public Field_longstr { + class Warn_filter_string: public Warn_filter + { + public: + Warn_filter_string(const THD *thd, const Field_string *field); + }; +public: + bool can_alter_field_type; + Field_string(uchar *ptr_arg, uint32 len_arg,uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + CHARSET_INFO *cs) + :Field_longstr(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, cs), + can_alter_field_type(1) {}; + Field_string(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, + CHARSET_INFO *cs) + :Field_longstr((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, 0, + NONE, field_name_arg, cs), + can_alter_field_type(1) {}; + + enum_field_types type() const + { + return ((can_alter_field_type && orig_table && + orig_table->s->db_create_options & HA_OPTION_PACK_RECORD && + field_length >= 4) && + orig_table->s->frm_version < FRM_VER_TRUE_VARCHAR ? + MYSQL_TYPE_VAR_STRING : MYSQL_TYPE_STRING); + } + enum ha_base_keytype key_type() const + { return binary() ? HA_KEYTYPE_BINARY : HA_KEYTYPE_TEXT; } + bool zero_pack() const { return 0; } + Copy_func *get_copy_func(const Field *from) const; + int reset(void) + { + charset()->cset->fill(charset(),(char*) ptr, field_length, + (has_charset() ? ' ' : 0)); + return 0; + } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(longlong nr, bool unsigned_val); + int store(double nr) { return Field_str::store(nr); } /* QQ: To be deleted */ + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + my_decimal *val_decimal(my_decimal *); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + void sql_type(String &str) const; + virtual uchar *pack(uchar *to, const uchar *from, + uint max_length); + virtual const uchar *unpack(uchar* to, const uchar *from, + const uchar *from_end,uint param_data); + uint pack_length_from_metadata(uint field_metadata) + { + DBUG_PRINT("debug", ("field_metadata: 0x%04x", field_metadata)); + if (field_metadata == 0) + return row_pack_length(); + return (((field_metadata >> 4) & 0x300) ^ 0x300) + (field_metadata & 0x00ff); + } + bool compatible_field_size(uint field_metadata, Relay_log_info *rli, + uint16 mflags, int *order_var); + uint row_pack_length() const { return field_length; } + int pack_cmp(const uchar *a,const uchar *b,uint key_length, + bool insert_or_update); + int pack_cmp(const uchar *b,uint key_length,bool insert_or_update); + uint packed_col_length(const uchar *to, uint length); + uint max_packed_col_length(uint max_length); + uint size_of() const { return sizeof(*this); } + enum_field_types real_type() const { return MYSQL_TYPE_STRING; } + bool has_charset(void) const + { return charset() == &my_charset_bin ? FALSE : TRUE; } + Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type); + virtual uint get_key_image(uchar *buff,uint length, imagetype type); +private: + int do_save_field_metadata(uchar *first_byte); +}; + + +class Field_varstring :public Field_longstr { + uchar *get_data() const + { + return ptr + length_bytes; + } + uint get_length() const + { + return length_bytes == 1 ? (uint) *ptr : uint2korr(ptr); + } +public: + /* + The maximum space available in a Field_varstring, in bytes. See + length_bytes. + */ + static const uint MAX_SIZE; + /* Store number of bytes used to store length (1 or 2) */ + uint32 length_bytes; + Field_varstring(uchar *ptr_arg, + uint32 len_arg, uint length_bytes_arg, + uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + TABLE_SHARE *share, CHARSET_INFO *cs) + :Field_longstr(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, cs), + length_bytes(length_bytes_arg) + { + share->varchar_fields++; + } + Field_varstring(uint32 len_arg,bool maybe_null_arg, + const char *field_name_arg, + TABLE_SHARE *share, CHARSET_INFO *cs) + :Field_longstr((uchar*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0, + NONE, field_name_arg, cs), + length_bytes(len_arg < 256 ? 1 :2) + { + share->varchar_fields++; + } + + enum_field_types type() const { return MYSQL_TYPE_VARCHAR; } + enum ha_base_keytype key_type() const; + uint row_pack_length() const { return field_length; } + bool zero_pack() const { return 0; } + int reset(void) { bzero(ptr,field_length+length_bytes); return 0; } + uint32 pack_length() const { return (uint32) field_length+length_bytes; } + uint32 key_length() const { return (uint32) field_length; } + uint32 sort_length() const + { + return (uint32) field_length + (field_charset == &my_charset_bin ? + length_bytes : 0); + } + Copy_func *get_copy_func(const Field *from) const; + bool memcpy_field_possible(const Field *from) const + { + return Field_str::memcpy_field_possible(from) && + length_bytes == ((Field_varstring*) from)->length_bytes; + } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(longlong nr, bool unsigned_val); + int store(double nr) { return Field_str::store(nr); } /* QQ: To be deleted */ + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + my_decimal *val_decimal(my_decimal *); + int cmp_max(const uchar *, const uchar *, uint max_length); + int cmp(const uchar *a,const uchar *b) + { + return cmp_max(a, b, ~0U); + } + void sort_string(uchar *buff,uint length); + uint get_key_image(uchar *buff,uint length, imagetype type); + void set_key_image(const uchar *buff,uint length); + void sql_type(String &str) const; + virtual uchar *pack(uchar *to, const uchar *from, uint max_length); + virtual const uchar *unpack(uchar* to, const uchar *from, + const uchar *from_end, uint param_data); + int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0U); + int key_cmp(const uchar *,const uchar*); + int key_cmp(const uchar *str, uint length); + uint packed_col_length(const uchar *to, uint length); + uint max_packed_col_length(uint max_length); + uint32 data_length(); + uint size_of() const { return sizeof(*this); } + enum_field_types real_type() const { return MYSQL_TYPE_VARCHAR; } + bool has_charset(void) const + { return charset() == &my_charset_bin ? FALSE : TRUE; } + Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type); + Field *new_key_field(MEM_ROOT *root, TABLE *new_table, + uchar *new_ptr, uint32 length, + uchar *new_null_ptr, uint new_null_bit); + uint is_equal(Create_field *new_field); + void hash(ulong *nr, ulong *nr2); + uint length_size() { return length_bytes; } +private: + int do_save_field_metadata(uchar *first_byte); +}; + + +class Field_blob :public Field_longstr { +protected: + /** + The number of bytes used to represent the length of the blob. + */ + uint packlength; + + /** + The 'value'-object is a cache fronting the storage engine. + */ + String value; + /** + Cache for blob values when reading a row with a virtual blob + field. This is needed to not destroy the old cached value when + updating the blob with a new value when creating the new row. + */ + String read_value; + + static void do_copy_blob(Copy_field *copy); + static void do_conv_blob(Copy_field *copy); +public: + Field_blob(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + TABLE_SHARE *share, uint blob_pack_length, CHARSET_INFO *cs); + Field_blob(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, + CHARSET_INFO *cs) + :Field_longstr((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, 0, + NONE, field_name_arg, cs), + packlength(4) + { + flags|= BLOB_FLAG; + } + Field_blob(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, + CHARSET_INFO *cs, bool set_packlength) + :Field_longstr((uchar*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0, + NONE, field_name_arg, cs) + { + flags|= BLOB_FLAG; + packlength= 4; + if (set_packlength) + { + packlength= len_arg <= 255 ? 1 : + len_arg <= 65535 ? 2 : + len_arg <= 16777215 ? 3 : 4; + } + } + Field_blob(uint32 packlength_arg) + :Field_longstr((uchar*) 0, 0, (uchar*) "", 0, NONE, "temp", system_charset_info), + packlength(packlength_arg) {} + /* Note that the default copy constructor is used, in clone() */ + enum_field_types type() const { return MYSQL_TYPE_BLOB;} + enum ha_base_keytype key_type() const + { return binary() ? HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2; } + Copy_func *get_copy_func(const Field *from) const + { + /* + TODO: MDEV-9331 + if (from->type() == MYSQL_TYPE_BIT) + return do_field_int; + */ + if (!(from->flags & BLOB_FLAG) || from->charset() != charset()) + return do_conv_blob; + if (from->pack_length() != Field_blob::pack_length()) + return do_copy_blob; + return get_identical_copy_func(); + } + int store_field(Field *from) + { // Be sure the value is stored + from->val_str(&value); + if (table->copy_blobs || + (!value.is_alloced() && from->is_varchar_and_in_write_set())) + value.copy(); + return store(value.ptr(), value.length(), from->charset()); + } + bool memcpy_field_possible(const Field *from) const + { + return Field_str::memcpy_field_possible(from) && + !table->copy_blobs; + } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + my_decimal *val_decimal(my_decimal *); + int cmp_max(const uchar *, const uchar *, uint max_length); + int cmp(const uchar *a,const uchar *b) + { return cmp_max(a, b, ~0U); } + int cmp(const uchar *a, uint32 a_length, const uchar *b, uint32 b_length); + int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0U); + int key_cmp(const uchar *,const uchar*); + int key_cmp(const uchar *str, uint length); + /* Never update the value of min_val for a blob field */ + bool update_min(Field *min_val, bool force_update) { return FALSE; } + /* Never update the value of max_val for a blob field */ + bool update_max(Field *max_val, bool force_update) { return FALSE; } + uint32 key_length() const { return 0; } + void sort_string(uchar *buff,uint length); + uint32 pack_length() const + { return (uint32) (packlength + portable_sizeof_char_ptr); } + + /** + Return the packed length without the pointer size added. + + This is used to determine the size of the actual data in the row + buffer. + + @returns The length of the raw data itself without the pointer. + */ + uint32 pack_length_no_ptr() const + { return (uint32) (packlength); } + uint row_pack_length() const { return pack_length_no_ptr(); } + uint32 sort_length() const; + uint32 value_length() { return get_length(); } + virtual uint32 max_data_length() const + { + return (uint32) (((ulonglong) 1 << (packlength*8)) -1); + } + int reset(void) { bzero(ptr, packlength+sizeof(uchar*)); return 0; } + void reset_fields() { bzero((uchar*) &value,sizeof(value)); bzero((uchar*) &read_value,sizeof(read_value)); } + uint32 get_field_buffer_size(void) { return value.alloced_length(); } + void store_length(uchar *i_ptr, uint i_packlength, uint32 i_number); + inline void store_length(uint32 number) + { + store_length(ptr, packlength, number); + } + inline uint32 get_length(uint row_offset= 0) const + { return get_length(ptr+row_offset, this->packlength); } + uint32 get_length(const uchar *ptr, uint packlength) const; + uint32 get_length(const uchar *ptr_arg) const + { return get_length(ptr_arg, this->packlength); } + inline uchar *get_ptr() const { return get_ptr(0); } + inline uchar *get_ptr(my_ptrdiff_t row_offset) const + { + uchar *s; + memcpy(&s, ptr + packlength + row_offset, sizeof(uchar*)); + return s; + } + inline void set_ptr(uchar *length, uchar *data) + { + memcpy(ptr,length,packlength); + memcpy(ptr+packlength, &data,sizeof(char*)); + } + void set_ptr_offset(my_ptrdiff_t ptr_diff, uint32 length, uchar *data) + { + uchar *ptr_ofs= ADD_TO_PTR(ptr,ptr_diff,uchar*); + store_length(ptr_ofs, packlength, length); + memcpy(ptr_ofs+packlength, &data, sizeof(char*)); + } + inline void set_ptr(uint32 length, uchar *data) + { + set_ptr_offset(0, length, data); + } + int copy_value(Field_blob *from); + uint get_key_image(uchar *buff,uint length, imagetype type); + void set_key_image(const uchar *buff,uint length); + Field *new_key_field(MEM_ROOT *root, TABLE *new_table, + uchar *new_ptr, uint32 length, + uchar *new_null_ptr, uint new_null_bit); + void sql_type(String &str) const; + inline bool copy() + { + uchar *tmp= get_ptr(); + if (value.copy((char*) tmp, get_length(), charset())) + { + Field_blob::reset(); + return 1; + } + tmp=(uchar*) value.ptr(); + memcpy(ptr+packlength, &tmp, sizeof(char*)); + return 0; + } + /* store value for the duration of the current read record */ + inline void swap_value_and_read_value() + { + read_value.swap(value); + } + inline void set_value(uchar *data) + { + /* Set value pointer. Lengths are not important */ + value.reset((char*) data, 1, 1, &my_charset_bin); + } + virtual uchar *pack(uchar *to, const uchar *from, uint max_length); + virtual const uchar *unpack(uchar *to, const uchar *from, + const uchar *from_end, uint param_data); + uint packed_col_length(const uchar *col_ptr, uint length); + uint max_packed_col_length(uint max_length); + void free() + { + value.free(); + read_value.free(); + } + inline void clear_temporary() + { + uchar *tmp= get_ptr(); + if (likely(value.ptr() == (char*) tmp)) + bzero((uchar*) &value, sizeof(value)); + else + { + /* + Currently read_value should never point to tmp, the following code + is mainly here to make things future proof. + */ + if (unlikely(read_value.ptr() == (char*) tmp)) + bzero((uchar*) &read_value, sizeof(read_value)); + } + } + uint size_of() const { return sizeof(*this); } + bool has_charset(void) const + { return charset() == &my_charset_bin ? FALSE : TRUE; } + uint32 max_display_length(); + uint32 char_length() const; + uint is_equal(Create_field *new_field); +private: + int do_save_field_metadata(uchar *first_byte); +}; + + +#ifdef HAVE_SPATIAL +class Field_geom :public Field_blob { +public: + enum geometry_type geom_type; + uint srid; + uint precision; + enum storage_type { GEOM_STORAGE_WKB= 0, GEOM_STORAGE_BINARY= 1}; + enum storage_type storage; + + Field_geom(uchar *ptr_arg, uchar *null_ptr_arg, uint null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + TABLE_SHARE *share, uint blob_pack_length, + enum geometry_type geom_type_arg, uint field_srid) + :Field_blob(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, + field_name_arg, share, blob_pack_length, &my_charset_bin) + { geom_type= geom_type_arg; srid= field_srid; } + Field_geom(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, + TABLE_SHARE *share, enum geometry_type geom_type_arg) + :Field_blob(len_arg, maybe_null_arg, field_name_arg, &my_charset_bin) + { geom_type= geom_type_arg; srid= 0; } + enum ha_base_keytype key_type() const { return HA_KEYTYPE_VARBINARY2; } + enum_field_types type() const { return MYSQL_TYPE_GEOMETRY; } + bool can_optimize_range(const Item_bool_func *cond, + const Item *item, + bool is_eq_func) const; + void sql_type(String &str) const; + uint is_equal(Create_field *new_field); + int store(const char *to, uint length, CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + int store_decimal(const my_decimal *); + uint size_of() const { return sizeof(*this); } + /** + Key length is provided only to support hash joins. (compared byte for byte) + Ex: SELECT .. FROM t1,t2 WHERE t1.field_geom1=t2.field_geom2. + + The comparison is not very relevant, as identical geometry might be + represented differently, but we need to support it either way. + */ + uint32 key_length() const { return packlength; } + + /** + Non-nullable GEOMETRY types cannot have defaults, + but the underlying blob must still be reset. + */ + int reset(void) { return Field_blob::reset() || !maybe_null(); } + + geometry_type get_geometry_type() { return geom_type; }; + static geometry_type geometry_type_merge(geometry_type, geometry_type); + uint get_srid() { return srid; } +}; + +uint gis_field_options_image(uchar *buff, List &create_fields); +uint gis_field_options_read(const uchar *buf, uint buf_len, + Field_geom::storage_type *st_type,uint *precision, uint *scale, uint *srid); + +#endif /*HAVE_SPATIAL*/ + + +class Field_enum :public Field_str { + static void do_field_enum(Copy_field *copy_field); +protected: + uint packlength; +public: + TYPELIB *typelib; + Field_enum(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + uint packlength_arg, + TYPELIB *typelib_arg, + CHARSET_INFO *charset_arg) + :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, charset_arg), + packlength(packlength_arg),typelib(typelib_arg) + { + flags|=ENUM_FLAG; + } + Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type); + enum_field_types type() const { return MYSQL_TYPE_STRING; } + enum Item_result cmp_type () const { return INT_RESULT; } + const Type_handler *cast_to_int_type_handler() const + { + return &type_handler_longlong; + } + enum ha_base_keytype key_type() const; + Copy_func *get_copy_func(const Field *from) const + { + if (eq_def(from)) + return get_identical_copy_func(); + if (real_type() == MYSQL_TYPE_ENUM && + from->real_type() == MYSQL_TYPE_ENUM) + return do_field_enum; + if (from->result_type() == STRING_RESULT) + return do_field_string; + return do_field_int; + } + int store_field(Field *from) + { + if (from->real_type() == MYSQL_TYPE_ENUM && from->val_int() == 0) + { + store_type(0); + return 0; + } + return from->save_in_field(this); + } + int save_in_field(Field *to) + { + if (to->result_type() != STRING_RESULT) + return to->store(val_int(), 0); + return save_in_field_str(to); + } + bool memcpy_field_possible(const Field *from) const { return false; } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return (uint32) packlength; } + void store_type(ulonglong value); + void sql_type(String &str) const; + uint size_of() const { return sizeof(*this); } + enum_field_types real_type() const { return MYSQL_TYPE_ENUM; } + uint pack_length_from_metadata(uint field_metadata) + { return (field_metadata & 0x00ff); } + uint row_pack_length() const { return pack_length(); } + virtual bool zero_pack() const { return 0; } + bool optimize_range(uint idx, uint part) { return 0; } + bool eq_def(const Field *field) const; + bool has_charset(void) const { return TRUE; } + /* enum and set are sorted as integers */ + CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; } + uint decimals() const { return 0; } + + virtual uchar *pack(uchar *to, const uchar *from, uint max_length); + virtual const uchar *unpack(uchar *to, const uchar *from, + const uchar *from_end, uint param_data); + + bool can_optimize_keypart_ref(const Item_bool_func *cond, + const Item *item) const; + bool can_optimize_group_min_max(const Item_bool_func *cond, + const Item *const_item) const + { + /* + Can't use GROUP_MIN_MAX optimization for ENUM and SET, + because the values are stored as numbers in index, + while MIN() and MAX() work as strings. + It would return the records with min and max enum numeric indexes. + "Bug#45300 MAX() and ENUM type" should be fixed first. + */ + return false; + } +private: + int do_save_field_metadata(uchar *first_byte); + uint is_equal(Create_field *new_field); +}; + + +class Field_set :public Field_enum { +public: + Field_set(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + uint32 packlength_arg, + TYPELIB *typelib_arg, CHARSET_INFO *charset_arg) + :Field_enum(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, + packlength_arg, + typelib_arg,charset_arg), + empty_set_string("", 0, charset_arg) + { + flags=(flags & ~ENUM_FLAG) | SET_FLAG; + } + int store_field(Field *from) { return from->save_in_field(this); } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr) { return Field_set::store((longlong) nr, FALSE); } + int store(longlong nr, bool unsigned_val); + + virtual bool zero_pack() const { return 1; } + String *val_str(String*,String *); + void sql_type(String &str) const; + uint size_of() const { return sizeof(*this); } + enum_field_types real_type() const { return MYSQL_TYPE_SET; } + bool has_charset(void) const { return TRUE; } +private: + const String empty_set_string; +}; + + +/* + Note: + To use Field_bit::cmp_binary() you need to copy the bits stored in + the beginning of the record (the NULL bytes) to each memory you + want to compare (where the arguments point). + + This is the reason: + - Field_bit::cmp_binary() is only implemented in the base class + (Field::cmp_binary()). + - Field::cmp_binary() currenly use pack_length() to calculate how + long the data is. + - pack_length() includes size of the bits stored in the NULL bytes + of the record. +*/ +class Field_bit :public Field { +public: + uchar *bit_ptr; // position in record where 'uneven' bits store + uchar bit_ofs; // offset to 'uneven' high bits + uint bit_len; // number of 'uneven' high bits + uint bytes_in_rec; + Field_bit(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, uchar *bit_ptr_arg, uchar bit_ofs_arg, + enum utype unireg_check_arg, const char *field_name_arg); + enum_field_types type() const { return MYSQL_TYPE_BIT; } + enum ha_base_keytype key_type() const { return HA_KEYTYPE_BIT; } + uint32 key_length() const { return (uint32) (field_length + 7) / 8; } + uint32 max_data_length() const { return (field_length + 7) / 8; } + uint32 max_display_length() { return field_length; } + uint size_of() const { return sizeof(*this); } + Item_result result_type () const { return INT_RESULT; } + int reset(void) { + bzero(ptr, bytes_in_rec); + if (bit_ptr && (bit_len > 0)) // reset odd bits among null bits + clr_rec_bits(bit_ptr, bit_ofs, bit_len); + return 0; + } + Copy_func *get_copy_func(const Field *from) const + { + return do_field_int; + } + int save_in_field(Field *to) { return to->store(val_int(), true); } + bool memcpy_field_possible(const Field *from) const { return false; } + int store(const char *to, uint length, CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + int store_decimal(const my_decimal *); + double val_real(void); + longlong val_int(void); + String *val_str(String*, String *); + virtual bool str_needs_quotes() { return TRUE; } + my_decimal *val_decimal(my_decimal *); + bool val_bool() { return val_int() != 0; } + int cmp(const uchar *a, const uchar *b) + { + DBUG_ASSERT(ptr == a || ptr == b); + if (ptr == a) + return Field_bit::key_cmp(b, bytes_in_rec + MY_TEST(bit_len)); + else + return Field_bit::key_cmp(a, bytes_in_rec + MY_TEST(bit_len)) * -1; + } + int cmp_binary_offset(uint row_offset) + { return cmp_offset(row_offset); } + int cmp_max(const uchar *a, const uchar *b, uint max_length); + int key_cmp(const uchar *a, const uchar *b) + { return cmp_binary((uchar *) a, (uchar *) b); } + int key_cmp(const uchar *str, uint length); + int cmp_offset(uint row_offset); + bool update_min(Field *min_val, bool force_update) + { + longlong val= val_int(); + bool update_fl= force_update || val < min_val->val_int(); + if (update_fl) + { + min_val->set_notnull(); + min_val->store(val, FALSE); + } + return update_fl; + } + bool update_max(Field *max_val, bool force_update) + { + longlong val= val_int(); + bool update_fl= force_update || val > max_val->val_int(); + if (update_fl) + { + max_val->set_notnull(); + max_val->store(val, FALSE); + } + return update_fl; + } + void store_field_value(uchar *val, uint len) + { + store(*((longlong *)val), TRUE); + } + double pos_in_interval(Field *min, Field *max) + { + return pos_in_interval_val_real(min, max); + } + void get_image(uchar *buff, uint length, CHARSET_INFO *cs) + { get_key_image(buff, length, itRAW); } + void set_image(const uchar *buff,uint length, CHARSET_INFO *cs) + { Field_bit::store((char *) buff, length, cs); } + uint get_key_image(uchar *buff, uint length, imagetype type); + void set_key_image(const uchar *buff, uint length) + { Field_bit::store((char*) buff, length, &my_charset_bin); } + void sort_string(uchar *buff, uint length) + { get_key_image(buff, length, itRAW); } + uint32 pack_length() const { return (uint32) (field_length + 7) / 8; } + uint32 pack_length_in_rec() const { return bytes_in_rec; } + uint pack_length_from_metadata(uint field_metadata); + uint row_pack_length() const + { return (bytes_in_rec + ((bit_len > 0) ? 1 : 0)); } + bool compatible_field_size(uint metadata, Relay_log_info *rli, + uint16 mflags, int *order_var); + void sql_type(String &str) const; + virtual uchar *pack(uchar *to, const uchar *from, uint max_length); + virtual const uchar *unpack(uchar *to, const uchar *from, + const uchar *from_end, uint param_data); + virtual void set_default(); + + Field *new_key_field(MEM_ROOT *root, TABLE *new_table, + uchar *new_ptr, uint32 length, + uchar *new_null_ptr, uint new_null_bit); + void set_bit_ptr(uchar *bit_ptr_arg, uchar bit_ofs_arg) + { + bit_ptr= bit_ptr_arg; + bit_ofs= bit_ofs_arg; + } + bool eq(Field *field) + { + return (Field::eq(field) && + bit_ptr == ((Field_bit *)field)->bit_ptr && + bit_ofs == ((Field_bit *)field)->bit_ofs); + } + uint is_equal(Create_field *new_field); + void move_field_offset(my_ptrdiff_t ptr_diff) + { + Field::move_field_offset(ptr_diff); + bit_ptr= ADD_TO_PTR(bit_ptr, ptr_diff, uchar*); + } + void hash(ulong *nr, ulong *nr2); + +private: + virtual size_t do_last_null_byte() const; + int do_save_field_metadata(uchar *first_byte); +}; + + +/** + BIT field represented as chars for non-MyISAM tables. + + @todo The inheritance relationship is backwards since Field_bit is + an extended version of Field_bit_as_char and not the other way + around. Hence, we should refactor it to fix the hierarchy order. + */ +class Field_bit_as_char: public Field_bit { +public: + Field_bit_as_char(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg); + enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } + uint size_of() const { return sizeof(*this); } + int store(const char *to, uint length, CHARSET_INFO *charset); + int store(double nr) { return Field_bit::store(nr); } + int store(longlong nr, bool unsigned_val) + { return Field_bit::store(nr, unsigned_val); } + void sql_type(String &str) const; +}; + + +extern const LEX_STRING null_lex_str; + + +Field *make_field(TABLE_SHARE *share, MEM_ROOT *mem_root, + uchar *ptr, uint32 field_length, + uchar *null_pos, uchar null_bit, + uint pack_flag, enum_field_types field_type, + CHARSET_INFO *cs, + Field::geometry_type geom_type, uint srid, + Field::utype unireg_check, + TYPELIB *interval, const char *field_name); + +/* + Create field class for CREATE TABLE +*/ +class Column_definition: public Sql_alloc +{ + /** + Create "interval" from "interval_list". + @param mem_root - memory root to create the TYPELIB + instance and its values on + @param reuse_interval_list_values - determines if TYPELIB can reuse strings + from interval_list, or should always + allocate a copy on mem_root, even if + character set conversion is not needed + @retval false on success + @retval true on error (bad values, or EOM) + */ + bool create_interval_from_interval_list(MEM_ROOT *mem_root, + bool reuse_interval_list_values); + + /* + Calculate TYPELIB (set or enum) max and total lengths + + @param cs charset+collation pair of the interval + @param max_length length of the longest item + @param tot_length sum of the item lengths + + After this method call: + - ENUM uses max_length + - SET uses tot_length. + */ + void calculate_interval_lengths(uint32 *max_length, uint32 *tot_length) + { + const char **pos; + uint *len; + *max_length= *tot_length= 0; + for (pos= interval->type_names, len= interval->type_lengths; + *pos ; pos++, len++) + { + size_t length= charset->cset->numchars(charset, *pos, *pos + *len); + *tot_length+= length; + set_if_bigger(*max_length, (uint32)length); + } + } +public: + enum enum_column_versioning + { + VERSIONING_NOT_SET, + WITH_VERSIONING, + WITHOUT_VERSIONING + }; + + const char *field_name; + LEX_STRING comment; // Comment for field + Item *on_update; // ON UPDATE NOW() + enum enum_field_types sql_type; + /* + At various stages in execution this can be length of field in bytes or + max number of characters. + */ + ulonglong length; + /* + The value of `length' as set by parser: is the number of characters + for most of the types, or of bytes for BLOBs or numeric types. + */ + uint32 char_length; + uint decimals, flags, pack_length, key_length; + Field::utype unireg_check; + TYPELIB *interval; // Which interval to use + List interval_list; + CHARSET_INFO *charset; + uint32 srid; + Field::geometry_type geom_type; + engine_option_value *option_list; + + uint pack_flag; + + /* + This is additinal data provided for any computed(virtual) field. + In particular it includes a pointer to the item by which this field + can be computed from other fields. + */ + Virtual_column_info + *vcol_info, // Virtual field + *default_value, // Default value + *check_constraint; // Check constraint + + enum_column_versioning versioning; + + Column_definition(): + comment(null_lex_str), + on_update(NULL), sql_type(MYSQL_TYPE_NULL), length(0), decimals(0), + flags(0), pack_length(0), key_length(0), unireg_check(Field::NONE), + interval(0), charset(&my_charset_bin), + srid(0), geom_type(Field::GEOM_GEOMETRY), + option_list(NULL), + vcol_info(0), default_value(0), check_constraint(0), + versioning(VERSIONING_NOT_SET) + { + interval_list.empty(); + } + + Column_definition(THD *thd, Field *field, Field *orig_field); + void set_attributes(const Lex_field_type_st &type, CHARSET_INFO *cs); + void create_length_to_internal_length(void); + + /** + Prepare a SET/ENUM field. + Create "interval" from "interval_list" if needed, and adjust "length". + @param mem_root - Memory root to allocate TYPELIB and + its values on + @param reuse_interval_list_values - determines if TYPELIB can reuse value + buffers from interval_list, or should + always allocate a copy on mem_root, + even if character set conversion + is not needed + */ + bool prepare_interval_field(MEM_ROOT *mem_root, + bool reuse_interval_list_values); + + void prepare_interval_field_calc_length() + { + uint32 field_length, dummy; + if (sql_type == MYSQL_TYPE_SET) + { + calculate_interval_lengths(&dummy, &field_length); + length= field_length + (interval->count - 1); + } + else /* MYSQL_TYPE_ENUM */ + { + calculate_interval_lengths(&field_length, &dummy); + length= field_length; + } + set_if_smaller(length, MAX_FIELD_WIDTH - 1); + } + + bool prepare_blob_field(THD *thd); + + bool sp_prepare_create_field(THD *thd, MEM_ROOT *mem_root); + + bool prepare_create_field(uint *blob_columns, ulonglong table_flags); + + bool check(THD *thd); + + bool stored_in_db() const { return !vcol_info || vcol_info->stored_in_db; } + + ha_storage_media field_storage_type() const + { + return (ha_storage_media) + ((flags >> FIELD_FLAGS_STORAGE_MEDIA) & 3); + } + + column_format_type column_format() const + { + return (column_format_type) + ((flags >> FIELD_FLAGS_COLUMN_FORMAT) & 3); + } + + bool has_default_function() const + { + return unireg_check != Field::NONE; + } + + Field *make_field(TABLE_SHARE *share, MEM_ROOT *mem_root, + uchar *ptr, uchar *null_pos, uchar null_bit, + const char *field_name_arg) const + { + return ::make_field(share, mem_root, ptr, + (uint32)length, null_pos, null_bit, + pack_flag, sql_type, charset, + geom_type, srid, unireg_check, interval, + field_name_arg); + } + Field *make_field(TABLE_SHARE *share, MEM_ROOT *mem_root, + const char *field_name_arg) + { + return make_field(share, mem_root, (uchar *) 0, (uchar *) "", 0, + field_name_arg); + } + /* Return true if default is an expression that must be saved explicitely */ + bool has_default_expression(); + + bool has_default_now_unireg_check() const + { + return unireg_check == Field::TIMESTAMP_DN_FIELD + || unireg_check == Field::TIMESTAMP_DNUN_FIELD; + } +}; + + +class Create_field :public Column_definition +{ +public: + const char *change; // If done with alter table + const char *after; // Put column after this one + Field *field; // For alter table + TYPELIB *save_interval; // Temporary copy for the above + // Used only for UCS2 intervals + + /** structure with parsed options (for comparing fields in ALTER TABLE) */ + ha_field_option_struct *option_struct; + uint offset; + uint8 interval_id; // For rea_create_table + bool create_if_not_exists; // Used in ALTER TABLE IF NOT EXISTS + + Create_field(): + Column_definition(), change(0), after(0), + field(0), option_struct(NULL), + create_if_not_exists(false) + { } + Create_field(THD *thd, Field *old_field, Field *orig_field): + Column_definition(thd, old_field, orig_field), + change(old_field->field_name), after(0), + field(old_field), option_struct(old_field->option_struct), + create_if_not_exists(false) + { } + /* Used to make a clone of this object for ALTER/CREATE TABLE */ + Create_field *clone(MEM_ROOT *mem_root) const; +}; + + +/* + A class for sending info to the client +*/ + +class Send_field :public Sql_alloc { + public: + const char *db_name; + const char *table_name,*org_table_name; + const char *col_name,*org_col_name; + ulong length; + uint flags, decimals; + enum_field_types type; + Send_field() {} +}; + + +/* + A class for quick copying data to fields +*/ + +class Copy_field :public Sql_alloc { +public: + uchar *from_ptr,*to_ptr; + uchar *from_null_ptr,*to_null_ptr; + bool *null_row; + uint from_bit,to_bit; + /** + Number of bytes in the fields pointed to by 'from_ptr' and + 'to_ptr'. Usually this is the number of bytes that are copied from + 'from_ptr' to 'to_ptr'. + + For variable-length fields (VARCHAR), the first byte(s) describe + the actual length of the text. For VARCHARs with length + < 256 there is 1 length byte + >= 256 there is 2 length bytes + Thus, if from_field is VARCHAR(10), from_length (and in most cases + to_length) is 11. For VARCHAR(1024), the length is 1026. @see + Field_varstring::length_bytes + + Note that for VARCHARs, do_copy() will be do_varstring*() which + only copies the length-bytes (1 or 2) + the actual length of the + text instead of from/to_length bytes. + */ + uint from_length,to_length; + Field *from_field,*to_field; + String tmp; // For items + + Copy_field() {} + ~Copy_field() {} + void set(Field *to,Field *from,bool save); // Field to field + void set(uchar *to,Field *from); // Field to string + void (*do_copy)(Copy_field *); + void (*do_copy2)(Copy_field *); // Used to handle null values +}; + + +uint pack_length_to_packflag(uint type); +enum_field_types get_blob_type_from_length(ulong length); +uint32 calc_pack_length(enum_field_types type,uint32 length); +int set_field_to_null(Field *field); +int set_field_to_null_with_conversions(Field *field, bool no_conversions); +int convert_null_to_field_value_or_error(Field *field); +bool check_expression(Virtual_column_info *vcol, const char *name, + enum_vcol_info_type type); + +/* + The following are for the interface with the .frm file +*/ + +#define FIELDFLAG_DECIMAL 1U +#define FIELDFLAG_BINARY 1U // Shares same flag +#define FIELDFLAG_NUMBER 2U +#define FIELDFLAG_ZEROFILL 4U +#define FIELDFLAG_PACK 120U // Bits used for packing +#define FIELDFLAG_INTERVAL 256U // mangled with decimals! +#define FIELDFLAG_BITFIELD 512U // mangled with decimals! +#define FIELDFLAG_BLOB 1024U // mangled with decimals! +#define FIELDFLAG_GEOM 2048U // mangled with decimals! + +#define FIELDFLAG_TREAT_BIT_AS_CHAR 4096U /* use Field_bit_as_char */ +#define FIELDFLAG_LONG_DECIMAL 8192U +#define FIELDFLAG_WITHOUT_SYSTEM_VERSIONING 8192U +#define FIELDFLAG_NO_DEFAULT 16384U /* sql */ +#define FIELDFLAG_MAYBE_NULL 32768U // sql +#define FIELDFLAG_HEX_ESCAPE 0x10000U +#define FIELDFLAG_PACK_SHIFT 3 +#define FIELDFLAG_DEC_SHIFT 8 +#define FIELDFLAG_MAX_DEC 63U + +#define MTYP_TYPENR(type) (type & 127U) /* Remove bits from type */ + +#define f_is_dec(x) ((x) & FIELDFLAG_DECIMAL) +#define f_is_num(x) ((x) & FIELDFLAG_NUMBER) +#define f_is_zerofill(x) ((x) & FIELDFLAG_ZEROFILL) +#define f_is_packed(x) ((x) & FIELDFLAG_PACK) +#define f_packtype(x) (((x) >> FIELDFLAG_PACK_SHIFT) & 15) +#define f_decimals(x) ((uint8) (((x) >> FIELDFLAG_DEC_SHIFT) & FIELDFLAG_MAX_DEC)) +#define f_is_alpha(x) (!f_is_num(x)) +#define f_is_binary(x) ((x) & FIELDFLAG_BINARY) // 4.0- compatibility +#define f_is_enum(x) (((x) & (FIELDFLAG_INTERVAL | FIELDFLAG_NUMBER)) == FIELDFLAG_INTERVAL) +#define f_is_bitfield(x) (((x) & (FIELDFLAG_BITFIELD | FIELDFLAG_NUMBER)) == FIELDFLAG_BITFIELD) +#define f_is_blob(x) (((x) & (FIELDFLAG_BLOB | FIELDFLAG_NUMBER)) == FIELDFLAG_BLOB) +#define f_is_geom(x) (((x) & (FIELDFLAG_GEOM | FIELDFLAG_NUMBER)) == FIELDFLAG_GEOM) +#define f_settype(x) (((uint) (x)) << FIELDFLAG_PACK_SHIFT) +#define f_maybe_null(x) ((x) & FIELDFLAG_MAYBE_NULL) +#define f_no_default(x) ((x) & FIELDFLAG_NO_DEFAULT) +#define f_bit_as_char(x) ((x) & FIELDFLAG_TREAT_BIT_AS_CHAR) +#define f_is_hex_escape(x) ((x) & FIELDFLAG_HEX_ESCAPE) +#define f_without_system_versioning(x) ((x) & FIELDFLAG_WITHOUT_SYSTEM_VERSIONING) +#define f_hidden(x) ((x) & FIELDFLAG_HIDDEN) + +#endif /* FIELD_INCLUDED */ diff --git a/sql/handler.cc b/sql/handler.cc index 0b079676fc9..d5dff46a22e 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6570,16 +6570,16 @@ static bool create_sys_trx_field(THD *thd, const char *field_name, memset(f, 0, sizeof(*f)); f->field_name= field_name; f->charset= system_charset_info; + f->flags= NOT_NULL_FLAG | HIDDEN_FLAG; if (integer_fields) { f->sql_type= MYSQL_TYPE_LONGLONG; - f->flags= UNSIGNED_FLAG | NOT_NULL_FLAG; + f->flags|= UNSIGNED_FLAG; f->length= MY_INT64_NUM_DECIMAL_DIGITS; } else { f->sql_type= MYSQL_TYPE_TIMESTAMP2; - f->flags= NOT_NULL_FLAG; f->length= 6; } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 1af45c12331..090133b72ed 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7568,6 +7568,14 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, if (!(item= field_iterator.create_item(thd))) DBUG_RETURN(TRUE); + if (item->type() == Item::FIELD_ITEM) + { + Item_field *f= static_cast(item); + DBUG_ASSERT(f->field); + if (f->field->flags & HIDDEN_FLAG) + continue; + } + /* cache the table for the Item_fields inserted by expanding stars */ if (item->type() == Item::FIELD_ITEM && tables->cacheable_table) ((Item_field *)item)->cached_table= tables; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index c4bc2028caf..a3e6565fa52 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2991,6 +2991,8 @@ bool Column_definition::prepare_create_field(uint *blob_columns, pack_flag|= FIELDFLAG_NO_DEFAULT; if (flags & WITHOUT_SYSTEM_VERSIONING_FLAG) pack_flag|= FIELDFLAG_WITHOUT_SYSTEM_VERSIONING; + if (flags & HIDDEN_FLAG) + pack_flag|= FIELDFLAG_HIDDEN; DBUG_RETURN(false); } diff --git a/sql/table.cc b/sql/table.cc index 3a75fbe8e48..a23589f530a 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2020,6 +2020,9 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, if (f_without_system_versioning(pack_flag)) reg_field->flags|= WITHOUT_SYSTEM_VERSIONING_FLAG; + if (f_hidden(pack_flag)) + reg_field->flags|= HIDDEN_FLAG; + if (reg_field->unireg_check == Field::NEXT_NUMBER) share->found_next_number_field= field_ptr; -- cgit v1.2.1 From 7d815be198e0c9a6ae47e45d91210d11d549cd7b Mon Sep 17 00:00:00 2001 From: Kosov Eugene Date: Wed, 26 Oct 2016 14:32:41 +0300 Subject: SQL: store versioning field flags in EXTRA2 --- include/mysql_com.h | 6 +++--- sql/field.h | 10 +++------- sql/handler.cc | 4 ++-- sql/sql_table.cc | 4 ---- sql/sql_update.cc | 2 +- sql/table.cc | 26 +++++++++++++++++++------- sql/unireg.cc | 33 +++++++++++++++++++++++++++++++++ sql/unireg.h | 6 ++++++ storage/innobase/handler/ha_innodb.cc | 4 ++-- 9 files changed, 69 insertions(+), 26 deletions(-) diff --git a/include/mysql_com.h b/include/mysql_com.h index d52bd8eaada..990a7160bd1 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -190,9 +190,9 @@ enum enum_indicator_type #define GENERATED_ROW_END_FLAG (1 << 28) /* autogenerated column declared with `generated always at row end` (see II.a SQL Standard).*/ -#define WITHOUT_SYSTEM_VERSIONING_FLAG (1 << 29) /* column that doesn't support - system versioning when table - itself supports it*/ +#define VERS_OPTIMIZED_UPDATE_FLAG (1 << 29) /* column that doesn't support + system versioning when table + itself supports it*/ #define HIDDEN_FLAG (1 << 31) /* hide from SELECT * */ #define REFRESH_GRANT (1ULL << 0) /* Refresh grant tables */ diff --git a/sql/field.h b/sql/field.h index e50595df11a..16e53c72b11 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1424,7 +1424,7 @@ public: bool is_versioning_disabled() { - return flags & WITHOUT_SYSTEM_VERSIONING_FLAG; + return flags & VERS_OPTIMIZED_UPDATE_FLAG; } /* Mark a field as auto-generated row start column. */ @@ -1444,13 +1444,13 @@ public: /* Disable a field versioning for a versioned table. */ void disable_versioning() { - flags |= WITHOUT_SYSTEM_VERSIONING_FLAG; + flags |= VERS_OPTIMIZED_UPDATE_FLAG; } /* Inherit a field versioning status from the table. */ void inherit_versioning() { - flags &= ~WITHOUT_SYSTEM_VERSIONING_FLAG; + flags &= ~VERS_OPTIMIZED_UPDATE_FLAG; } /* @@ -4281,8 +4281,6 @@ bool check_expression(Virtual_column_info *vcol, const char *name, #define FIELDFLAG_BITFIELD 512U // mangled with decimals! #define FIELDFLAG_BLOB 1024U // mangled with decimals! #define FIELDFLAG_GEOM 2048U // mangled with decimals! -// Do not show field in SELECT *. Hope GEOM field is never hidden. -#define FIELDFLAG_HIDDEN 2048U #define FIELDFLAG_TREAT_BIT_AS_CHAR 4096U /* use Field_bit_as_char */ #define FIELDFLAG_LONG_DECIMAL 8192U @@ -4313,7 +4311,5 @@ bool check_expression(Virtual_column_info *vcol, const char *name, #define f_no_default(x) ((x) & FIELDFLAG_NO_DEFAULT) #define f_bit_as_char(x) ((x) & FIELDFLAG_TREAT_BIT_AS_CHAR) #define f_is_hex_escape(x) ((x) & FIELDFLAG_HEX_ESCAPE) -#define f_without_system_versioning(x) ((x) & FIELDFLAG_WITHOUT_SYSTEM_VERSIONING) -#define f_hidden(x) ((x) & FIELDFLAG_HIDDEN) #endif /* FIELD_INCLUDED */ diff --git a/sql/handler.cc b/sql/handler.cc index d5dff46a22e..0badaa3fa24 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6616,10 +6616,10 @@ bool Vers_parse_info::add_versioning_info( if (f->versioning == Column_definition::VERSIONING_NOT_SET && without_system_versioning_by_default) - f->flags|= WITHOUT_SYSTEM_VERSIONING_FLAG; + f->flags|= VERS_OPTIMIZED_UPDATE_FLAG; else if (f->versioning == Column_definition::WITHOUT_VERSIONING) - f->flags|= WITHOUT_SYSTEM_VERSIONING_FLAG; + f->flags|= VERS_OPTIMIZED_UPDATE_FLAG; } // If user specified some of these he must specify the others too. Do nothing. diff --git a/sql/sql_table.cc b/sql/sql_table.cc index a3e6565fa52..b92b5f5c6c4 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2989,10 +2989,6 @@ bool Column_definition::prepare_create_field(uint *blob_columns, pack_flag|= FIELDFLAG_MAYBE_NULL; if (flags & NO_DEFAULT_VALUE_FLAG) pack_flag|= FIELDFLAG_NO_DEFAULT; - if (flags & WITHOUT_SYSTEM_VERSIONING_FLAG) - pack_flag|= FIELDFLAG_WITHOUT_SYSTEM_VERSIONING; - if (flags & HIDDEN_FLAG) - pack_flag|= FIELDFLAG_HIDDEN; DBUG_RETURN(false); } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 419ccc1bc94..c6e2736f4ce 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -161,7 +161,7 @@ static bool check_has_vers_fields(List &items) while (Item *item= it++) { if (Item_field *item_field= item->field_for_view_update()) - if (!(item_field->field->flags & WITHOUT_SYSTEM_VERSIONING_FLAG)) + if (!(item_field->field->flags & VERS_OPTIMIZED_UPDATE_FLAG)) return true; } return false; diff --git a/sql/table.cc b/sql/table.cc index a23589f530a..622ced5f60f 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1197,7 +1197,9 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, uint len; uint ext_key_parts= 0; plugin_ref se_plugin= 0; - const uchar *system_period = 0; + const uchar *system_period= 0; + const uchar *extra2_field_flags= 0; + size_t extra2_field_flags_length= 0; MEM_ROOT *old_root= thd->mem_root; Virtual_column_info **table_check_constraints; @@ -1297,6 +1299,12 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, goto err; system_period = extra2; break; + case EXTRA2_FIELD_FLAGS: + if (extra2_field_flags) + goto err; + extra2_field_flags= extra2; + extra2_field_flags_length= length; + break; default: /* abort frm parsing if it's an unknown but important extra2 value */ if (type >= EXTRA2_ENGINE_IMPORTANT) @@ -1615,6 +1623,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, disk_buff= frm_image + pos + FRM_FORMINFO_SIZE; share->fields= uint2korr(forminfo+258); + if (extra2_field_flags && extra2_field_flags_length != share->fields) + goto err; pos= uint2korr(forminfo+260); /* Length of all screens */ n_length= uint2korr(forminfo+268); interval_count= uint2korr(forminfo+270); @@ -1987,6 +1997,14 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, reg_field->field_index= i; reg_field->comment=comment; reg_field->vcol_info= vcol_info; + if (extra2_field_flags) + { + uchar flags= *extra2_field_flags++; + if (flags & VERS_OPTIMIZED_UPDATE) + reg_field->disable_versioning(); + if (flags & HIDDEN) + reg_field->flags|= HIDDEN_FLAG; + } if (field_type == MYSQL_TYPE_BIT && !f_bit_as_char(pack_flag)) { null_bits_are_used= 1; @@ -2017,12 +2035,6 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, if (f_no_default(pack_flag)) reg_field->flags|= NO_DEFAULT_VALUE_FLAG; - if (f_without_system_versioning(pack_flag)) - reg_field->flags|= WITHOUT_SYSTEM_VERSIONING_FLAG; - - if (f_hidden(pack_flag)) - reg_field->flags|= HIDDEN_FLAG; - if (reg_field->unireg_check == Field::NEXT_NUMBER) share->found_next_number_field= field_ptr; diff --git a/sql/unireg.cc b/sql/unireg.cc index 445d3441af7..9b4ee324aa3 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -120,6 +120,16 @@ vers_get_field(HA_CREATE_INFO *create_info, List &create_fields, b return 0; } +bool has_extra2_field_flags(List &create_fields) +{ + List_iterator it(create_fields); + while (Create_field *f= it++) + { + if (f->flags & (VERS_OPTIMIZED_UPDATE_FLAG | HIDDEN_FLAG)) + return true; + } + return false; +} /** Create a frm (table definition) file @@ -258,6 +268,13 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table, extra2_size+= 1 + 1 + 2 * sizeof(uint16); } + bool has_extra2_field_flags_= has_extra2_field_flags(create_fields); + if (has_extra2_field_flags_) + { + extra2_size+= + 1 + (create_fields.elements <= 255 ? 1 : 3) + create_fields.elements; + } + key_buff_length= uint4korr(fileinfo+47); frm.length= FRM_HEADER_SIZE; // fileinfo; @@ -323,6 +340,22 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table, pos+= sizeof(uint16); } + if (has_extra2_field_flags_) + { + *pos++= EXTRA2_FIELD_FLAGS; + pos= extra2_write_len(pos, create_fields.elements); + List_iterator it(create_fields); + while (Create_field *field= it++) + { + uchar flags= 0; + if (field->flags & VERS_OPTIMIZED_UPDATE_FLAG) + flags|= VERS_OPTIMIZED_UPDATE; + if (field->flags & HIDDEN_FLAG) + flags|= HIDDEN; + *pos++= flags; + } + } + int4store(pos, filepos); // end of the extra2 segment pos+= 4; diff --git a/sql/unireg.h b/sql/unireg.h index 475945311e4..a47114054e1 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -173,12 +173,18 @@ enum extra2_frm_value_type { EXTRA2_DEFAULT_PART_ENGINE=1, EXTRA2_GIS=2, EXTRA2_PERIOD_FOR_SYSTEM_TIME=4, + EXTRA2_FIELD_FLAGS=8, #define EXTRA2_ENGINE_IMPORTANT 128 EXTRA2_ENGINE_TABLEOPTS=128, }; +enum extra2_field_flags { + VERS_OPTIMIZED_UPDATE=1, + HIDDEN=2, +}; + int rea_create_table(THD *thd, LEX_CUSTRING *frm, const char *path, const char *db, const char *table_name, HA_CREATE_INFO *create_info, handler *file, diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 8eed719d748..8f97169adef 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -9203,7 +9203,7 @@ calc_row_difference( if (!prebuilt->upd_node->versioned && DICT_TF2_FLAG_IS_SET(prebuilt->table, DICT_TF2_VERSIONED) && - !(field->flags & WITHOUT_SYSTEM_VERSIONING_FLAG)) + !(field->flags & VERS_OPTIMIZED_UPDATE_FLAG)) { prebuilt->upd_node->versioned = true; } @@ -9315,7 +9315,7 @@ calc_row_difference( if (!prebuilt->upd_node->versioned && DICT_TF2_FLAG_IS_SET(prebuilt->table, DICT_TF2_VERSIONED) && - !(field->flags & WITHOUT_SYSTEM_VERSIONING_FLAG)) + !(field->flags & VERS_OPTIMIZED_UPDATE_FLAG)) { prebuilt->upd_node->versioned = true; } -- cgit v1.2.1 From 3c634602b9d692a9f02a35e48069bdecfb7fff86 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Sat, 29 Oct 2016 08:28:17 +0000 Subject: Parser: SYSTEM_TIME_SYM (fixes #67) --- sql/gen_lex_token.cc | 2 ++ sql/sql_lex.cc | 2 ++ sql/sql_yacc.yy | 11 ++++++----- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/sql/gen_lex_token.cc b/sql/gen_lex_token.cc index eefe9163819..264dde9b8a2 100644 --- a/sql/gen_lex_token.cc +++ b/sql/gen_lex_token.cc @@ -132,6 +132,8 @@ void compute_tokens() set_token(WITH_CUBE_SYM, "WITH CUBE"); set_token(WITH_ROLLUP_SYM, "WITH ROLLUP"); + set_token(WITH_SYSTEM_SYM, "WITH SYSTEM"); + set_token(FOR_SYSTEM_TIME_SYM, "FOR SYSTEM_TIME"); set_token(NOT2_SYM, "!"); set_token(OR2_SYM, "|"); set_token(PARAM_MARKER, "?"); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 242923de546..40ead5824fb 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1333,6 +1333,8 @@ int MYSQLlex(YYSTYPE *yylval, THD *thd) return WITH_CUBE_SYM; case ROLLUP_SYM: return WITH_ROLLUP_SYM; + case SYSTEM: + return WITH_SYSTEM_SYM; default: /* Save the token following 'WITH' diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 9d5640280e0..bbcb0630bd7 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -859,10 +859,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %parse-param { THD *thd } %lex-param { THD *thd } /* - Currently there are 106 shift/reduce conflicts. + Currently there are 103 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 106 +%expect 103 /* Comments for TOKENS. @@ -1093,7 +1093,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token FORCE_SYM %token FOREIGN /* SQL-2003-R */ %token FOR_SYM /* SQL-2003-R */ -%token FOR_SYSTEM_TIME_SYM /* internal */ +%token FOR_SYSTEM_TIME_SYM /* INTERNAL */ %token FORMAT_SYM %token FOUND_SYM /* SQL-2003-R */ %token FROM @@ -1575,6 +1575,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token WITHOUT /* SQL-2003-R */ %token WITH_CUBE_SYM /* INTERNAL */ %token WITH_ROLLUP_SYM /* INTERNAL */ +%token WITH_SYSTEM_SYM /* INTERNAL */ %token WORK_SYM /* SQL-2003-N */ %token WRAPPER_SYM %token WRITE_SYM /* SQL-2003-N */ @@ -5849,7 +5850,7 @@ create_table_option: Lex->create_info.used_fields|= HA_CREATE_USED_SEQUENCE; Lex->create_info.sequence= $3; } - | WITH SYSTEM VERSIONING + | WITH_SYSTEM_SYM VERSIONING { Vers_parse_info &info= Lex->vers_get_info(); info.declared_system_versioning= true; @@ -6666,7 +6667,7 @@ serial_attribute: new (thd->mem_root) engine_option_value($1, &Lex->last_field->option_list, &Lex->option_list_last); } - | WITH SYSTEM VERSIONING + | WITH_SYSTEM_SYM VERSIONING { Lex->last_field->versioning = Column_definition::WITH_VERSIONING; Lex->create_info.vers_info.has_versioned_fields= true; -- cgit v1.2.1 From 4cfc5dc81409b0f103ff72f9b4e95398b28d3f44 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Sun, 30 Oct 2016 05:59:42 +0000 Subject: Tests: disabled some tests --- mysql-test/disabled.def | 2 ++ mysql-test/suite/innodb/disabled.def | 2 ++ 2 files changed, 4 insertions(+) diff --git a/mysql-test/disabled.def b/mysql-test/disabled.def index e82ddcf92d1..3d95ac73095 100644 --- a/mysql-test/disabled.def +++ b/mysql-test/disabled.def @@ -22,3 +22,5 @@ innodb-wl5522-debug-zip : broken upstream innodb_bug12902967 : broken upstream file_contents : MDEV-6526 these files are not installed anymore max_statement_time : cannot possibly work, depends on timing +ssl_ca : natsys: fails in mariadb-10.2.2 +innodb_load_xa : natsys: requires external innodb plugin diff --git a/mysql-test/suite/innodb/disabled.def b/mysql-test/suite/innodb/disabled.def index 631f01a8e65..eaa7e2eb9d6 100644 --- a/mysql-test/suite/innodb/disabled.def +++ b/mysql-test/suite/innodb/disabled.def @@ -12,3 +12,5 @@ innodb_defragment_fill_factor : MDEV-10771 innodb_bug14147491 : MDEV-12253 ut_ad(buf_pool->n_pend_reads > 0) +innodb_uninstall : natsys: requires external innodb plugin + -- cgit v1.2.1 From 012e3e7e4e9929d7c40e9f98b277ad5456a4581c Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 1 Nov 2016 14:24:18 +0000 Subject: Comment: reminder for merging HIDDEN feature (closes #38) --- sql/sql_base.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 090133b72ed..6d288483818 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7568,6 +7568,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, if (!(item= field_iterator.create_item(thd))) DBUG_RETURN(TRUE); + /* This will be deprecated when HIDDEN feature will come to MariaDB. */ if (item->type() == Item::FIELD_ITEM) { Item_field *f= static_cast(item); -- cgit v1.2.1 From a22cbc453f6140ef0588328f3b4b72553286ad8e Mon Sep 17 00:00:00 2001 From: kevgs Date: Tue, 1 Nov 2016 19:51:44 +0300 Subject: IB: (0.4) foreign keys for versioned tables (#58) --- mysql-test/suite/versioning/t/foreign.test | 158 +++++++++++++++++++++++++++++ sql/share/errmsg-utf8.txt | 3 - sql/sql_table.cc | 14 --- storage/innobase/handler/ha_innodb.cc | 1 + storage/innobase/include/row0upd.h | 1 + storage/innobase/row/row0ins.cc | 93 ++++++++++++++++- storage/innobase/row/row0mysql.cc | 81 ++++++++------- storage/innobase/row/row0upd.cc | 2 + 8 files changed, 297 insertions(+), 56 deletions(-) create mode 100644 mysql-test/suite/versioning/t/foreign.test diff --git a/mysql-test/suite/versioning/t/foreign.test b/mysql-test/suite/versioning/t/foreign.test new file mode 100644 index 00000000000..3f1a14e58aa --- /dev/null +++ b/mysql-test/suite/versioning/t/foreign.test @@ -0,0 +1,158 @@ +-- source include/have_innodb.inc + +################# +# Test RESTRICT # +################# + +create table parent( + id int unique key +) engine innodb; + +create table child( + parent_id int, + foreign key(parent_id) references parent(id) + on delete restrict + on update restrict +) engine innodb with system versioning; + +insert into parent values(1); +insert into child values(1); + +-- error ER_ROW_IS_REFERENCED_2 +delete from parent where id = 1; +delete from child where parent_id = 1; +delete from parent where id = 1; + +insert into parent values(1); +insert into child values(1); +-- error ER_ROW_IS_REFERENCED_2 +update parent set id=id+1; +delete from child; +update parent set id=id+1; +select * from child for system_time from timestamp '1-1-1' to timestamp now(6); + +drop table child; +drop table parent; + +############################################## +# Test when clustered index is a foreign key # +############################################## + +create table parent( + id int(10) unsigned unique key +) engine innodb; + +create table child( + parent_id int(10) unsigned primary key, + foreign key(parent_id) references parent(id) +) engine innodb with system versioning; + +insert into parent values(1); +insert into child values(1); + +-- error ER_ROW_IS_REFERENCED_2 +delete from parent where id = 1; + +drop table child; +drop table parent; + +################ +# Test CASCADE # +################ + +create table parent( + id int unique key +) engine innodb; + +create table child( + parent_id int, + foreign key(parent_id) references parent(id) + on delete cascade + on update cascade +) engine innodb with system versioning; + +insert into parent values(1); +insert into child values(1); + +delete from parent where id = 1; +select * from child; +select * from child for system_time from timestamp '1-1-1' to timestamp now(6); + +insert into parent values(1); +insert into child values(1); +update parent set id=id+1; +select * from child; +select * from child for system_time from timestamp '1-1-1' to timestamp now(6); + +drop table child; +drop table parent; + +################# +# Test SET NULL # +################# + +create table parent( + id int unique key +) engine innodb; + +create table child( + parent_id int, + foreign key(parent_id) references parent(id) + on delete set null + on update set null +) engine innodb with system versioning; + +insert into parent values(1); +insert into child values(1); +delete from child; +insert into child values(1); + +delete from parent where id = 1; +select * from child; +select * from child for system_time from timestamp '1-1-1' to timestamp now(6); +delete from child; + +insert into parent values(1); +insert into child values(1); +update parent set id=id+1; +select * from child; +select * from child for system_time from timestamp '1-1-1' to timestamp now(6); + +drop table child; +drop table parent; + +########################### +# Parent table is foreign # +########################### + +create or replace table parent( + id int unique key +) engine innodb with system versioning; + +create or replace table child( + parent_id int, + foreign key(parent_id) references parent(id) +) engine innodb; + +insert into parent values(1); +insert into child values(1); +-- error ER_ROW_IS_REFERENCED_2 +delete from parent; +-- error ER_ROW_IS_REFERENCED_2 +update parent set id=2; + +delete from child; +delete from parent; + +-- error ER_NO_REFERENCED_ROW_2 +insert into child values(1); + +insert into parent values(1); +insert into child values(1); +-- error ER_ROW_IS_REFERENCED_2 +delete from parent; +-- error ER_ROW_IS_REFERENCED_2 +update parent set id=2; + +drop table child; +drop table parent; diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 167be4d10fc..e215395c3c2 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7520,9 +7520,6 @@ ER_SYS_START_AND_SYS_END_SAME ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER eng "Generated field for System Versioning cannot be set by user" -ER_FOREIGN_KEY_ON_SYSTEM_VERSIONED - eng "Foreign key clause is not yet supported in conjunction with system versioning" - ER_UPDATE_INFO_WITH_SYSTEM_VERSIONING eng "Rows matched: %ld Changed: %ld Inserted: %ld Warnings: %ld" diff --git a/sql/sql_table.cc b/sql/sql_table.cc index b92b5f5c6c4..ae697b61eb1 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4621,20 +4621,6 @@ handler *mysql_create_frm_image(THD *thd, if (create_info->versioned()) { - // FIXME: This test doesn't detect foreign key relationship on the side of - // parent table and System Time support will not work correctly for such - // table either. But this cannot be implemented without changes to innodb - // that are postponed for later time. - List_iterator_fast key_iterator(alter_info->key_list); - Key *key; - while ((key= key_iterator++)) - { - if (key->type == Key::FOREIGN_KEY) - { - my_error(ER_FOREIGN_KEY_ON_SYSTEM_VERSIONED, MYF(0)); - goto err; - } - } if(vers_prepare_keys(thd, create_info, alter_info, key_info, *key_count)) goto err; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 8f97169adef..18a8a9018ec 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -8960,6 +8960,7 @@ calc_row_difference( buf = (byte*) upd_buff; prebuilt->upd_node->versioned = false; + prebuilt->upd_node->vers_delete = false; for (i = 0; i < table->s->fields; i++) { field = table->field[i]; diff --git a/storage/innobase/include/row0upd.h b/storage/innobase/include/row0upd.h index d035e346c1e..1775eb2e179 100644 --- a/storage/innobase/include/row0upd.h +++ b/storage/innobase/include/row0upd.h @@ -583,6 +583,7 @@ struct upd_node_t{ UPD_NODE_NO_ORD_CHANGE and UPD_NODE_NO_SIZE_CHANGE, ORed */ bool versioned;/* update is versioned */ + bool vers_delete;/* versioned delete */ /*----------------------*/ /* Local storage for this graph node */ ulint state; /*!< node execution state */ diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 604656c8944..0a13be95d98 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -1569,6 +1569,79 @@ private: ulint& counter; }; +/*********************************************************************//** +Reads sys_trx_end field from clustered index row. +@return trx_id_t */ +static +trx_id_t +row_ins_get_sys_trx_end( +/*===================================*/ + const rec_t *rec, /*!< in: clustered row */ + ulint *offsets, /*!< in: offsets */ + dict_index_t *index) /*!< in: clustered index */ +{ + ut_a(dict_index_is_clust(index)); + + ulint len; + ulint nfield = dict_col_get_clust_pos( + &index->table->cols[index->table->vers_row_end], index); + const byte *field = rec_get_nth_field(rec, offsets, nfield, &len); + ut_a(len == 8); + return(mach_read_from_8(field)); +} + +/*********************************************************************//** +Performs search at clustered index and returns sys_trx_end if row was found. +@return DB_SUCCESS, DB_NO_REFERENCED_ROW */ +static +dberr_t +row_ins_search_sys_trx_end( +/*=======================*/ + dict_index_t *index, /*!< in: index of record */ + const rec_t *rec, /*!< in: record */ + trx_id_t *end_trx_id) /*!< out: end_trx_id */ +{ + rec_t *clust_rec; + bool found = false; + mem_heap_t *clust_heap = mem_heap_create(256); + ulint clust_offsets_[REC_OFFS_NORMAL_SIZE]; + ulint *clust_offsets = clust_offsets_; + rec_offs_init(clust_offsets_); + btr_pcur_t clust_pcur; + + dict_index_t *clust_index = dict_table_get_first_index(index->table); + + dtuple_t *ref = + row_build_row_ref(ROW_COPY_POINTERS, index, rec, clust_heap); + + mtr_t clust_mtr; + mtr_start(&clust_mtr); + btr_pcur_open_on_user_rec(clust_index, ref, PAGE_CUR_GE, + BTR_SEARCH_LEAF, &clust_pcur, &clust_mtr); + + if (!btr_pcur_is_on_user_rec(&clust_pcur)) + goto not_found; + + clust_rec = btr_pcur_get_rec(&clust_pcur); + clust_offsets = rec_get_offsets(clust_rec, clust_index, clust_offsets, + ULINT_UNDEFINED, &clust_heap); + if (0 != cmp_dtuple_rec(ref, clust_rec, clust_offsets)) + goto not_found; + + *end_trx_id = row_ins_get_sys_trx_end( + clust_rec, clust_offsets, clust_index); + found = true; +not_found: + mtr_commit(&clust_mtr); + btr_pcur_close(&clust_pcur); + mem_heap_free(clust_heap); + if (!found) { + fprintf(stderr, "InnoDB: foreign constraints: secondary index is out of sync\n"); + return(DB_NO_REFERENCED_ROW); + } + return(DB_SUCCESS); +} + /***************************************************************//** Checks if foreign key constraint fails for an index entry. Sets shared locks which lock either the success or the failure of the constraint. NOTE that @@ -1745,8 +1818,24 @@ row_ins_check_foreign_constraint( cmp = cmp_dtuple_rec(entry, rec, offsets); if (cmp == 0) { - if (rec_get_deleted_flag(rec, - rec_offs_comp(offsets))) { + if (DICT_TF2_FLAG_IS_SET(check_table, DICT_TF2_VERSIONED)) { + trx_id_t end_trx_id = 0; + + if (dict_index_is_clust(check_index)) { + end_trx_id = + row_ins_get_sys_trx_end( + rec, offsets, check_index); + } else if (row_ins_search_sys_trx_end( + check_index, rec, &end_trx_id) != + DB_SUCCESS) { + break; + } + + if (end_trx_id != TRX_ID_MAX) + continue; + } + + if (rec_get_deleted_flag(rec, rec_offs_comp(offsets))) { err = row_ins_set_shared_rec_lock( LOCK_ORDINARY, block, rec, check_index, offsets, thr); diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 7a4f2719ba5..60b221a4e4a 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -1957,43 +1957,6 @@ row_update_for_mysql_using_upd_graph( prebuilt->clust_pcur); } - if (DICT_TF2_FLAG_IS_SET(node->table, DICT_TF2_VERSIONED) && - (node->is_delete || node->versioned)) - { - /* System Versioning: modify update vector to set - sys_trx_start (or sys_trx_end in case of DELETE) - to current trx_id. */ - upd_t* uvect = node->update; - upd_field_t* ufield; - dict_col_t* col; - unsigned col_idx; - if (node->is_delete) { - ufield = &uvect->fields[0]; - uvect->n_fields = 0; - node->is_delete = false; - col_idx = table->vers_row_end; - } else { - ut_ad(uvect->n_fields < node->table->n_cols); - ufield = &uvect->fields[uvect->n_fields]; - col_idx = table->vers_row_start; - } - col = &table->cols[col_idx]; - UNIV_MEM_INVALID(ufield, sizeof *ufield); - ufield->field_no = dict_col_get_clust_pos(col, clust_index); - ufield->orig_len = 0; - ufield->exp = NULL; - - static const ulint fsize = sizeof(trx_id_t); - byte* buf = static_cast(mem_heap_alloc(node->heap, fsize)); - mach_write_to_8(buf, trx->id); - dfield_t* dfield = &ufield->new_val; - dfield_set_data(dfield, buf, fsize); - dict_col_copy_type(col, &dfield->type); - - uvect->n_fields++; - ut_ad(node->in_mysql_interface); // otherwise needs to recalculate node->cmpl_info - } - ut_a(node->pcur->rel_pos == BTR_PCUR_ON); /* MySQL seems to call rnd_pos before updating each row it @@ -2029,6 +1992,50 @@ row_update_for_mysql_using_upd_graph( thr->fk_cascade_depth = 0; run_again: + if (DICT_TF2_FLAG_IS_SET(node->table, DICT_TF2_VERSIONED) && + (node->is_delete || node->versioned)) + { + /* System Versioning: modify update vector to set + sys_trx_start (or sys_trx_end in case of DELETE) + to current trx_id. */ + dict_table_t* table = node->table; + dict_index_t* clust_index = dict_table_get_first_index(table); + upd_t* uvect = node->update; + upd_field_t* ufield; + dict_col_t* col; + unsigned col_idx; + if (node->is_delete) { + ufield = &uvect->fields[0]; + uvect->n_fields = 0; + node->is_delete = false; + node->vers_delete = true; + col_idx = table->vers_row_end; + } else { + ut_ad(uvect->n_fields < table->n_cols); + ufield = &uvect->fields[uvect->n_fields]; + col_idx = table->vers_row_start; + } + col = &table->cols[col_idx]; + UNIV_MEM_INVALID(ufield, sizeof *ufield); + { + ulint field_no = dict_col_get_clust_pos(col, clust_index); + ut_ad(field_no != ULINT_UNDEFINED); + ufield->field_no = field_no; + } + ufield->orig_len = 0; + ufield->exp = NULL; + + static const ulint fsize = sizeof(trx_id_t); + byte* buf = static_cast(mem_heap_alloc(node->update->heap, fsize)); + mach_write_to_8(buf, trx->id); + dfield_t* dfield = &ufield->new_val; + dfield_set_data(dfield, buf, fsize); + dict_col_copy_type(col, &dfield->type); + + uvect->n_fields++; + ut_ad(node->in_mysql_interface); // otherwise needs to recalculate node->cmpl_info + } + if (thr->fk_cascade_depth == 1 && trx->dict_operation_lock_mode == 0) { got_s_lock = true; row_mysql_freeze_data_dictionary(trx); diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index cc86a8c419b..513a2a15d6c 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -269,6 +269,7 @@ row_upd_check_references_constraints( if (foreign->referenced_index == index && (node->is_delete + || node->vers_delete || row_upd_changes_first_fields_binary( entry, index, node->update, foreign->n_fields))) { @@ -381,6 +382,7 @@ wsrep_row_upd_check_foreign_constraints( if (foreign->foreign_index == index && (node->is_delete + || node->vers_delete || row_upd_changes_first_fields_binary( entry, index, node->update, foreign->n_fields))) { -- cgit v1.2.1 From 6d89a4a49b14b64c99083c2b8af32e735ff285fc Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Fri, 14 Oct 2016 13:25:28 +0000 Subject: Parser, SQL: (0.4) TRANSACTION support in queries Syntax extension: TIMESTAMP/TRANSACTION keyword can be used before FROM ... TO, BETWEEN ... AND. Example: SELECT * FROM t1 FOR SYSTEM_TIME TIMESTAMP FROM '1-1-1' TO NOW(); Closes #27 --- sql/share/errmsg-utf8.txt | 6 +++++ sql/sql_lex.cc | 4 +-- sql/sql_lex.h | 2 +- sql/sql_select.cc | 36 +++++++++++++++----------- sql/sql_yacc.yy | 64 ++++++++++++++++++++++++++++++++++++++++------- sql/table.h | 20 +++++++++++---- 6 files changed, 101 insertions(+), 31 deletions(-) diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index e215395c3c2..5e3a725a895 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7537,3 +7537,9 @@ ER_SYS_END_FIELD_MUST_BE_BIGINT ER_NO_VERSIONED_FIELDS_IN_VERSIONED_TABLE eng "Every field specified unversioned in versioned table" + +ER_VERS_TRX_ID_UNSUPPORTED + eng "Engine does not support versioned TRX_ID" + +ER_VERS_RANGE_UNITS_MISMATCH + eng "Range units mismatch" diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 40ead5824fb..3375324b027 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -33,9 +33,9 @@ #include "sql_signal.h" -void LEX::parse_error() +void LEX::parse_error(uint err_number) { - thd->parse_error(); + thd->parse_error(err_number); } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 826ebd03063..c0e28ab8fd2 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -2649,7 +2649,6 @@ struct LEX: public Query_tables_list private: Query_arena_memroot *arena_for_set_stmt; MEM_ROOT *mem_root_for_set_stmt; - void parse_error(); bool sp_block_finalize(THD *thd, const Lex_spblock_st spblock, class sp_label **splabel); bool sp_change_context(THD *thd, const sp_pcontext *ctx, bool exclusive); @@ -2663,6 +2662,7 @@ private: bool sp_for_loop_increment(THD *thd, const Lex_for_loop_st &loop); public: + void parse_error(uint err_number= ER_SYNTAX_ERROR); inline bool is_arena_for_set_stmt() {return arena_for_set_stmt != 0;} bool set_arena_for_set_stmt(Query_arena *backup); void reset_arena_for_set_stmt(Query_arena *backup); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 4e7ca4663b1..81ff9b7246a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -668,7 +668,7 @@ setup_without_group(THD *thd, Ref_ptr_array ref_pointer_array, } static int -setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LEX *select_lex) +setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LEX *slex) { DBUG_ENTER("setup_for_system_time"); @@ -698,11 +698,11 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LE because they must outlive execution phase for multiple executions. */ arena= thd->activate_stmt_arena_if_needed(&backup); - if (select_lex->saved_where) + if (slex->saved_where) { DBUG_ASSERT(thd->stmt_arena->is_sp_execute()); /* 2. this copy_andor_structure() is also required by the same reason */ - *where_expr= select_lex->saved_where->copy_andor_structure(thd); + *where_expr= slex->saved_where->copy_andor_structure(thd); } else if (thd->stmt_arena->is_sp_execute()) { @@ -711,7 +711,7 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LE else if (*where_expr) // SP executed first time (STMT_INITIALIZED_FOR_SP) /* 1. copy_andor_structure() is required since this andor tree is modified later (and on shorter arena) */ - select_lex->saved_where= (*where_expr)->copy_andor_structure(thd); + slex->saved_where= (*where_expr)->copy_andor_structure(thd); } /* We have to save also non-versioned on_expr since we may have @@ -754,15 +754,23 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LE Field *fstart= table->table->vers_start_field(); Field *fend= table->table->vers_end_field(); - DBUG_ASSERT(select_lex->parent_lex); - Name_resolution_context *context= select_lex->parent_lex->current_context(); + DBUG_ASSERT(slex->parent_lex); + Name_resolution_context *context= slex->parent_lex->current_context(); DBUG_ASSERT(context); Item *row_start= new (thd->mem_root) Item_field(thd, context, fstart); Item *row_end= new (thd->mem_root) Item_field(thd, context, fend); Item *row_end2= row_end; - if (!table->table->versioned_by_sql()) + if (table->table->versioned_by_sql()) + { + if (slex->vers_conditions.unit == UNIT_TRX_ID) + { + my_error(ER_VERS_TRX_ID_UNSUPPORTED, MYF(0), table->table_name); + DBUG_RETURN(-1); + } + } + else if (slex->vers_conditions.unit == UNIT_TIMESTAMP) { DBUG_ASSERT(table->table->s && table->table->s->db_plugin); row_start= new (thd->mem_root) Item_func_vtq_ts( @@ -778,7 +786,7 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LE } Item *cond1= 0, *cond2= 0, *curr= 0; - switch (select_lex->vers_conditions.type) + switch (slex->vers_conditions.type) { case FOR_SYSTEM_TIME_UNSPECIFIED: if (table->table->versioned_by_sql()) @@ -796,21 +804,21 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LE break; case FOR_SYSTEM_TIME_AS_OF: cond1= new (thd->mem_root) Item_func_le(thd, row_start, - select_lex->vers_conditions.start); + slex->vers_conditions.start); cond2= new (thd->mem_root) Item_func_gt(thd, row_end, - select_lex->vers_conditions.start); + slex->vers_conditions.start); break; case FOR_SYSTEM_TIME_FROM_TO: cond1= new (thd->mem_root) Item_func_lt(thd, row_start, - select_lex->vers_conditions.end); + slex->vers_conditions.end); cond2= new (thd->mem_root) Item_func_ge(thd, row_end, - select_lex->vers_conditions.start); + slex->vers_conditions.start); break; case FOR_SYSTEM_TIME_BETWEEN: cond1= new (thd->mem_root) Item_func_le(thd, row_start, - select_lex->vers_conditions.end); + slex->vers_conditions.end); cond2= new (thd->mem_root) Item_func_ge(thd, row_end, - select_lex->vers_conditions.start); + slex->vers_conditions.start); break; default: DBUG_ASSERT(0); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index bbcb0630bd7..0f810d72f66 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -849,6 +849,7 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr) enum Window_frame::Frame_exclusion frame_exclusion; enum trigger_order_type trigger_action_order_type; DDL_options_st object_ddl_options; + enum vers_range_unit_t vers_range_unit; } %{ @@ -1968,6 +1969,8 @@ END_OF_INPUT %type opt_with_column_list +%type trans_or_timestamp + %% @@ -8673,14 +8676,25 @@ select_options: } ; +trans_or_timestamp: + TRANSACTION_SYM + { + $$ = UNIT_TRX_ID; + } + | TIMESTAMP + { + $$ = UNIT_TIMESTAMP; + } + ; + opt_for_system_time_clause: /* empty */ {} | FOR_SYSTEM_TIME_SYM AS OF_SYM - TIMESTAMP simple_expr + trans_or_timestamp simple_expr { - Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_AS_OF, $5); + Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_AS_OF, $4, $5); } | FOR_SYSTEM_TIME_SYM AS OF_SYM @@ -8689,23 +8703,55 @@ opt_for_system_time_clause: Item *item= new (thd->mem_root) Item_func_now_local(thd, 6); if (item == NULL) MYSQL_YYABORT; - Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_AS_OF, item); + Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_AS_OF, UNIT_TIMESTAMP, item); } | FOR_SYSTEM_TIME_SYM FROM - TIMESTAMP simple_expr + trans_or_timestamp + simple_expr TO_SYM - TIMESTAMP simple_expr + trans_or_timestamp + simple_expr { - Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_FROM_TO, $4, $7); + if ($3 != $6) + { + Lex->parse_error(ER_VERS_RANGE_UNITS_MISMATCH); + MYSQL_YYABORT; + } + Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_FROM_TO, $3, $4, $7); + } + | FOR_SYSTEM_TIME_SYM + trans_or_timestamp + FROM + simple_expr + TO_SYM + simple_expr + { + Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_FROM_TO, $2, $4, $6); + } + | FOR_SYSTEM_TIME_SYM + BETWEEN_SYM + trans_or_timestamp + simple_expr + AND_SYM + trans_or_timestamp + simple_expr + { + if ($3 != $6) + { + Lex->parse_error(ER_VERS_RANGE_UNITS_MISMATCH); + MYSQL_YYABORT; + } + Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_BETWEEN, $3, $4, $7); } | FOR_SYSTEM_TIME_SYM + trans_or_timestamp BETWEEN_SYM - TIMESTAMP simple_expr + simple_expr AND_SYM - TIMESTAMP simple_expr + simple_expr { - Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_BETWEEN, $4, $7); + Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_BETWEEN, $2, $4, $6); } ; diff --git a/sql/table.h b/sql/table.h index e2c055b14d5..df0300d498c 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1812,7 +1812,7 @@ class Item_in_subselect; 4) jtbm semi-join (jtbm_subselect != NULL) */ -enum for_system_time_type +enum vers_range_type_t { FOR_SYSTEM_TIME_UNSPECIFIED = 0, FOR_SYSTEM_TIME_AS_OF, @@ -1820,24 +1820,34 @@ enum for_system_time_type FOR_SYSTEM_TIME_BETWEEN }; +enum vers_range_unit_t +{ + UNIT_TIMESTAMP = 0, + UNIT_TRX_ID +}; + /** System versioning support. */ struct vers_select_conds_t { - enum for_system_time_type type; + vers_range_type_t type; + vers_range_unit_t unit; Item *start, *end; void empty() { type= FOR_SYSTEM_TIME_UNSPECIFIED; + unit= UNIT_TIMESTAMP; start= end= NULL; } void init( - const enum for_system_time_type t, - Item * const s, - Item * const e= NULL) + vers_range_type_t t, + vers_range_unit_t u, + Item * s, + Item * e= NULL) { type= t; + unit= u; start= s; end= e; } -- cgit v1.2.1 From d65bc8290987162c06ee3b6d3d74cad6868a665e Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 31 Oct 2016 12:44:58 +0000 Subject: Tests: (0.4) TRANSACTION support in queries (#27) --- mysql-test/suite/versioning/r/select.result | 140 +++++++++++++++++++++++++--- mysql-test/suite/versioning/t/select.test | 28 +++++- 2 files changed, 152 insertions(+), 16 deletions(-) diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index 94dcb243e65..da8cb25340e 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -42,15 +42,30 @@ insert into t1 (x, y) values (8, 108), (9, 109); set @t0= now(6); +if engine = 'innodb' then +select sys_start from t1 limit 1 into @x0; +end if; delete from t1 where x = 3; delete from t1 where x > 7; insert into t1(x, y) values(3, 33); -set @str= concat('select ', fields, ' from t1 where x = 3 and y = 33 into @t1'); -prepare stmt from @str; execute stmt; drop prepare stmt; +select sys_start from t1 where x = 3 and y = 33 into @t1; +if engine = 'innodb' then +set @x1= @t1; +select commit_ts(@x1) into @t1; +end if; select x, y from t1; -select x as AS_OF_x, y from t1 for system_time as of timestamp @t0; -select x as FROM_TO_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; -select x as BETWEEN_AND_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; +select x as ASOF_x, y from t1 for system_time as of timestamp @t0; +select x as FROMTO_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; +select x as BETWAND_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; +select x as FROMTO_ext_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; +select x as BETWAND_ext_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; +if engine = 'innodb' then +select x as ASOF2_x, y from t1 for system_time as of transaction @x0; +select x as FROMTO2_x, y from t1 for system_time from transaction 0 to transaction @x1; +select x as BETWAND2_x, y from t1 for system_time between transaction 0 and transaction @x1; +select x as FROMTO2_ext_x, y from t1 for system_time transaction from 0 to @x1; +select x as BETWAND2_ext_x, y from t1 for system_time transaction between 0 and @x1; +end if; drop table t1; end~~ create or replace procedure test_02( @@ -97,7 +112,7 @@ x y 6 106 7 107 3 33 -AS_OF_x y +ASOF_x y 0 100 1 101 2 102 @@ -108,7 +123,7 @@ AS_OF_x y 7 107 8 108 9 109 -FROM_TO_x y +FROMTO_x y 0 100 1 101 2 102 @@ -119,7 +134,30 @@ FROM_TO_x y 7 107 8 108 9 109 -BETWEEN_AND_x y +BETWAND_x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +3 33 +FROMTO_ext_x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +BETWAND_ext_x y 0 100 1 101 2 102 @@ -141,7 +179,52 @@ x y 6 106 7 107 3 33 -AS_OF_x y +ASOF_x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +FROMTO_x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +BETWAND_x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +3 33 +FROMTO_ext_x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +BETWAND_ext_x y 0 100 1 101 2 102 @@ -152,7 +235,42 @@ AS_OF_x y 7 107 8 108 9 109 -FROM_TO_x y +3 33 +ASOF2_x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +FROMTO2_x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +BETWAND2_x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +3 33 +FROMTO2_ext_x y 0 100 1 101 2 102 @@ -163,7 +281,7 @@ FROM_TO_x y 7 107 8 108 9 109 -BETWEEN_AND_x y +BETWAND2_ext_x y 0 100 1 101 2 102 diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index 0aa4f561882..6c586ccd868 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -28,16 +28,34 @@ begin (8, 108), (9, 109); set @t0= now(6); + if engine = 'innodb' then + select sys_start from t1 limit 1 into @x0; + end if; + delete from t1 where x = 3; delete from t1 where x > 7; insert into t1(x, y) values(3, 33); - set @str= concat('select ', fields, ' from t1 where x = 3 and y = 33 into @t1'); - prepare stmt from @str; execute stmt; drop prepare stmt; + select sys_start from t1 where x = 3 and y = 33 into @t1; + if engine = 'innodb' then + set @x1= @t1; + select commit_ts(@x1) into @t1; + end if; + select x, y from t1; - select x as AS_OF_x, y from t1 for system_time as of timestamp @t0; - select x as FROM_TO_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; - select x as BETWEEN_AND_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; + select x as ASOF_x, y from t1 for system_time as of timestamp @t0; + select x as FROMTO_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; + select x as BETWAND_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; + select x as FROMTO_ext_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; + select x as BETWAND_ext_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; + + if engine = 'innodb' then + select x as ASOF2_x, y from t1 for system_time as of transaction @x0; + select x as FROMTO2_x, y from t1 for system_time from transaction 0 to transaction @x1; + select x as BETWAND2_x, y from t1 for system_time between transaction 0 and transaction @x1; + select x as FROMTO2_ext_x, y from t1 for system_time transaction from 0 to @x1; + select x as BETWAND2_ext_x, y from t1 for system_time transaction between 0 and @x1; + end if; drop table t1; end~~ -- cgit v1.2.1 From 19641ce89f285c5569fa19e07ac53cb3a40443ca Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Fri, 4 Nov 2016 22:30:56 +0000 Subject: IB: production compilation fix --- storage/innobase/btr/btr0pcur.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/innobase/btr/btr0pcur.cc b/storage/innobase/btr/btr0pcur.cc index 9160265aae9..bb636e4f5df 100644 --- a/storage/innobase/btr/btr0pcur.cc +++ b/storage/innobase/btr/btr0pcur.cc @@ -509,7 +509,7 @@ btr_pcur_move_to_prev_page( page_cur_set_after_last(prev_block, btr_pcur_get_page_cur(cursor)); - page_check_dir(prev_page); + ut_d(page_check_dir(prev_page)); } /*********************************************************//** -- cgit v1.2.1 From 0581c018b79230b7ce5a4d9e3af928b6152577f1 Mon Sep 17 00:00:00 2001 From: Kosov Eugene Date: Mon, 7 Nov 2016 22:01:29 +0300 Subject: SQL: NULL instead of optimized fields in versioned queries --- .../suite/versioning/r/optimized_fields.result | 68 ++++++++++++++++++++++ .../suite/versioning/t/optimized_fields.test | 22 +++++++ sql/field.cc | 2 +- sql/field.h | 4 ++ sql/item.cc | 17 ++++++ sql/share/errmsg-utf8.txt | 3 + 6 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/versioning/r/optimized_fields.result create mode 100644 mysql-test/suite/versioning/t/optimized_fields.test diff --git a/mysql-test/suite/versioning/r/optimized_fields.result b/mysql-test/suite/versioning/r/optimized_fields.result new file mode 100644 index 00000000000..2e266430967 --- /dev/null +++ b/mysql-test/suite/versioning/r/optimized_fields.result @@ -0,0 +1,68 @@ +create table t( +a int, +b int without system versioning +) with system versioning; +insert into t values(1, 2); +insert into t values(3, 4); +select * from t; +a b +1 2 +3 4 +select a from t for system_time as of timestamp now(6); +a +1 +3 +select a, b, b+0 from t for system_time as of timestamp now(6); +a b b+0 +1 NULL NULL +3 NULL NULL +Warnings: +Warning 4050 Attempt to read unversioned field 'b' in historical query +select * from t for system_time as of timestamp now(6); +a b +1 NULL +3 NULL +Warnings: +Warning 4050 Attempt to read unversioned field 'b' in historical query +select count(*) from t group by b for system_time as of timestamp now(6); +count(*) +2 +Warnings: +Warning 4050 Attempt to read unversioned field 'b' in historical query +select * from t for system_time as of timestamp now(6) order by b asc; +a b +1 NULL +3 NULL +Warnings: +Warning 4050 Attempt to read unversioned field 'b' in historical query +select * from t for system_time as of timestamp now(6) order by b desc; +a b +1 NULL +3 NULL +Warnings: +Warning 4050 Attempt to read unversioned field 'b' in historical query +select * from t group by a having a=2 for system_time as of timestamp now(6); +a b +Warnings: +Warning 4050 Attempt to read unversioned field 'b' in historical query +select * from t group by b having b=2 for system_time as of timestamp now(6); +a b +Warnings: +Warning 4050 Attempt to read unversioned field 'b' in historical query +select a from t where b=2 for system_time as of timestamp now(6); +a +Warnings: +Warning 4050 Attempt to read unversioned field 'b' in historical query +select a from t where b=NULL for system_time as of timestamp now(6); +a +Warnings: +Warning 4050 Attempt to read unversioned field 'b' in historical query +select count(*), b from t group by b having b=NULL for system_time as of timestamp now(6); +count(*) b +Warnings: +Warning 4050 Attempt to read unversioned field 'b' in historical query +select a, b from t; +a b +1 2 +3 4 +drop table t; diff --git a/mysql-test/suite/versioning/t/optimized_fields.test b/mysql-test/suite/versioning/t/optimized_fields.test new file mode 100644 index 00000000000..62f245dc28d --- /dev/null +++ b/mysql-test/suite/versioning/t/optimized_fields.test @@ -0,0 +1,22 @@ +create table t( + a int, + b int without system versioning +) with system versioning; + +insert into t values(1, 2); +insert into t values(3, 4); +select * from t; +select a from t for system_time as of timestamp now(6); +select a, b, b+0 from t for system_time as of timestamp now(6); +select * from t for system_time as of timestamp now(6); +select count(*) from t group by b for system_time as of timestamp now(6); +select * from t for system_time as of timestamp now(6) order by b asc; +select * from t for system_time as of timestamp now(6) order by b desc; +select * from t group by a having a=2 for system_time as of timestamp now(6); +select * from t group by b having b=2 for system_time as of timestamp now(6); +select a from t where b=2 for system_time as of timestamp now(6); +select a from t where b=NULL for system_time as of timestamp now(6); +select count(*), b from t group by b having b=NULL for system_time as of timestamp now(6); +select a, b from t; + +drop table t; diff --git a/sql/field.cc b/sql/field.cc index c22ae9e2df3..a7108924f57 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1631,7 +1631,7 @@ Field::Field(uchar *ptr_arg,uint32 length_arg,uchar *null_ptr_arg, :ptr(ptr_arg), null_ptr(null_ptr_arg), table(0), orig_table(0), table_name(0), field_name(field_name_arg), option_list(0), option_struct(0), key_start(0), part_of_key(0), - part_of_key_not_clustered(0), part_of_sortkey(0), + part_of_key_not_clustered(0), force_null(false), part_of_sortkey(0), unireg_check(unireg_check_arg), field_length(length_arg), null_bit(null_bit_arg), is_created_from_null_item(FALSE), read_stats(NULL), collected_stats(0), vcol_info(0), check_constraint(0), diff --git a/sql/field.h b/sql/field.h index 16e53c72b11..f3c29c29cac 100644 --- a/sql/field.h +++ b/sql/field.h @@ -707,6 +707,8 @@ public: /* Field is part of the following keys */ key_map key_start, part_of_key, part_of_key_not_clustered; + bool force_null; + /* Bitmap of indexes that have records ordered by col1, ... this_field, ... @@ -1089,6 +1091,8 @@ public: virtual uint size_of() const =0; // For new field inline bool is_null(my_ptrdiff_t row_offset= 0) const { + if (force_null) + return true; /* The table may have been marked as containing only NULL values for all fields if it is a NULL-complemented row of an OUTER JOIN diff --git a/sql/item.cc b/sql/item.cc index a76152c14e2..ec4ed9ab07f 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2759,6 +2759,21 @@ void Item_field::set_field(Field *field_par) fixed= 1; if (field->table->s->tmp_table == SYSTEM_TMP_TABLE) any_privileges= 0; + + if (field->is_versioning_disabled() && context && context->select_lex && + context->select_lex->vers_conditions.type != + FOR_SYSTEM_TIME_UNSPECIFIED && + !field->force_null) + { + DBUG_ASSERT(context->select_lex->parent_lex && + context->select_lex->parent_lex->thd); + field->force_null= true; + THD *thd= context->select_lex->parent_lex->thd; + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + ER_NON_VERSIONED_FIELD_IN_VERSIONED_QUERY, + ER_THD(thd, ER_NON_VERSIONED_FIELD_IN_VERSIONED_QUERY), + field_name); + } } @@ -5907,6 +5922,8 @@ void Item_field::cleanup() it will be linked correctly next time by name of field and table alias. I.e. we can drop 'field'. */ + if (field) + field->force_null= false; field= 0; item_equal= NULL; null_value= FALSE; diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 5e3a725a895..e39677765a2 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7543,3 +7543,6 @@ ER_VERS_TRX_ID_UNSUPPORTED ER_VERS_RANGE_UNITS_MISMATCH eng "Range units mismatch" + +ER_NON_VERSIONED_FIELD_IN_VERSIONED_QUERY + eng "Attempt to read unversioned field '%s' in historical query" -- cgit v1.2.1 From 20b2719f4582a7ab93dfafb3d1a9874e64e74447 Mon Sep 17 00:00:00 2001 From: Kosov Eugene Date: Tue, 8 Nov 2016 15:36:20 +0300 Subject: Misc: foreign check code cleanups --- storage/innobase/row/row0ins.cc | 42 ++++++++++++++++------------------------- 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 0a13be95d98..ef30a434bf6 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -1601,42 +1601,32 @@ row_ins_search_sys_trx_end( const rec_t *rec, /*!< in: record */ trx_id_t *end_trx_id) /*!< out: end_trx_id */ { - rec_t *clust_rec; bool found = false; - mem_heap_t *clust_heap = mem_heap_create(256); - ulint clust_offsets_[REC_OFFS_NORMAL_SIZE]; - ulint *clust_offsets = clust_offsets_; - rec_offs_init(clust_offsets_); - btr_pcur_t clust_pcur; - - dict_index_t *clust_index = dict_table_get_first_index(index->table); - - dtuple_t *ref = - row_build_row_ref(ROW_COPY_POINTERS, index, rec, clust_heap); + mem_heap_t *heap = mem_heap_create(256); + dict_index_t *clust_index = NULL; + ulint offsets_[REC_OFFS_NORMAL_SIZE]; + ulint *offsets = offsets_; + rec_offs_init(offsets_); - mtr_t clust_mtr; - mtr_start(&clust_mtr); - btr_pcur_open_on_user_rec(clust_index, ref, PAGE_CUR_GE, - BTR_SEARCH_LEAF, &clust_pcur, &clust_mtr); + mtr_t mtr; + mtr_start(&mtr); - if (!btr_pcur_is_on_user_rec(&clust_pcur)) + rec_t *clust_rec = + row_get_clust_rec(BTR_SEARCH_LEAF, rec, index, &clust_index, &mtr); + if (!clust_rec) goto not_found; - clust_rec = btr_pcur_get_rec(&clust_pcur); - clust_offsets = rec_get_offsets(clust_rec, clust_index, clust_offsets, - ULINT_UNDEFINED, &clust_heap); - if (0 != cmp_dtuple_rec(ref, clust_rec, clust_offsets)) - goto not_found; + offsets = rec_get_offsets(clust_rec, clust_index, offsets, + ULINT_UNDEFINED, &heap); - *end_trx_id = row_ins_get_sys_trx_end( - clust_rec, clust_offsets, clust_index); + *end_trx_id = row_ins_get_sys_trx_end(clust_rec, offsets, clust_index); found = true; not_found: - mtr_commit(&clust_mtr); - btr_pcur_close(&clust_pcur); - mem_heap_free(clust_heap); + mtr_commit(&mtr); + mem_heap_free(heap); if (!found) { fprintf(stderr, "InnoDB: foreign constraints: secondary index is out of sync\n"); + ut_ad(false && "secondary index is out of sync"); return(DB_NO_REFERENCED_ROW); } return(DB_SUCCESS); -- cgit v1.2.1 From 1645e97cc91f695eea5bf8ea87e0bfb737812a4f Mon Sep 17 00:00:00 2001 From: Kosov Eugene Date: Thu, 10 Nov 2016 13:47:50 +0300 Subject: Tests: forgotten foreign.result --- mysql-test/suite/versioning/r/foreign.result | 129 +++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 mysql-test/suite/versioning/r/foreign.result diff --git a/mysql-test/suite/versioning/r/foreign.result b/mysql-test/suite/versioning/r/foreign.result new file mode 100644 index 00000000000..b9c49778c5e --- /dev/null +++ b/mysql-test/suite/versioning/r/foreign.result @@ -0,0 +1,129 @@ +create table parent( +id int unique key +) engine innodb; +create table child( +parent_id int, +foreign key(parent_id) references parent(id) +on delete restrict +on update restrict +) engine innodb with system versioning; +insert into parent values(1); +insert into child values(1); +delete from parent where id = 1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`)) +delete from child where parent_id = 1; +delete from parent where id = 1; +insert into parent values(1); +insert into child values(1); +update parent set id=id+1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`)) +delete from child; +update parent set id=id+1; +select * from child for system_time from timestamp '1-1-1' to timestamp now(6); +parent_id +1 +1 +drop table child; +drop table parent; +create table parent( +id int(10) unsigned unique key +) engine innodb; +create table child( +parent_id int(10) unsigned primary key, +foreign key(parent_id) references parent(id) +) engine innodb with system versioning; +insert into parent values(1); +insert into child values(1); +delete from parent where id = 1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`)) +drop table child; +drop table parent; +create table parent( +id int unique key +) engine innodb; +create table child( +parent_id int, +foreign key(parent_id) references parent(id) +on delete cascade +on update cascade +) engine innodb with system versioning; +insert into parent values(1); +insert into child values(1); +delete from parent where id = 1; +select * from child; +parent_id +select * from child for system_time from timestamp '1-1-1' to timestamp now(6); +parent_id +1 +insert into parent values(1); +insert into child values(1); +update parent set id=id+1; +select * from child; +parent_id +2 +select * from child for system_time from timestamp '1-1-1' to timestamp now(6); +parent_id +1 +2 +drop table child; +drop table parent; +create table parent( +id int unique key +) engine innodb; +create table child( +parent_id int, +foreign key(parent_id) references parent(id) +on delete set null +on update set null +) engine innodb with system versioning; +insert into parent values(1); +insert into child values(1); +delete from child; +insert into child values(1); +delete from parent where id = 1; +select * from child; +parent_id +NULL +select * from child for system_time from timestamp '1-1-1' to timestamp now(6); +parent_id +1 +NULL +delete from child; +insert into parent values(1); +insert into child values(1); +update parent set id=id+1; +select * from child; +parent_id +NULL +select * from child for system_time from timestamp '1-1-1' to timestamp now(6); +parent_id +1 +NULL +NULL +drop table child; +drop table parent; +create or replace table parent( +id int unique key +) engine innodb with system versioning; +create or replace table child( +parent_id int, +foreign key(parent_id) references parent(id) +) engine innodb; +insert into parent values(1); +insert into child values(1); +delete from parent; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`)) +update parent set id=2; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`)) +delete from child; +delete from parent; +insert into child values(1); +ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`)) +insert into parent values(1); +insert into child values(1); +delete from parent; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`)) +update parent set id=2; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`)) +drop table child; +drop table parent; -- cgit v1.2.1 From 618d87e5cbb043cc31ec79f8ad8793beddf9d799 Mon Sep 17 00:00:00 2001 From: Kosov Eugene Date: Thu, 10 Nov 2016 14:34:09 +0300 Subject: Scripts: debug and release configurations for travis build Closes #72 --- .travis.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 267f479eb8f..43e72839b03 100644 --- a/.travis.yml +++ b/.travis.yml @@ -62,6 +62,11 @@ addons: - libcrack2-dev - libjemalloc-dev - devscripts # implicit for any build on Ubuntu + - libtcmalloc-minimal4 + +env: + - BUILD_TYPE=-DCMAKE_BUILD_TYPE=Debug -DWITH_JEMALLOC=yes -DSECURITY_HARDENED=no -DWITH_PIC=no -DCMAKE_CXX_FLAGS_DEBUG="-g -O0" -DCMAKE_C_FLAGS_DEBUG="-g -O0" "${TRAVIS_BUILD_DIR}" + - BUILD_TYPE=-DCMAKE_BUILD_TYPE=Release -DWITH_JEMALLOC=yes -DSECURITY_HARDENED=yes -DWITH_PIC=no -DCMAKE_CXX_FLAGS_DEBUG="-g -O2" -DCMAKE_C_FLAGS_DEBUG="-g -O2" "${TRAVIS_BUILD_DIR}" # libsnappy-dev # https://github.com/travis-ci/apt-package-whitelist/issues/3880 # liblzma-dev # https://github.com/travis-ci/apt-package-whitelist/issues/3879 @@ -72,7 +77,4 @@ script: - export MYSQL_BUILD_CC=/usr/bin/gcc-${GCC_VERSION} MYSQL_BUILD_CXX=/usr/bin/g++-${GCC_VERSION} - ${MYSQL_BUILD_CC} --version ; ${MYSQL_BUILD_CXX} --version - cd "${TRAVIS_BUILD_DIR}" - - cmake -DCMAKE_BUILD_TYPE=Debug -DWITH_INNOBASE_STORAGE_ENGINE=yes -DWITH_JEMALLOC=yes -DSECURITY_HARDENED=no -DWITH_PIC=no -DCMAKE_CXX_FLAGS_DEBUG="-g -O0" -DCMAKE_C_FLAGS_DEBUG="-g -O0" - - make -j $(grep -c processor /proc/cpuinfo) - - cd ./mysql-test - - ./mtr --suite=versioning --force --max-test-fail=0 + - "LD_PRELOAD=/usr/lib/libtcmalloc_minimal.so.4 cmake -DWITH_INNOBASE_STORAGE_ENGINE=yes $BUILD_TYPE && LD_PRELOAD=/usr/lib/libtcmalloc_minimal.so.4 make -j $(grep -c processor /proc/cpuinfo) && cd ./mysql-test && ./mtr --suite=versioning --force --max-test-fail=0" \ No newline at end of file -- cgit v1.2.1 From 07cc46acea56e7fdaab6ac3555ebc4cff078f1f0 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 14 Nov 2016 20:30:21 +0700 Subject: Scripts: travis.yml typo fix --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 43e72839b03..1066e983a67 100644 --- a/.travis.yml +++ b/.travis.yml @@ -66,7 +66,7 @@ addons: env: - BUILD_TYPE=-DCMAKE_BUILD_TYPE=Debug -DWITH_JEMALLOC=yes -DSECURITY_HARDENED=no -DWITH_PIC=no -DCMAKE_CXX_FLAGS_DEBUG="-g -O0" -DCMAKE_C_FLAGS_DEBUG="-g -O0" "${TRAVIS_BUILD_DIR}" - - BUILD_TYPE=-DCMAKE_BUILD_TYPE=Release -DWITH_JEMALLOC=yes -DSECURITY_HARDENED=yes -DWITH_PIC=no -DCMAKE_CXX_FLAGS_DEBUG="-g -O2" -DCMAKE_C_FLAGS_DEBUG="-g -O2" "${TRAVIS_BUILD_DIR}" + - BUILD_TYPE=-DCMAKE_BUILD_TYPE=Release -DWITH_JEMALLOC=yes -DSECURITY_HARDENED=yes -DCMAKE_CXX_FLAGS_RELEASE="-g" -DCMAKE_C_FLAGS_RELEASE="-g" "${TRAVIS_BUILD_DIR}" # libsnappy-dev # https://github.com/travis-ci/apt-package-whitelist/issues/3880 # liblzma-dev # https://github.com/travis-ci/apt-package-whitelist/issues/3879 @@ -77,4 +77,4 @@ script: - export MYSQL_BUILD_CC=/usr/bin/gcc-${GCC_VERSION} MYSQL_BUILD_CXX=/usr/bin/g++-${GCC_VERSION} - ${MYSQL_BUILD_CC} --version ; ${MYSQL_BUILD_CXX} --version - cd "${TRAVIS_BUILD_DIR}" - - "LD_PRELOAD=/usr/lib/libtcmalloc_minimal.so.4 cmake -DWITH_INNOBASE_STORAGE_ENGINE=yes $BUILD_TYPE && LD_PRELOAD=/usr/lib/libtcmalloc_minimal.so.4 make -j $(grep -c processor /proc/cpuinfo) && cd ./mysql-test && ./mtr --suite=versioning --force --max-test-fail=0" \ No newline at end of file + - "LD_PRELOAD=/usr/lib/libtcmalloc_minimal.so.4 cmake -DWITH_INNOBASE_STORAGE_ENGINE=yes $BUILD_TYPE && LD_PRELOAD=/usr/lib/libtcmalloc_minimal.so.4 make -j $(grep -c processor /proc/cpuinfo) && cd ./mysql-test && ./mtr --suite=versioning --force --max-test-fail=0" -- cgit v1.2.1 From d54d36c45e1eb14bb549dd225a28bea1d168754a Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 14 Nov 2016 06:14:28 +0000 Subject: IB, SQL: (0.4) COMMIT_ID-based ordering of transactions IB: * removed CONCURR_TRX from VTQ; * new fields in VTQ: COMMIT_ID, ISO_LEVEL. SQL: * renamed BEGIN_TS, COMMIT_TS to VTQ_BEGIN_TS, VTQ_COMMIT_TS; * new functions: VTQ_COMMIT_ID, VTQ_ISO_LEVEL, VTQ_TRX_ID, VTQ_TRX_SEES, VTQ_TRX_SEES_EQ; * versioned SELECT for IB uses VTQ_TRX_SEES, VTQ_TRX_SEES_EQ. Closes #71 --- mysql-test/suite/versioning/common.inc | 6 +- .../suite/versioning/r/auto_increment.result | 8 +- mysql-test/suite/versioning/r/commit_id.result | 103 +++++++ mysql-test/suite/versioning/r/delete.result | 20 +- mysql-test/suite/versioning/r/insert.result | 24 +- .../suite/versioning/r/optimized_fields.result | 20 +- mysql-test/suite/versioning/r/select.result | 12 +- mysql-test/suite/versioning/r/update.result | 20 +- mysql-test/suite/versioning/t/auto_increment.test | 2 +- mysql-test/suite/versioning/t/commit_id.test | 79 +++++ mysql-test/suite/versioning/t/delete.test | 6 +- mysql-test/suite/versioning/t/insert.test | 10 +- mysql-test/suite/versioning/t/select.test | 6 +- mysql-test/suite/versioning/t/update.test | 14 +- sql/handler.h | 4 +- sql/item.h | 13 +- sql/item_create.cc | 122 +++++--- sql/item_timefunc.cc | 222 ++++++++++++-- sql/item_timefunc.h | 101 ++++++- sql/sql_select.cc | 98 ++++-- sql/vtq.h | 18 +- storage/innobase/btr/btr0pcur.cc | 5 +- storage/innobase/dict/dict0crea.cc | 33 +- storage/innobase/dict/dict0load.cc | 71 ++--- storage/innobase/handler/ha_innodb.cc | 335 +++++++++++++++++++-- storage/innobase/handler/i_s.cc | 67 +++-- storage/innobase/include/dict0boot.h | 16 +- storage/innobase/include/dict0dict.h | 3 +- storage/innobase/include/dict0load.h | 8 +- storage/innobase/include/row0ins.ic | 35 ++- storage/innobase/include/trx0trx.h | 10 +- storage/innobase/include/trx0vtq.h | 40 +++ storage/innobase/row/row0ins.cc | 39 ++- storage/innobase/row/row0mysql.cc | 6 +- storage/innobase/trx/trx0trx.cc | 11 - 35 files changed, 1241 insertions(+), 346 deletions(-) create mode 100644 mysql-test/suite/versioning/r/commit_id.result create mode 100644 mysql-test/suite/versioning/t/commit_id.test create mode 100644 storage/innobase/include/trx0vtq.h diff --git a/mysql-test/suite/versioning/common.inc b/mysql-test/suite/versioning/common.inc index 6306e9e9ed3..6723395f92f 100644 --- a/mysql-test/suite/versioning/common.inc +++ b/mysql-test/suite/versioning/common.inc @@ -10,9 +10,9 @@ begin select @i:= @i + 1 as No, trx_id > 0 as A, - begin_ts > '1-1-1 0:0:0' as B, - commit_ts > begin_ts as C, - concurr_trx is null as D + commit_id >= trx_id as B, + begin_ts > '1-1-1 0:0:0' as C, + commit_ts > begin_ts as D from information_schema.innodb_vtq where trx_id > @start_trx_id; select ifnull(max(trx_id), 0) diff --git a/mysql-test/suite/versioning/r/auto_increment.result b/mysql-test/suite/versioning/r/auto_increment.result index 9dc0075d06d..81222963826 100644 --- a/mysql-test/suite/versioning/r/auto_increment.result +++ b/mysql-test/suite/versioning/r/auto_increment.result @@ -6,9 +6,9 @@ set @i= 0; select @i:= @i + 1 as No, trx_id > 0 as A, -begin_ts > '1-1-1 0:0:0' as B, -commit_ts > begin_ts as C, -concurr_trx is null as D +commit_id >= trx_id as B, +begin_ts > '1-1-1 0:0:0' as C, +commit_ts > begin_ts as D from information_schema.innodb_vtq where trx_id > @start_trx_id; select ifnull(max(trx_id), 0) @@ -93,7 +93,7 @@ A x y x y 1 5 15 5 15 1 6 16 6 16 1 7 17 7 17 -call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_01('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); A x y x y 1 1 11 1 11 1 2 12 2 12 diff --git a/mysql-test/suite/versioning/r/commit_id.result b/mysql-test/suite/versioning/r/commit_id.result new file mode 100644 index 00000000000..bb70b239fa0 --- /dev/null +++ b/mysql-test/suite/versioning/r/commit_id.result @@ -0,0 +1,103 @@ +set @@session.time_zone='+00:00'; +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +create procedure if not exists verify_vtq() +begin +set @i= 0; +select +@i:= @i + 1 as No, +trx_id > 0 as A, +commit_id >= trx_id as B, +begin_ts > '1-1-1 0:0:0' as C, +commit_ts > begin_ts as D +from information_schema.innodb_vtq +where trx_id > @start_trx_id; +select ifnull(max(trx_id), 0) +into @start_trx_id +from information_schema.innodb_vtq; +end~~ +create table t1( +id int auto_increment primary key) +with system versioning +engine innodb; +set transaction isolation level read uncommitted; +insert into t1 values (); +select iso_level = 'RU' from information_schema.innodb_vtq limit 1; +iso_level = 'RU' +1 +set transaction isolation level read committed; +insert into t1 values (); +select iso_level = 'RC' from information_schema.innodb_vtq limit 1; +iso_level = 'RC' +1 +set transaction isolation level serializable; +insert into t1 values (); +select iso_level = 'S' from information_schema.innodb_vtq limit 1; +iso_level = 'S' +1 +set transaction isolation level repeatable read; +insert into t1 values (); +select iso_level = 'RR' from information_schema.innodb_vtq limit 1; +iso_level = 'RR' +1 +set @ts0= now(6); +insert into t1 values (); +select sys_trx_start from t1 where id = last_insert_id() into @tx0; +select trx_id = @tx0 from information_schema.innodb_vtq limit 1; +trx_id = @tx0 +1 +set @ts1= now(6); +insert into t1 values (); +select sys_trx_start from t1 where id = last_insert_id() into @tx1; +select trx_id = @tx1 from information_schema.innodb_vtq limit 1; +trx_id = @tx1 +1 +set @ts2= now(6); +insert into t1 values (); +select sys_trx_start from t1 where id = last_insert_id() into @tx2; +select trx_id = @tx2 from information_schema.innodb_vtq limit 1; +trx_id = @tx2 +1 +set @ts3= now(6); +select +vtq_trx_id(@ts0) < @tx0 as A, +vtq_trx_id(@ts0, true) = @tx0 as B, +vtq_trx_id(@ts1) = @tx0 as C, +vtq_trx_id(@ts1, true) = @tx1 as D, +vtq_trx_id(@ts2) = @tx1 as E, +vtq_trx_id(@ts2, true) = @tx2 as F, +vtq_trx_id(@ts3) = @tx2 as G, +vtq_trx_id(@ts3, true) is null as H; +A B C D E F G H +1 1 1 1 1 1 1 1 +select +vtq_commit_id(@ts0) < @tx0 as A, +vtq_commit_id(@ts0, true) = vtq_commit_id(null, @tx0) as B, +vtq_commit_id(@ts1) = vtq_commit_id(null, @tx0) as C, +vtq_commit_id(@ts1, true) = vtq_commit_id(null, @tx1) as D, +vtq_commit_id(@ts2) = vtq_commit_id(null, @tx1) as E, +vtq_commit_id(@ts2, true) = vtq_commit_id(null, @tx2) as F, +vtq_commit_id(@ts3) = vtq_commit_id(null, @tx2) as G, +vtq_commit_id(@ts3, true) is null as H; +A B C D E F G H +1 1 1 1 1 1 1 1 +select +vtq_trx_sees(@tx1, @tx0) as A, +not vtq_trx_sees(@tx0, @tx1) as B, +vtq_trx_sees_eq(@tx1, @tx1) as C, +not vtq_trx_sees(@tx1, @tx1) as D, +vtq_trx_sees(@tx2, 0) as E, +vtq_trx_sees(0, @tx2) is null as F, +vtq_trx_sees(-1, @tx2) as H; +A B C D E F H +1 1 1 1 1 1 1 +drop table t1; +call verify_vtq; +No A B C D +1 1 1 1 1 +2 1 1 1 1 +3 1 1 1 1 +4 1 1 1 1 +5 1 1 1 1 +6 1 1 1 1 +7 1 1 1 1 +drop procedure verify_vtq; diff --git a/mysql-test/suite/versioning/r/delete.result b/mysql-test/suite/versioning/r/delete.result index 2d604ff3381..e8e7ba34919 100644 --- a/mysql-test/suite/versioning/r/delete.result +++ b/mysql-test/suite/versioning/r/delete.result @@ -6,9 +6,9 @@ set @i= 0; select @i:= @i + 1 as No, trx_id > 0 as A, -begin_ts > '1-1-1 0:0:0' as B, -commit_ts > begin_ts as C, -concurr_trx is null as D +commit_id >= trx_id as B, +begin_ts > '1-1-1 0:0:0' as C, +commit_ts > begin_ts as D from information_schema.innodb_vtq where trx_id > @start_trx_id; select ifnull(max(trx_id), 0) @@ -164,8 +164,8 @@ XNo sys_end < '2038-01-19 03:14:07' 7 1 8 1 9 1 -call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); -XNo commit_ts(sys_end) < '2038-01-19 03:14:07' +call test_01('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); +XNo vtq_commit_ts(sys_end) < '2038-01-19 03:14:07' 0 0 1 0 2 0 @@ -176,7 +176,7 @@ XNo commit_ts(sys_end) < '2038-01-19 03:14:07' 7 0 8 0 9 0 -XNo commit_ts(sys_end) < '2038-01-19 03:14:07' +XNo vtq_commit_ts(sys_end) < '2038-01-19 03:14:07' 0 1 1 0 2 0 @@ -187,7 +187,7 @@ XNo commit_ts(sys_end) < '2038-01-19 03:14:07' 7 0 8 0 9 0 -XNo commit_ts(sys_end) < '2038-01-19 03:14:07' +XNo vtq_commit_ts(sys_end) < '2038-01-19 03:14:07' 0 1 1 1 2 0 @@ -207,7 +207,7 @@ XNo 2 4 5 -XNo commit_ts(sys_end) < '2038-01-19 03:14:07' +XNo vtq_commit_ts(sys_end) < '2038-01-19 03:14:07' 0 1 1 1 2 0 @@ -239,7 +239,7 @@ call test_02('timestamp(6)', 'myisam', 'sys_end'); x sys_start sys_end A B C 1 1 1 -call test_02('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_02('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); x sys_start sys_end A B C 1 1 1 @@ -273,7 +273,7 @@ t2_x_all 12 13 14 -call test_03('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_03('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); t1_x 1 2 diff --git a/mysql-test/suite/versioning/r/insert.result b/mysql-test/suite/versioning/r/insert.result index 343abb7978c..fdac34f6759 100644 --- a/mysql-test/suite/versioning/r/insert.result +++ b/mysql-test/suite/versioning/r/insert.result @@ -6,9 +6,9 @@ set @i= 0; select @i:= @i + 1 as No, trx_id > 0 as A, -begin_ts > '1-1-1 0:0:0' as B, -commit_ts > begin_ts as C, -concurr_trx is null as D +commit_id >= trx_id as B, +begin_ts > '1-1-1 0:0:0' as C, +commit_ts > begin_ts as D from information_schema.innodb_vtq where trx_id > @start_trx_id; select ifnull(max(trx_id), 0) @@ -156,8 +156,8 @@ x y sys_end 3 4 2038-01-19 03:14:07.000000 2 3 2038-01-19 03:14:07.000000 40 33 2038-01-19 03:14:07.000000 -call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); -x y commit_ts(sys_end) +call test_01('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); +x y vtq_commit_ts(sys_end) 3 4 2038-01-19 03:14:07.000000 2 3 2038-01-19 03:14:07.000000 40 33 2038-01-19 03:14:07.000000 @@ -166,8 +166,8 @@ id x y sys_end 1 33 44 2038-01-19 03:14:07.000000 20 33 44 2038-01-19 03:14:07.000000 40 33 44 2038-01-19 03:14:07.000000 -call test_02('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); -id x y commit_ts(sys_end) +call test_02('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); +id x y vtq_commit_ts(sys_end) 1 33 44 2038-01-19 03:14:07.000000 20 33 44 2038-01-19 03:14:07.000000 40 33 44 2038-01-19 03:14:07.000000 @@ -194,8 +194,8 @@ ERROR HY000: Generated field for System Versioning cannot be set by user drop table t1; drop view vt1_1; drop view vt1_2; -call test_03('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); -x y commit_ts(sys_end) +call test_03('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); +x y vtq_commit_ts(sys_end) 8001 9001 2038-01-19 03:14:07.000000 1001 2001 2038-01-19 03:14:07.000000 1002 2002 2038-01-19 03:14:07.000000 @@ -205,7 +205,7 @@ x y 1001 2001 1002 2002 3001 4001 -x y commit_ts(sys_end) +x y vtq_commit_ts(sys_end) 8001 9001 2038-01-19 03:14:07.000000 1001 2001 2038-01-19 03:14:07.000000 1002 2002 2038-01-19 03:14:07.000000 @@ -222,7 +222,7 @@ id a b 1 1 1 id a b C D 2 2 2 1 1 -call test_04('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_04('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); id a b 1 1 1 id a b C D @@ -257,7 +257,7 @@ x y 7 7001 8 8001 9 9001 -call test_05('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_05('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); x y 1 1001 2 2001 diff --git a/mysql-test/suite/versioning/r/optimized_fields.result b/mysql-test/suite/versioning/r/optimized_fields.result index 2e266430967..aa1f1d3696b 100644 --- a/mysql-test/suite/versioning/r/optimized_fields.result +++ b/mysql-test/suite/versioning/r/optimized_fields.result @@ -17,50 +17,50 @@ a b b+0 1 NULL NULL 3 NULL NULL Warnings: -Warning 4050 Attempt to read unversioned field 'b' in historical query +Warning 4067 Attempt to read unversioned field 'b' in historical query select * from t for system_time as of timestamp now(6); a b 1 NULL 3 NULL Warnings: -Warning 4050 Attempt to read unversioned field 'b' in historical query +Warning 4067 Attempt to read unversioned field 'b' in historical query select count(*) from t group by b for system_time as of timestamp now(6); count(*) 2 Warnings: -Warning 4050 Attempt to read unversioned field 'b' in historical query +Warning 4067 Attempt to read unversioned field 'b' in historical query select * from t for system_time as of timestamp now(6) order by b asc; a b 1 NULL 3 NULL Warnings: -Warning 4050 Attempt to read unversioned field 'b' in historical query +Warning 4067 Attempt to read unversioned field 'b' in historical query select * from t for system_time as of timestamp now(6) order by b desc; a b 1 NULL 3 NULL Warnings: -Warning 4050 Attempt to read unversioned field 'b' in historical query +Warning 4067 Attempt to read unversioned field 'b' in historical query select * from t group by a having a=2 for system_time as of timestamp now(6); a b Warnings: -Warning 4050 Attempt to read unversioned field 'b' in historical query +Warning 4067 Attempt to read unversioned field 'b' in historical query select * from t group by b having b=2 for system_time as of timestamp now(6); a b Warnings: -Warning 4050 Attempt to read unversioned field 'b' in historical query +Warning 4067 Attempt to read unversioned field 'b' in historical query select a from t where b=2 for system_time as of timestamp now(6); a Warnings: -Warning 4050 Attempt to read unversioned field 'b' in historical query +Warning 4067 Attempt to read unversioned field 'b' in historical query select a from t where b=NULL for system_time as of timestamp now(6); a Warnings: -Warning 4050 Attempt to read unversioned field 'b' in historical query +Warning 4067 Attempt to read unversioned field 'b' in historical query select count(*), b from t group by b having b=NULL for system_time as of timestamp now(6); count(*) b Warnings: -Warning 4050 Attempt to read unversioned field 'b' in historical query +Warning 4067 Attempt to read unversioned field 'b' in historical query select a, b from t; a b 1 2 diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index da8cb25340e..92e5c25fc6e 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -6,9 +6,9 @@ set @i= 0; select @i:= @i + 1 as No, trx_id > 0 as A, -begin_ts > '1-1-1 0:0:0' as B, -commit_ts > begin_ts as C, -concurr_trx is null as D +commit_id >= trx_id as B, +begin_ts > '1-1-1 0:0:0' as C, +commit_ts > begin_ts as D from information_schema.innodb_vtq where trx_id > @start_trx_id; select ifnull(max(trx_id), 0) @@ -51,7 +51,7 @@ insert into t1(x, y) values(3, 33); select sys_start from t1 where x = 3 and y = 33 into @t1; if engine = 'innodb' then set @x1= @t1; -select commit_ts(@x1) into @t1; +select vtq_commit_ts(@x1) into @t1; end if; select x, y from t1; select x as ASOF_x, y from t1 for system_time as of timestamp @t0; @@ -169,7 +169,7 @@ BETWAND_ext_x y 8 108 9 109 3 33 -call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_start)'); +call test_01('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_start)'); x y 0 100 1 101 @@ -326,7 +326,7 @@ RJ2_x1 y1 x2 y2 1 3 1 2 NULL NULL 2 1 NULL NULL 3 1 -call test_02('bigint unsigned', 'innodb', 'commit_ts(sys_start)'); +call test_02('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_start)'); IJ1_x1 y1 x2 y2 1 1 1 2 1 2 1 2 diff --git a/mysql-test/suite/versioning/r/update.result b/mysql-test/suite/versioning/r/update.result index ff0874799b0..da626cf425d 100644 --- a/mysql-test/suite/versioning/r/update.result +++ b/mysql-test/suite/versioning/r/update.result @@ -6,9 +6,9 @@ set @i= 0; select @i:= @i + 1 as No, trx_id > 0 as A, -begin_ts > '1-1-1 0:0:0' as B, -commit_ts > begin_ts as C, -concurr_trx is null as D +commit_id >= trx_id as B, +begin_ts > '1-1-1 0:0:0' as C, +commit_ts > begin_ts as D from information_schema.innodb_vtq where trx_id > @start_trx_id; select ifnull(max(trx_id), 0) @@ -258,7 +258,7 @@ x y 9 9001 8 8000 9 9000 -call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_01('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); x y 1 1000 2 2000 @@ -296,7 +296,7 @@ A1 x y 1 11 11 A2 x 1 11 -call test_02('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_02('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); A1 x y 1 11 11 A2 x @@ -308,7 +308,7 @@ x y 3 3 3 1 3 2 -call test_03('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_03('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); x y 1 1 2 1 @@ -322,7 +322,7 @@ x 2 x 3 -call test_04('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_04('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); x x 1 @@ -356,7 +356,7 @@ x y 7 7000 8 8000 9 9000 -call test_05('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_05('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); x y 1 1000 2 2000 @@ -431,7 +431,7 @@ x y 7 7010 8 8010 9 9010 -call test_06('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_06('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); x y 1 1000 2 2000 @@ -489,7 +489,7 @@ B1 salary 1 2500 B2 salary 1 2500 -call test_07('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_07('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); A1 name 1 Jerry A2 name diff --git a/mysql-test/suite/versioning/t/auto_increment.test b/mysql-test/suite/versioning/t/auto_increment.test index 978a0eec9d4..ee5cb9411d0 100644 --- a/mysql-test/suite/versioning/t/auto_increment.test +++ b/mysql-test/suite/versioning/t/auto_increment.test @@ -60,7 +60,7 @@ end~~ delimiter ;~~ call test_01('timestamp(6)', 'myisam', 'sys_end'); -call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_01('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); call verify_vtq; drop procedure test_01; diff --git a/mysql-test/suite/versioning/t/commit_id.test b/mysql-test/suite/versioning/t/commit_id.test new file mode 100644 index 00000000000..9f06e8a5b50 --- /dev/null +++ b/mysql-test/suite/versioning/t/commit_id.test @@ -0,0 +1,79 @@ +-- source suite/versioning/common.inc + +create table t1( + id int auto_increment primary key) +with system versioning +engine innodb; + + + +# VTQ_ISO_LEVEL # + +set transaction isolation level read uncommitted; +insert into t1 values (); +select iso_level = 'RU' from information_schema.innodb_vtq limit 1; + +set transaction isolation level read committed; +insert into t1 values (); +select iso_level = 'RC' from information_schema.innodb_vtq limit 1; + +set transaction isolation level serializable; +insert into t1 values (); +select iso_level = 'S' from information_schema.innodb_vtq limit 1; + +set transaction isolation level repeatable read; +insert into t1 values (); +select iso_level = 'RR' from information_schema.innodb_vtq limit 1; + + +# VTQ_TRX_ID, VTQ_COMMIT_ID, VTQ_TRX_SEES # + +set @ts0= now(6); +insert into t1 values (); +select sys_trx_start from t1 where id = last_insert_id() into @tx0; +select trx_id = @tx0 from information_schema.innodb_vtq limit 1; + +set @ts1= now(6); +insert into t1 values (); +select sys_trx_start from t1 where id = last_insert_id() into @tx1; +select trx_id = @tx1 from information_schema.innodb_vtq limit 1; + +set @ts2= now(6); +insert into t1 values (); +select sys_trx_start from t1 where id = last_insert_id() into @tx2; +select trx_id = @tx2 from information_schema.innodb_vtq limit 1; + +set @ts3= now(6); + +select + vtq_trx_id(@ts0) < @tx0 as A, + vtq_trx_id(@ts0, true) = @tx0 as B, + vtq_trx_id(@ts1) = @tx0 as C, + vtq_trx_id(@ts1, true) = @tx1 as D, + vtq_trx_id(@ts2) = @tx1 as E, + vtq_trx_id(@ts2, true) = @tx2 as F, + vtq_trx_id(@ts3) = @tx2 as G, + vtq_trx_id(@ts3, true) is null as H; + +select + vtq_commit_id(@ts0) < @tx0 as A, + vtq_commit_id(@ts0, true) = vtq_commit_id(null, @tx0) as B, + vtq_commit_id(@ts1) = vtq_commit_id(null, @tx0) as C, + vtq_commit_id(@ts1, true) = vtq_commit_id(null, @tx1) as D, + vtq_commit_id(@ts2) = vtq_commit_id(null, @tx1) as E, + vtq_commit_id(@ts2, true) = vtq_commit_id(null, @tx2) as F, + vtq_commit_id(@ts3) = vtq_commit_id(null, @tx2) as G, + vtq_commit_id(@ts3, true) is null as H; + +select + vtq_trx_sees(@tx1, @tx0) as A, + not vtq_trx_sees(@tx0, @tx1) as B, + vtq_trx_sees_eq(@tx1, @tx1) as C, + not vtq_trx_sees(@tx1, @tx1) as D, + vtq_trx_sees(@tx2, 0) as E, + vtq_trx_sees(0, @tx2) is null as F, + vtq_trx_sees(-1, @tx2) as H; + +drop table t1; +call verify_vtq; +drop procedure verify_vtq; diff --git a/mysql-test/suite/versioning/t/delete.test b/mysql-test/suite/versioning/t/delete.test index 48bec973cee..320efd29d56 100644 --- a/mysql-test/suite/versioning/t/delete.test +++ b/mysql-test/suite/versioning/t/delete.test @@ -101,17 +101,17 @@ delimiter ;~~ --echo # Basic + delete from view call test_01('timestamp(6)', 'myisam', 'sys_end'); -call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_01('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); call verify_vtq; --echo # Check sys_start, sys_end call test_02('timestamp(6)', 'myisam', 'sys_end'); -call test_02('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_02('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); call verify_vtq; --echo # Multi-delete call test_03('timestamp(6)', 'myisam', 'sys_end'); -call test_03('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_03('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); call verify_vtq; drop procedure test_01; diff --git a/mysql-test/suite/versioning/t/insert.test b/mysql-test/suite/versioning/t/insert.test index e13a5d0516a..80eded07d2c 100644 --- a/mysql-test/suite/versioning/t/insert.test +++ b/mysql-test/suite/versioning/t/insert.test @@ -144,10 +144,10 @@ end~~ delimiter ;~~ call test_01('timestamp(6)', 'myisam', 'sys_end'); -call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_01('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); call test_02('timestamp(6)', 'myisam', 'sys_end'); -call test_02('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_02('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); call test_03('timestamp(6)', 'myisam', 'sys_end'); --ERROR ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER @@ -158,7 +158,7 @@ drop table t1; drop view vt1_1; drop view vt1_2; -call test_03('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_03('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); --ERROR ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER insert into t1(x, y, sys_end) values(8001, 9001, 1111111); --ERROR ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER @@ -168,10 +168,10 @@ drop view vt1_1; drop view vt1_2; call test_04('timestamp(6)', 'myisam', 'sys_end'); -call test_04('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_04('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); call test_05('timestamp(6)', 'myisam', 'sys_end'); -call test_05('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_05('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); # VTQ test diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index 6c586ccd868..3db024b6624 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -39,7 +39,7 @@ begin select sys_start from t1 where x = 3 and y = 33 into @t1; if engine = 'innodb' then set @x1= @t1; - select commit_ts(@x1) into @t1; + select vtq_commit_ts(@x1) into @t1; end if; select x, y from t1; @@ -102,10 +102,10 @@ end~~ delimiter ;~~ call test_01('timestamp(6)', 'myisam', 'sys_start'); -call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_start)'); +call test_01('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_start)'); call test_02('timestamp(6)', 'myisam', 'sys_start'); -call test_02('bigint unsigned', 'innodb', 'commit_ts(sys_start)'); +call test_02('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_start)'); # Test wildcard expansion on hidden fields. create table t1( diff --git a/mysql-test/suite/versioning/t/update.test b/mysql-test/suite/versioning/t/update.test index 9ca7fee4126..861e5dd66eb 100644 --- a/mysql-test/suite/versioning/t/update.test +++ b/mysql-test/suite/versioning/t/update.test @@ -234,25 +234,25 @@ end~~ delimiter ;~~ call test_01('timestamp(6)', 'myisam', 'sys_end'); -call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_01('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); call test_02('timestamp(6)', 'myisam', 'sys_end'); -call test_02('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_02('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); call test_03('timestamp(6)', 'myisam', 'sys_end'); -call test_03('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_03('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); call test_04('timestamp(6)', 'myisam', 'sys_end'); -call test_04('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_04('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); call test_05('timestamp(6)', 'myisam', 'sys_end'); -call test_05('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_05('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); call test_06('timestamp(6)', 'myisam', 'sys_end'); -call test_06('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_06('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); call test_07('timestamp(6)', 'myisam', 'sys_end'); -call test_07('bigint unsigned', 'innodb', 'commit_ts(sys_end)'); +call test_07('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); call verify_vtq; diff --git a/sql/handler.h b/sql/handler.h index 11b71a6f03d..964880b0b62 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1391,7 +1391,9 @@ struct handlerton System Versioning */ bool versioned() const; - bool (*vers_get_vtq_ts)(THD* thd, MYSQL_TIME *out, ulonglong trx_id, vtq_field_t field); + bool (*vers_query_trx_id)(THD* thd, void *out, ulonglong trx_id, vtq_field_t field); + bool (*vers_query_commit_ts)(THD* thd, void *out, const MYSQL_TIME &commit_ts, vtq_field_t field, bool backwards); + bool (*vers_trx_sees)(THD *thd, bool &result, ulonglong trx_id1, ulonglong trx_id0, ulonglong commit_id1, uchar iso_level1, ulonglong commit_id0); }; diff --git a/sql/item.h b/sql/item.h index 35b76a3278e..b7381bde260 100644 --- a/sql/item.h +++ b/sql/item.h @@ -480,9 +480,20 @@ public: String_copier_for_item(THD *thd): m_thd(thd) { } }; +/* System versioning */ +class Vers_extended_item +{ +public: + virtual vtq_record_t* vtq_cached_result() + { + return NULL; + } +}; + class Item: public Value_source, - public Type_std_attributes + public Type_std_attributes, + public Vers_extended_item { void operator=(Item &); /** diff --git a/sql/item_create.cc b/sql/item_create.cc index 48055ccb11e..7e8c60591e6 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -6678,24 +6678,26 @@ Create_func_year_week::create_native(THD *thd, LEX_STRING name, } -/* System Versioning: BEGIN_TS(), COMMIT_TS() */ - -class Create_func_begin_ts : public Create_native_func +/* System Versioning: VTQ_TRX_ID(), VTQ_COMMIT_ID(), VTQ_BEGIN_TS(), VTQ_COMMIT_TS(), VTQ_ISO_LEVEL() */ +template +class Create_func_vtq : public Create_native_func { public: virtual Item *create_native(THD *thd, LEX_STRING name, List *item_list); - static Create_func_begin_ts s_singleton; + static Create_func_vtq s_singleton; protected: - Create_func_begin_ts() {} - virtual ~Create_func_begin_ts() {} + Create_func_vtq() {} + virtual ~Create_func_vtq() {} }; -Create_func_begin_ts Create_func_begin_ts::s_singleton; +template +Create_func_vtq Create_func_vtq::s_singleton; +template Item* -Create_func_begin_ts::create_native(THD *thd, LEX_STRING name, +Create_func_vtq::create_native(THD *thd, LEX_STRING name, List *item_list) { Item *func= NULL; @@ -6708,9 +6710,38 @@ Create_func_begin_ts::create_native(THD *thd, LEX_STRING name, case 1: { Item *param_1= item_list->pop(); - func= new (thd->mem_root) Item_func_vtq_ts(thd, param_1, VTQ_BEGIN_TS); + switch (VTQ_FIELD) + { + case VTQ_BEGIN_TS: + case VTQ_COMMIT_TS: + func= new (thd->mem_root) Item_func_vtq_ts(thd, param_1, VTQ_FIELD); + break; + case VTQ_TRX_ID: + case VTQ_COMMIT_ID: + case VTQ_ISO_LEVEL: + func= new (thd->mem_root) Item_func_vtq_id(thd, param_1, VTQ_FIELD); + break; + default: + DBUG_ASSERT(0); + } + break; + } + case 2: + { + Item *param_1= item_list->pop(); + Item *param_2= item_list->pop(); + switch (VTQ_FIELD) + { + case VTQ_TRX_ID: + case VTQ_COMMIT_ID: + func= new (thd->mem_root) Item_func_vtq_id(thd, param_1, param_2, VTQ_FIELD); + break; + default: + goto error; + } break; } + error: default: { my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str); @@ -6719,49 +6750,45 @@ Create_func_begin_ts::create_native(THD *thd, LEX_STRING name, } return func; -} +}; -class Create_func_commit_ts : public Create_native_func +template +class Create_func_vtq_trx_sees : public Create_native_func { public: - virtual Item *create_native(THD *thd, LEX_STRING name, List *item_list); - - static Create_func_commit_ts s_singleton; - -protected: - Create_func_commit_ts() {} - virtual ~Create_func_commit_ts() {} -}; - -Create_func_commit_ts Create_func_commit_ts::s_singleton; + virtual Item *create_native(THD *thd, LEX_STRING name, List *item_list) + { + Item *func= NULL; + int arg_count= 0; -Item* -Create_func_commit_ts::create_native(THD *thd, LEX_STRING name, - List *item_list) -{ - Item *func= NULL; - int arg_count= 0; + if (item_list != NULL) + arg_count= item_list->elements; - if (item_list != NULL) - arg_count= item_list->elements; + switch (arg_count) { + case 2: + { + Item *param_1= item_list->pop(); + Item *param_2= item_list->pop(); + func= new (thd->mem_root) Item_func_vtq_trx_seesX(thd, param_1, param_2); + break; + } + default: + my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str); + break; + } - switch (arg_count) { - case 1: - { - Item *param_1= item_list->pop(); - func= new (thd->mem_root) Item_func_vtq_ts(thd, param_1, VTQ_COMMIT_TS); - break; - } - default: - { - my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str); - break; - } + return func; } - return func; -} + static Create_func_vtq_trx_sees s_singleton; + +protected: + Create_func_vtq_trx_sees() {} + virtual ~Create_func_vtq_trx_sees() {} +}; +template +Create_func_vtq_trx_sees Create_func_vtq_trx_sees::s_singleton; struct Native_func_registry @@ -6804,7 +6831,6 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("ASWKT") }, GEOM_BUILDER(Create_func_as_wkt)}, { { C_STRING_WITH_LEN("ATAN") }, BUILDER(Create_func_atan)}, { { C_STRING_WITH_LEN("ATAN2") }, BUILDER(Create_func_atan)}, - { { C_STRING_WITH_LEN("BEGIN_TS") }, BUILDER(Create_func_begin_ts)}, { { C_STRING_WITH_LEN("BENCHMARK") }, BUILDER(Create_func_benchmark)}, { { C_STRING_WITH_LEN("BIN") }, BUILDER(Create_func_bin)}, { { C_STRING_WITH_LEN("BINLOG_GTID_POS") }, BUILDER(Create_func_binlog_gtid_pos)}, @@ -6822,7 +6848,6 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("COLUMN_EXISTS") }, BUILDER(Create_func_dyncol_exists)}, { { C_STRING_WITH_LEN("COLUMN_LIST") }, BUILDER(Create_func_dyncol_list)}, { { C_STRING_WITH_LEN("COLUMN_JSON") }, BUILDER(Create_func_dyncol_json)}, - { { C_STRING_WITH_LEN("COMMIT_TS") }, BUILDER(Create_func_commit_ts)}, { { C_STRING_WITH_LEN("COMPRESS") }, BUILDER(Create_func_compress)}, { { C_STRING_WITH_LEN("CONCAT") }, BUILDER(Create_func_concat)}, { { C_STRING_WITH_LEN("CONCAT_WS") }, BUILDER(Create_func_concat_ws)}, @@ -7121,6 +7146,13 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("UUID") }, BUILDER(Create_func_uuid)}, { { C_STRING_WITH_LEN("UUID_SHORT") }, BUILDER(Create_func_uuid_short)}, { { C_STRING_WITH_LEN("VERSION") }, BUILDER(Create_func_version)}, + { { C_STRING_WITH_LEN("VTQ_BEGIN_TS") }, BUILDER(Create_func_vtq)}, + { { C_STRING_WITH_LEN("VTQ_COMMIT_ID") }, BUILDER(Create_func_vtq)}, + { { C_STRING_WITH_LEN("VTQ_COMMIT_TS") }, BUILDER(Create_func_vtq)}, + { { C_STRING_WITH_LEN("VTQ_ISO_LEVEL") }, BUILDER(Create_func_vtq)}, + { { C_STRING_WITH_LEN("VTQ_TRX_ID") }, BUILDER(Create_func_vtq)}, + { { C_STRING_WITH_LEN("VTQ_TRX_SEES") }, BUILDER(Create_func_vtq_trx_sees)}, + { { C_STRING_WITH_LEN("VTQ_TRX_SEES_EQ") }, BUILDER(Create_func_vtq_trx_sees)}, { { C_STRING_WITH_LEN("WEEKDAY") }, BUILDER(Create_func_weekday)}, { { C_STRING_WITH_LEN("WEEKOFYEAR") }, BUILDER(Create_func_weekofyear)}, { { C_STRING_WITH_LEN("WITHIN") }, GEOM_BUILDER(Create_func_within)}, diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 3ceb87246ce..1f9d1076060 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -3278,10 +3278,9 @@ Item_func_vtq_ts::Item_func_vtq_ts( THD *thd, Item* a, vtq_field_t _vtq_field, - handlerton* _hton) : - Item_datetimefunc(thd, a), - vtq_field(_vtq_field), - hton(_hton) + handlerton* hton) : + VTQ_common(thd, a, hton), + vtq_field(_vtq_field) { decimals= 6; null_value= true; @@ -3292,33 +3291,24 @@ Item_func_vtq_ts::Item_func_vtq_ts( THD *thd, Item* a, vtq_field_t _vtq_field) : - Item_datetimefunc(thd, a), - vtq_field(_vtq_field), - hton(NULL) + VTQ_common(thd, a), + vtq_field(_vtq_field) { decimals= 6; null_value= true; DBUG_ASSERT(arg_count == 1 && args[0]); } -bool Item_func_vtq_ts::get_date(MYSQL_TIME *res, ulonglong fuzzy_date) +template +void +VTQ_common::init_hton() { - THD *thd= current_thd; // can it differ from constructor's? - DBUG_ASSERT(thd); - ulonglong trx_id= args[0]->val_uint(); - if (trx_id == ULONGLONG_MAX) - { - null_value= false; - thd->variables.time_zone->gmt_sec_to_TIME(res, TIMESTAMP_MAX_VALUE); - return false; - } - if (!hton) { - if (args[0]->type() == Item::FIELD_ITEM) + if (Item_func_X::args[0]->type() == Item::FIELD_ITEM) { Item_field *f= - static_cast(args[0]); + static_cast(Item_func_X::args[0]); DBUG_ASSERT( f->field && f->field->table && @@ -3333,11 +3323,201 @@ bool Item_func_vtq_ts::get_date(MYSQL_TIME *res, ulonglong fuzzy_date) DBUG_ASSERT(hton); } } +} + +bool +Item_func_vtq_ts::get_date(MYSQL_TIME *res, ulonglong fuzzy_date) +{ + THD *thd= current_thd; // can it differ from constructor's? + DBUG_ASSERT(thd); + ulonglong trx_id= args[0]->val_uint(); + if (trx_id == ULONGLONG_MAX) + { + null_value= false; + thd->variables.time_zone->gmt_sec_to_TIME(res, TIMESTAMP_MAX_VALUE); + return false; + } + + init_hton(); if (!hton) return true; - null_value= !hton->vers_get_vtq_ts(thd, res, trx_id, vtq_field); + null_value= !hton->vers_query_trx_id(thd, res, trx_id, vtq_field); return false; } + + +Item_func_vtq_id::Item_func_vtq_id( + THD *thd, + Item* a, + vtq_field_t _vtq_field, + bool _backwards) : + VTQ_common(thd, a), + vtq_field(_vtq_field), + backwards(_backwards) +{ + memset(&cached_result, 0, sizeof(cached_result)); + decimals= 0; + unsigned_flag= 1; + null_value= true; + DBUG_ASSERT(arg_count == 1 && args[0]); +} + +Item_func_vtq_id::Item_func_vtq_id( + THD *thd, + Item* a, + Item* b, + vtq_field_t _vtq_field) : + VTQ_common(thd, a, b), + vtq_field(_vtq_field), + backwards(false) +{ + memset(&cached_result, 0, sizeof(cached_result)); + decimals= 0; + unsigned_flag= 1; + null_value= true; + DBUG_ASSERT(arg_count == 2 && args[0] && args[1]); +} + +longlong +Item_func_vtq_id::get_by_trx_id(ulonglong trx_id) +{ + ulonglong res; + THD *thd= current_thd; // can it differ from constructor's? + DBUG_ASSERT(thd); + + if (trx_id == ULONGLONG_MAX) + { + null_value= true; + return 0; + } + + null_value= !hton->vers_query_trx_id(thd, &res, trx_id, vtq_field); + return res; +} + +longlong +Item_func_vtq_id::get_by_commit_ts(MYSQL_TIME &commit_ts, bool backwards) +{ + THD *thd= current_thd; // can it differ from constructor's? + DBUG_ASSERT(thd); + + null_value= !hton->vers_query_commit_ts(thd, &cached_result, commit_ts, VTQ_ALL, backwards); + if (null_value) + { + return 0; + } + + switch (vtq_field) + { + case VTQ_COMMIT_ID: + return cached_result.commit_id; + case VTQ_ISO_LEVEL: + return cached_result.iso_level; + case VTQ_TRX_ID: + return cached_result.trx_id; + default: + DBUG_ASSERT(0); + null_value= true; + } + + return 0; +} + +longlong +Item_func_vtq_id::val_int() +{ + init_hton(); + + if (!hton) + { + null_value= true; + return 0; + } + + if (args[0]->is_null()) + { + if (arg_count < 2 || vtq_field == VTQ_TRX_ID) + { + null_value= true; + return 0; + } + return get_by_trx_id(args[1]->val_uint()); + } + else + { + MYSQL_TIME commit_ts; + if (args[0]->get_date(&commit_ts, 0)) + { + null_value= true; + return 0; + } + if (arg_count > 1) + { + backwards= args[1]->val_bool(); + DBUG_ASSERT(arg_count == 2); + } + return get_by_commit_ts(commit_ts, backwards); + } +} + +Item_func_vtq_trx_sees::Item_func_vtq_trx_sees( + THD *thd, + Item* a, + Item* b) : + VTQ_common(thd, a, b), + accept_eq(false) +{ + null_value= true; + DBUG_ASSERT(arg_count == 2 && args[0] && args[1]); +} + +longlong +Item_func_vtq_trx_sees::val_int() +{ + THD *thd= current_thd; + DBUG_ASSERT(thd); + + init_hton(); + + if (!hton) + { + null_value= true; + return 0; + } + + ulonglong trx_id1, trx_id0; + ulonglong commit_id1= 0; + ulonglong commit_id0= 0; + uchar iso_level1= 0; + + DBUG_ASSERT(arg_count > 1); + trx_id1= args[0]->val_uint(); + trx_id0= args[1]->val_uint(); + + vtq_record_t *cached= args[0]->vtq_cached_result(); + if (cached && cached->commit_id) + { + commit_id1= cached->commit_id; + iso_level1= cached->iso_level; + } + + cached= args[1]->vtq_cached_result(); + if (cached && cached->commit_id) + { + commit_id0= cached->commit_id; + } + + if (accept_eq && trx_id1 && trx_id1 == trx_id0) + { + null_value= false; + return true; + } + + bool result= false; + null_value= !hton->vers_trx_sees(thd, result, trx_id1, trx_id0, commit_id1, iso_level1, commit_id0); + return result; +} + diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index a8281124b38..4d7935b8506 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -1288,10 +1288,28 @@ public: #include "vtq.h" -class Item_func_vtq_ts :public Item_datetimefunc +template +class VTQ_common : public Item_func_X { - vtq_field_t vtq_field; +protected: handlerton *hton; + void init_hton(); +public: + VTQ_common(THD *thd, Item* a) : + Item_func_X(thd, a), + hton(NULL) {} + VTQ_common(THD *thd, Item* a, Item* b) : + Item_func_X(thd, a, b), + hton(NULL) {} + VTQ_common(THD *thd, Item* a, handlerton* _hton) : + Item_func_X(thd, a), + hton(_hton) {} +}; + +class Item_func_vtq_ts : + public VTQ_common +{ + vtq_field_t vtq_field; public: Item_func_vtq_ts(THD *thd, Item* a, vtq_field_t _vtq_field, handlerton *hton); Item_func_vtq_ts(THD *thd, Item* a, vtq_field_t _vtq_field); @@ -1299,13 +1317,88 @@ public: { if (vtq_field == VTQ_BEGIN_TS) { - return "begin_ts"; + return "vtq_begin_ts"; } - return "commit_ts"; + return "vtq_commit_ts"; } bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy(thd, mem_root, this); } }; +class Item_func_vtq_id : + public VTQ_common +{ + vtq_field_t vtq_field; + vtq_record_t cached_result; + bool backwards; + + longlong get_by_trx_id(ulonglong trx_id); + longlong get_by_commit_ts(MYSQL_TIME &commit_ts, bool backwards); + +public: + Item_func_vtq_id(THD *thd, Item* a, vtq_field_t _vtq_field, bool _backwards= false); + Item_func_vtq_id(THD *thd, Item* a, Item* b, vtq_field_t _vtq_field); + + vtq_record_t *vtq_cached_result() { return &cached_result; } + + const char *func_name() const + { + switch (vtq_field) + { + case VTQ_TRX_ID: + return "vtq_trx_id"; + case VTQ_COMMIT_ID: + return "vtq_commit_id"; + case VTQ_ISO_LEVEL: + return "vtq_iso_level"; + default: + DBUG_ASSERT(0); + } + return NULL; + } + + void fix_length_and_dec() + { + Item_int_func::fix_length_and_dec(); + max_length= 20; + } + + longlong val_int(); + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy(thd, mem_root, this); } +}; + +class Item_func_vtq_trx_sees : + public VTQ_common +{ +protected: + bool accept_eq; + +public: + Item_func_vtq_trx_sees(THD *thd, Item* a, Item* b); + const char *func_name() const + { + return "vtq_trx_sees"; + } + longlong val_int(); + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy(thd, mem_root, this); } +}; + +class Item_func_vtq_trx_sees_eq : + public Item_func_vtq_trx_sees +{ +public: + Item_func_vtq_trx_sees_eq(THD *thd, Item* a, Item* b) : + Item_func_vtq_trx_sees(thd, a, b) + { + accept_eq= true; + } + const char *func_name() const + { + return "vtq_trx_sees_eq"; + } +}; + #endif /* ITEM_TIMEFUNC_INCLUDED */ diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 81ff9b7246a..4c2ba3caa02 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -671,6 +671,7 @@ static int setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LEX *slex) { DBUG_ENTER("setup_for_system_time"); +#define newx new (thd->mem_root) TABLE_LIST *table; int versioned_tables= 0; @@ -741,6 +742,8 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LE } } + const static bool vers_simple_select= false; + for (table= tables; table; table= table->next_local) { if (table->table && table->table->versioned()) @@ -758,8 +761,8 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LE Name_resolution_context *context= slex->parent_lex->current_context(); DBUG_ASSERT(context); - Item *row_start= new (thd->mem_root) Item_field(thd, context, fstart); - Item *row_end= new (thd->mem_root) Item_field(thd, context, fend); + Item *row_start= newx Item_field(thd, context, fstart); + Item *row_end= newx Item_field(thd, context, fend); Item *row_end2= row_end; if (table->table->versioned_by_sql()) @@ -770,58 +773,108 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LE DBUG_RETURN(-1); } } - else if (slex->vers_conditions.unit == UNIT_TIMESTAMP) + else if (vers_simple_select && slex->vers_conditions.unit == UNIT_TIMESTAMP + && slex->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED) { DBUG_ASSERT(table->table->s && table->table->s->db_plugin); - row_start= new (thd->mem_root) Item_func_vtq_ts( + handlerton *hton= plugin_hton(table->table->s->db_plugin); + DBUG_ASSERT(hton); + row_start= newx Item_func_vtq_ts( thd, row_start, VTQ_COMMIT_TS, - plugin_hton(table->table->s->db_plugin)); - row_end= new (thd->mem_root) Item_func_vtq_ts( + // FIXME: is it needed to pass hton or it can be deduced from arg 'a'? + hton); + row_end= newx Item_func_vtq_ts( thd, row_end, VTQ_COMMIT_TS, - plugin_hton(table->table->s->db_plugin)); + hton); } Item *cond1= 0, *cond2= 0, *curr= 0; - switch (slex->vers_conditions.type) + if (table->table->versioned_by_sql() || vers_simple_select) { + switch (slex->vers_conditions.type) + { case FOR_SYSTEM_TIME_UNSPECIFIED: if (table->table->versioned_by_sql()) { MYSQL_TIME max_time; thd->variables.time_zone->gmt_sec_to_TIME(&max_time, TIMESTAMP_MAX_VALUE); - curr= new (thd->mem_root) Item_datetime_literal(thd, &max_time); - cond1= new (thd->mem_root) Item_func_eq(thd, row_end, curr); + curr= newx Item_datetime_literal(thd, &max_time); + cond1= newx Item_func_eq(thd, row_end, curr); } else { - curr= new (thd->mem_root) Item_int(thd, ULONGLONG_MAX); - cond1= new (thd->mem_root) Item_func_eq(thd, row_end2, curr); + curr= newx Item_int(thd, ULONGLONG_MAX); + cond1= newx Item_func_eq(thd, row_end2, curr); } break; case FOR_SYSTEM_TIME_AS_OF: - cond1= new (thd->mem_root) Item_func_le(thd, row_start, + cond1= newx Item_func_le(thd, row_start, slex->vers_conditions.start); - cond2= new (thd->mem_root) Item_func_gt(thd, row_end, + cond2= newx Item_func_gt(thd, row_end, slex->vers_conditions.start); break; case FOR_SYSTEM_TIME_FROM_TO: - cond1= new (thd->mem_root) Item_func_lt(thd, row_start, - slex->vers_conditions.end); - cond2= new (thd->mem_root) Item_func_ge(thd, row_end, - slex->vers_conditions.start); + cond1= newx Item_func_lt(thd, row_start, + slex->vers_conditions.end); + cond2= newx Item_func_ge(thd, row_end, + slex->vers_conditions.start); + break; + case FOR_SYSTEM_TIME_BETWEEN: + cond1= newx Item_func_le(thd, row_start, + slex->vers_conditions.end); + cond2= newx Item_func_ge(thd, row_end, + slex->vers_conditions.start); + break; + default: + DBUG_ASSERT(0); + } + } + else + { + DBUG_ASSERT(table->table->s && table->table->s->db_plugin); + handlerton *hton= plugin_hton(table->table->s->db_plugin); + DBUG_ASSERT(hton); + + Item *trx_id0, *trx_id1; + + switch (slex->vers_conditions.type) + { + case FOR_SYSTEM_TIME_UNSPECIFIED: + curr= newx Item_int(thd, ULONGLONG_MAX); + cond1= newx Item_func_eq(thd, row_end2, curr); break; + case FOR_SYSTEM_TIME_AS_OF: + trx_id0= slex->vers_conditions.unit == UNIT_TIMESTAMP ? + newx Item_func_vtq_id(thd, slex->vers_conditions.start, VTQ_TRX_ID) : + slex->vers_conditions.start; + cond1= newx Item_func_vtq_trx_sees_eq(thd, trx_id0, row_start); + cond2= newx Item_func_vtq_trx_sees(thd, row_end, trx_id0); + break; + case FOR_SYSTEM_TIME_FROM_TO: case FOR_SYSTEM_TIME_BETWEEN: - cond1= new (thd->mem_root) Item_func_le(thd, row_start, - slex->vers_conditions.end); - cond2= new (thd->mem_root) Item_func_ge(thd, row_end, - slex->vers_conditions.start); + if (slex->vers_conditions.unit == UNIT_TIMESTAMP) + { + trx_id0= newx Item_func_vtq_id(thd, slex->vers_conditions.start, VTQ_TRX_ID, true); + trx_id1= newx Item_func_vtq_id(thd, slex->vers_conditions.end, VTQ_TRX_ID, false); + } + else + { + trx_id0= slex->vers_conditions.start; + trx_id1= slex->vers_conditions.end; + } + + cond1= slex->vers_conditions.type == FOR_SYSTEM_TIME_FROM_TO ? + newx Item_func_vtq_trx_sees(thd, trx_id1, row_start) : + newx Item_func_vtq_trx_sees_eq(thd, trx_id1, row_start); + cond2= newx Item_func_vtq_trx_sees_eq(thd, row_end, trx_id0); break; default: DBUG_ASSERT(0); + } } if (cond1) @@ -848,6 +901,7 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LE } DBUG_RETURN(0); +#undef newx } /***************************************************************************** diff --git a/sql/vtq.h b/sql/vtq.h index 3a235352853..68c01990b04 100755 --- a/sql/vtq.h +++ b/sql/vtq.h @@ -17,9 +17,21 @@ enum vtq_field_t { - VTQ_BEGIN_TS = 0, - VTQ_COMMIT_TS + VTQ_ALL = 0, + VTQ_TRX_ID, + VTQ_COMMIT_ID, + VTQ_BEGIN_TS, + VTQ_COMMIT_TS, + VTQ_ISO_LEVEL }; -#endif /* VTQ_INCLUDED */ +struct vtq_record_t +{ + ulonglong trx_id; + ulonglong commit_id; + timeval begin_ts; + timeval commit_ts; + uchar iso_level; +}; +#endif /* VTQ_INCLUDED */ diff --git a/storage/innobase/btr/btr0pcur.cc b/storage/innobase/btr/btr0pcur.cc index bb636e4f5df..1fc2c99bde4 100644 --- a/storage/innobase/btr/btr0pcur.cc +++ b/storage/innobase/btr/btr0pcur.cc @@ -657,8 +657,9 @@ btr_pcur_open_on_user_rec_func( } else { ut_ad((mode == PAGE_CUR_LE) || (mode == PAGE_CUR_L)); - /* Not implemented yet */ + if (btr_pcur_is_before_first_on_page(cursor)) { - ut_error; + btr_pcur_move_to_prev_user_rec(cursor, mtr); + } } } diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc index e3eb1004c62..abcd8b380d9 100644 --- a/storage/innobase/dict/dict0crea.cc +++ b/storage/innobase/dict/dict0crea.cc @@ -1887,20 +1887,19 @@ dict_create_or_check_vtq_table(void) my_bool srv_file_per_table_backup; dberr_t err; dberr_t sys_vtq_err; + dict_index_t* index; ut_a(srv_get_active_thread_type() == SRV_NONE); /* Note: The master thread has not been started at this point. */ - + static const int vtq_num_indexes = 4; sys_vtq_err = dict_check_if_system_table_exists( - "SYS_VTQ", DICT_NUM_FIELDS__SYS_VTQ + 1, 3); + "SYS_VTQ", DICT_NUM_FIELDS__SYS_VTQ + 1, vtq_num_indexes); if (sys_vtq_err == DB_SUCCESS) { - mutex_enter(&dict_sys->mutex); - dict_sys->sys_vtq = dict_table_get_low("SYS_VTQ"); - mutex_exit(&dict_sys->mutex); - return(DB_SUCCESS); + err = DB_SUCCESS; + goto assign_and_exit; } trx = trx_allocate_for_mysql(); @@ -1935,10 +1934,16 @@ dict_create_or_check_vtq_table(void) "PROCEDURE CREATE_VTQ_SYS_TABLE_PROC () IS\n" "BEGIN\n" "CREATE TABLE\n" - "SYS_VTQ(TRX_ID BIGINT UNSIGNED, BEGIN_TS BIGINT UNSIGNED," - " COMMIT_TS BIGINT UNSIGNED, CONCURR_TRX BLOB);\n" + "SYS_VTQ(" + "TRX_ID BIGINT UNSIGNED, " + "COMMIT_ID BIGINT UNSIGNED, " + "BEGIN_TS BIGINT UNSIGNED, " + "COMMIT_TS BIGINT UNSIGNED, " + "ISO_LEVEL CHAR(1));\n" "CREATE UNIQUE CLUSTERED INDEX TRX_ID_IND" " ON SYS_VTQ (TRX_ID);\n" + "CREATE INDEX COMMIT_ID_IND" + " ON SYS_VTQ (COMMIT_ID);\n" "CREATE INDEX BEGIN_TS_IND" " ON SYS_VTQ (BEGIN_TS);\n" "CREATE INDEX COMMIT_TS_IND" @@ -1978,10 +1983,20 @@ dict_create_or_check_vtq_table(void) /* Note: The master thread has not been started at this point. */ /* Confirm and move to the non-LRU part of the table LRU list. */ sys_vtq_err = dict_check_if_system_table_exists( - "SYS_VTQ", DICT_NUM_FIELDS__SYS_VTQ + 1, 3); + "SYS_VTQ", DICT_NUM_FIELDS__SYS_VTQ + 1, vtq_num_indexes); ut_a(sys_vtq_err == DB_SUCCESS); + +assign_and_exit: mutex_enter(&dict_sys->mutex); dict_sys->sys_vtq = dict_table_get_low("SYS_VTQ"); + ut_ad(dict_sys->sys_vtq); + index = dict_table_get_first_index(dict_sys->sys_vtq); + for (int i = 0; i < 3; ++i) { + index = dict_table_get_next_index(index); + ut_ad(index); + } + ut_ad(strcmp(index->name, "COMMIT_TS_IND") == 0); + dict_sys->vtq_commit_ts_ind = index; mutex_exit(&dict_sys->mutex); return(err); diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc index 415f5eb8531..fa73380fcad 100644 --- a/storage/innobase/dict/dict0load.cc +++ b/storage/innobase/dict/dict0load.cc @@ -845,15 +845,11 @@ dict_process_sys_vtq( /*=======================*/ mem_heap_t* heap, /*!< in/out: heap memory */ const rec_t* rec, /*!< in: current rec */ -trx_id_t* col_trx_id, /*!< out: field values */ -timeval* col_begin_ts, -timeval* col_commit_ts, -char** col_concurr_trx) +vtq_record_t& out /*!< out: field values */ +) { - ulint len, col, concurr_n; - const byte *field, *ptr; - char *out; - trx_id_t trx_id; + ulint len, nfld; + const byte *field; if (rec_get_deleted_flag(rec, 0)) { return("delete-marked record in SYS_VTQ"); @@ -864,57 +860,46 @@ char** col_concurr_trx) } /* TRX_ID */ field = rec_get_nth_field_old( - rec, (col = DICT_FLD__SYS_VTQ__TRX_ID), &len); + rec, (nfld = DICT_FLD__SYS_VTQ__TRX_ID), &len); if (len != sizeof(trx_id_t)) - return dict_print_error(heap, col, len, sizeof(trx_id_t)); + return dict_print_error(heap, nfld, len, sizeof(trx_id_t)); - *col_trx_id = mach_read_from_8(field); + out.trx_id = mach_read_from_8(field); + /* COMMIT_ID */ + field = rec_get_nth_field_old( + rec, (nfld = DICT_FLD__SYS_VTQ__COMMIT_ID), &len); + + if (len != sizeof(trx_id_t)) + return dict_print_error(heap, nfld, len, sizeof(trx_id_t)); + + out.commit_id = mach_read_from_8(field); /* BEGIN_TS */ field = rec_get_nth_field_old( - rec, (col = DICT_FLD__SYS_VTQ__BEGIN_TS), &len); + rec, (nfld = DICT_FLD__SYS_VTQ__BEGIN_TS), &len); if (len != sizeof(ullong)) - return dict_print_error(heap, col, len, sizeof(ullong)); + return dict_print_error(heap, nfld, len, sizeof(ullong)); - col_begin_ts->tv_sec = mach_read_from_4(field); - col_begin_ts->tv_usec = mach_read_from_4(field + 4); + out.begin_ts.tv_sec = mach_read_from_4(field); + out.begin_ts.tv_usec = mach_read_from_4(field + 4); /* COMMIT_TS */ field = rec_get_nth_field_old( - rec, (col = DICT_FLD__SYS_VTQ__COMMIT_TS), &len); + rec, (nfld = DICT_FLD__SYS_VTQ__COMMIT_TS), &len); if (len != sizeof(ullong)) - return dict_print_error(heap, col, len, sizeof(ullong)); + return dict_print_error(heap, nfld, len, sizeof(ullong)); - col_commit_ts->tv_sec = mach_read_from_4(field); - col_commit_ts->tv_usec = mach_read_from_4(field + 4); - /* CONCURR_TRX */ + out.commit_ts.tv_sec = mach_read_from_4(field); + out.commit_ts.tv_usec = mach_read_from_4(field + 4); + /* ISOLATION_LEVEL */ field = rec_get_nth_field_old( - rec, (col = DICT_FLD__SYS_VTQ__CONCURR_TRX), &len); - concurr_n = len / sizeof(trx_id_t); - if (len != concurr_n * sizeof(trx_id_t)) - return dict_print_error(heap, col, len, concurr_n * sizeof(trx_id_t)); + rec, (nfld = DICT_FLD__SYS_VTQ__ISOLATION_LEVEL), &len); - bool truncated = false; - if (concurr_n > I_S_MAX_CONCURR_TRX) { - concurr_n = I_S_MAX_CONCURR_TRX; - truncated = true; - } + if (len != sizeof(byte)) + return dict_print_error(heap, nfld, len, sizeof(byte)); - if (concurr_n == 0) { - *col_concurr_trx = NULL; - return(NULL); - } - *col_concurr_trx = static_cast(mem_heap_alloc(heap, concurr_n * (TRX_ID_MAX_LEN + 1) + 3 + 1)); - ptr = field, out = *col_concurr_trx; - for (ulint i = 0; i < concurr_n; - ++i, ptr += sizeof(trx_id_t)) - { - trx_id = mach_read_from_8(ptr); - out += ut_snprintf(out, TRX_ID_MAX_LEN + 1, TRX_ID_FMT " ", trx_id); - } - if (truncated) - strcpy(out, "..."); + out.iso_level = *field; return(NULL); } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 18a8a9018ec..6d7f541c749 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -121,7 +121,6 @@ this program; if not, write to the Free Software Foundation, Inc., #include "trx0xa.h" #include "ut0mem.h" #include "row0ext.h" -#include "vtq.h" #define thd_get_trx_isolation(X) ((enum_tx_isolation)thd_tx_isolation(X)) @@ -1542,7 +1541,21 @@ innobase_fts_store_docid( #endif bool -innobase_get_vtq_ts(THD* thd, MYSQL_TIME *out, ulonglong in_trx_id, vtq_field_t field); +vtq_query_trx_id(THD* thd, void *out, ulonglong in_trx_id, vtq_field_t field); + +bool +vtq_query_commit_ts(THD* thd, void *out, const MYSQL_TIME &commit_ts, vtq_field_t field, bool backwards); + +bool +vtq_trx_sees( + THD *thd, + bool &result, + ulonglong trx_id1, + ulonglong trx_id0, + ulonglong commit_id1, + uchar iso_level1, + ulonglong commit_id0); + /*************************************************************//** Check for a valid value of innobase_commit_concurrency. @@ -3877,7 +3890,9 @@ innobase_init( innobase_hton->table_options = innodb_table_option_list; /* System Versioning */ - innobase_hton->vers_get_vtq_ts = innobase_get_vtq_ts; + innobase_hton->vers_query_trx_id = vtq_query_trx_id; + innobase_hton->vers_query_commit_ts = vtq_query_commit_ts; + innobase_hton->vers_trx_sees = vtq_trx_sees; innodb_remember_check_sysvar_funcs(); @@ -23138,25 +23153,54 @@ ib_push_frm_error( inline void -innobase_get_vtq_ts_result(THD* thd, vtq_query_t* q, MYSQL_TIME *out, vtq_field_t field) +innobase_vtq_result(THD* thd, vtq_record_t& q, void *out, vtq_field_t field) { + ut_ad(field == VTQ_ALL || out); + switch (field) { - case VTQ_BEGIN_TS: - thd_get_timezone(thd)->gmt_sec_to_TIME(out, q->begin_ts.tv_sec); - out->second_part = q->begin_ts.tv_usec; + case VTQ_ALL: + if (out) { + *reinterpret_cast(out) = q; + } + break; + case VTQ_TRX_ID: + *reinterpret_cast(out) = q.trx_id; + break; + case VTQ_COMMIT_ID: + *reinterpret_cast(out) = q.commit_id; break; - case VTQ_COMMIT_TS: - thd_get_timezone(thd)->gmt_sec_to_TIME(out, q->commit_ts.tv_sec); - out->second_part = q->commit_ts.tv_usec; + case VTQ_BEGIN_TS: { + MYSQL_TIME* out_ts = reinterpret_cast(out); + thd_get_timezone(thd)->gmt_sec_to_TIME(out_ts, q.begin_ts.tv_sec); + out_ts->second_part = q.begin_ts.tv_usec; + break; + } + case VTQ_COMMIT_TS: { + MYSQL_TIME* out_ts = reinterpret_cast(out); + thd_get_timezone(thd)->gmt_sec_to_TIME(out_ts, q.commit_ts.tv_sec); + out_ts->second_part = q.commit_ts.tv_usec; + break; + } + case VTQ_ISO_LEVEL: + *reinterpret_cast(out) = q.iso_level; break; default: ut_error; } } + +inline +const char * +vtq_query_t::cache_result(mem_heap_t* heap, const rec_t* rec) +{ + prev_query.tv_sec = 0; + return dict_process_sys_vtq(heap, rec, result); +} + UNIV_INTERN bool -innobase_get_vtq_ts(THD* thd, MYSQL_TIME *out, ulonglong _in_trx_id, vtq_field_t field) +vtq_query_trx_id(THD* thd, void *out, ulonglong _in_trx_id, vtq_field_t field) { trx_t* trx; dict_index_t* index; @@ -23167,11 +23211,9 @@ innobase_get_vtq_ts(THD* thd, MYSQL_TIME *out, ulonglong _in_trx_id, vtq_field_t mtr_t mtr; mem_heap_t* heap; rec_t* rec; - ulint len; - byte* result_net; bool found = false; - DBUG_ENTER("innobase_get_vtq_ts"); + DBUG_ENTER("vtq_query_trx_id"); if (_in_trx_id == 0) { DBUG_RETURN(false); @@ -23182,10 +23224,11 @@ innobase_get_vtq_ts(THD* thd, MYSQL_TIME *out, ulonglong _in_trx_id, vtq_field_t trx = thd_to_trx(thd); ut_a(trx); - vtq_query_t* q = &trx->vtq_query; - if (q->trx_id == in_trx_id) { - innobase_get_vtq_ts_result(thd, q, out, field); + vtq_record_t &cached = trx->vtq_query.result; + + if (cached.trx_id == in_trx_id) { + innobase_vtq_result(thd, cached, out, field); DBUG_RETURN(true); } @@ -23212,24 +23255,201 @@ innobase_get_vtq_ts(THD* thd, MYSQL_TIME *out, ulonglong _in_trx_id, vtq_field_t goto not_found; rec = btr_pcur_get_rec(&pcur); - result_net = rec_get_nth_field_old(rec, DICT_FLD__SYS_VTQ__TRX_ID, &len); - ut_ad(len == 8); - q->trx_id = mach_read_from_8(result_net); + { + const char *err = trx->vtq_query.cache_result(heap, rec); + if (err) { + fprintf(stderr, "InnoDB: vtq_query_trx_id: get VTQ field failed: %s\n", err); + ut_ad(false && "get VTQ field failed"); + goto not_found; + } + } + + if (cached.trx_id != in_trx_id) + goto not_found; + + innobase_vtq_result(thd, cached, out, field); + found = true; + +not_found: + btr_pcur_close(&pcur); + mtr_commit(&mtr); + mem_heap_free(heap); + + DBUG_RETURN(found); +} + +static +inline +trx_id_t rec_get_trx_id(const rec_t* rec, ulint nfield) +{ + ulint len; + const byte* field; + field = rec_get_nth_field_old( + rec, nfield, &len); + + ut_ad(len == sizeof(trx_id_t)); + return mach_read_from_8(field); +} + +static +inline +void rec_get_timeval(const rec_t* rec, ulint nfield, timeval& out) +{ + ulint len; + const byte* field; + field = rec_get_nth_field_old( + rec, nfield, &len); + + ut_ad(len == sizeof(ullong)); + + out.tv_sec = mach_read_from_4(field); + out.tv_usec = mach_read_from_4(field + 4); +} + +inline +const char * +vtq_query_t::cache_result( + mem_heap_t* heap, + const rec_t* rec, + const timeval& _ts_query, + bool _backwards) +{ + prev_query = _ts_query; + backwards = _backwards; + return dict_process_sys_vtq(heap, rec, result); +} + +static +inline +bool +operator== (const timeval &a, const timeval &b) +{ + return a.tv_sec == b.tv_sec && a.tv_usec == b.tv_usec; +} + +static +inline +bool +operator> (const timeval &a, const timeval &b) +{ + return a.tv_sec > b.tv_sec || (a.tv_sec == b.tv_sec && a.tv_usec > b.tv_usec); +} + +static +inline +bool +operator< (const timeval &a, const timeval &b) +{ + return b > a; +} + +UNIV_INTERN +bool +vtq_query_commit_ts(THD* thd, void *out, const MYSQL_TIME &_commit_ts, vtq_field_t field, bool backwards) +{ + trx_t* trx; + btr_pcur_t pcur; + dtuple_t* tuple; + page_cur_mode_t mode; + mtr_t mtr; + mem_heap_t* heap; + uint err; + timeval commit_ts; + timeval rec_ts = { 0, 0 }; + const rec_t *rec, *clust_rec; + dict_index_t* index = dict_sys->vtq_commit_ts_ind; + dict_index_t* clust_index; + bool found = false; - result_net = rec_get_nth_field_old(rec, DICT_FLD__SYS_VTQ__BEGIN_TS, &len); - ut_ad(len == 8); - q->begin_ts.tv_sec = mach_read_from_4(result_net); - q->begin_ts.tv_usec = mach_read_from_4(result_net + 4); + DBUG_ENTER("vtq_query_commit_ts"); + + mode = backwards ? PAGE_CUR_LE : PAGE_CUR_GE; + + trx = thd_to_trx(thd); + ut_a(trx); + + vtq_record_t &cached = trx->vtq_query.result; + timeval &prev_query = trx->vtq_query.prev_query; + bool prev_bwds = trx->vtq_query.backwards; + + commit_ts.tv_usec = _commit_ts.second_part; + commit_ts.tv_sec = thd_get_timezone(thd)->TIME_to_gmt_sec(&_commit_ts, &err); + if (err) { + if (err == ER_WARN_DATA_OUT_OF_RANGE) { + if (_commit_ts.year <= TIMESTAMP_MIN_YEAR) { + commit_ts.tv_usec = 0; + commit_ts.tv_sec = 1; + } else { + ut_ad(_commit_ts.year >= TIMESTAMP_MAX_YEAR); + commit_ts.tv_usec = TIME_MAX_SECOND_PART; + commit_ts.tv_sec = MY_TIME_T_MAX; + } + } else { + DBUG_RETURN(false); + } + } else if (cached.commit_ts == commit_ts || + (prev_query.tv_sec && prev_bwds == backwards && ( + (!backwards && (commit_ts < prev_query) && commit_ts > cached.commit_ts) || + (backwards && (commit_ts > prev_query) && commit_ts < cached.commit_ts)))) + { + innobase_vtq_result(thd, cached, out, field); + DBUG_RETURN(true); + } + + heap = mem_heap_create(0); + + tuple = dtuple_create(heap, 1); + dict_index_copy_types(tuple, index, 1); + dtuple_get_nth_field(tuple, 0)->len = UNIV_SQL_NULL; + set_tuple_col_8(tuple, 0, commit_ts, heap); + + mtr_start_trx(&mtr, trx); + btr_pcur_open_on_user_rec(index, tuple, mode, + BTR_SEARCH_LEAF, &pcur, &mtr); - result_net = rec_get_nth_field_old(rec, DICT_FLD__SYS_VTQ__COMMIT_TS, &len); - ut_ad(len == 8); - q->commit_ts.tv_sec = mach_read_from_4(result_net); - q->commit_ts.tv_usec = mach_read_from_4(result_net + 4); + if (btr_pcur_is_on_user_rec(&pcur)) { + rec = btr_pcur_get_rec(&pcur); + rec_get_timeval(rec, 0, rec_ts); - if (q->trx_id != in_trx_id) + if (rec_ts.tv_sec == commit_ts.tv_sec + && rec_ts.tv_usec == commit_ts.tv_usec) + goto found; + } else { + rec_ts = commit_ts; + } + + if (mode == PAGE_CUR_GE) { + btr_pcur_move_to_prev_user_rec(&pcur, &mtr); + } else { + btr_pcur_move_to_next_user_rec(&pcur, &mtr); + } + + if (!btr_pcur_is_on_user_rec(&pcur)) goto not_found; - innobase_get_vtq_ts_result(thd, q, out, field); + rec = btr_pcur_get_rec(&pcur); +found: + clust_rec = row_get_clust_rec(BTR_SEARCH_LEAF, rec, index, &clust_index, &mtr); + if (!clust_rec) { + fprintf(stderr, "InnoDB: vtq_query_commit_ts: secondary index is out of sync\n"); + ut_ad(false && "secondary index is out of sync"); + goto not_found; + } + + { + const char *err = + trx->vtq_query.cache_result( + heap, + clust_rec, + rec_ts, + backwards); + if (err) { + fprintf(stderr, "InnoDB: vtq_query_commit_ts: get VTQ field failed: %s\n", err); + ut_ad(false && "get VTQ field failed"); + goto not_found; + } + } + innobase_vtq_result(thd, cached, out, field); found = true; not_found: @@ -23239,3 +23459,58 @@ not_found: DBUG_RETURN(found); } + +bool +vtq_trx_sees( + THD *thd, + bool &result, + ulonglong trx_id1, + ulonglong trx_id0, + ulonglong commit_id1, + uchar iso_level1, + ulonglong commit_id0) +{ + DBUG_ENTER("vtq_trx_sees"); + + if (trx_id1 == trx_id0) { + result = false; + DBUG_RETURN(true); + } + + if (trx_id1 == ULONGLONG_MAX || trx_id0 == 0) { + result = true; + DBUG_RETURN(true); + } + + static const char* msg_cant_find = "InnoDB: vtq_trx_sees: can't find COMMIT_ID%c by TRX_ID: %llu\n"; + if (!commit_id1) { + if (!vtq_query_trx_id(thd, NULL, trx_id1, VTQ_ALL)) { + fprintf(stderr, msg_cant_find, '1', trx_id1); + DBUG_RETURN(false); + } + trx_t* trx = thd_to_trx(thd); + ut_ad(trx); + commit_id1 = trx->vtq_query.result.commit_id; + iso_level1 = trx->vtq_query.result.iso_level; + } + + if (!commit_id0) { + if (!vtq_query_trx_id(thd, &commit_id0, trx_id0, VTQ_COMMIT_ID)) { + fprintf(stderr, msg_cant_find, '0', trx_id0); + DBUG_RETURN(false); + } + } + + // Trivial case: TX1 started after TX0 committed + if (trx_id1 > commit_id0 + // Concurrent transactions: TX1 committed after TX0 and TX1 is read (un)committed + || (commit_id1 > commit_id0 && iso_level1 < TRX_ISO_REPEATABLE_READ)) + { + result = true; + } else { + // All other cases: TX1 does not see TX0 + result = false; + } + + DBUG_RETURN(true); +} diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index d3f3cff82f8..436cea7fe4b 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -9669,7 +9669,16 @@ static ST_FIELD_INFO innodb_vtq_fields_info[] = STRUCT_FLD(old_name, ""), STRUCT_FLD(open_method, SKIP_OPEN_TABLE) }, -#define SYS_VTQ_BEGIN_TS 1 +#define SYS_VTQ_COMMIT_ID 1 + { STRUCT_FLD(field_name, "commit_id"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE) }, + +#define SYS_VTQ_BEGIN_TS 2 { STRUCT_FLD(field_name, "begin_ts"), STRUCT_FLD(field_length, 6), STRUCT_FLD(field_type, MYSQL_TYPE_TIMESTAMP), @@ -9678,7 +9687,7 @@ static ST_FIELD_INFO innodb_vtq_fields_info[] = STRUCT_FLD(old_name, ""), STRUCT_FLD(open_method, SKIP_OPEN_TABLE) }, -#define SYS_VTQ_COMMIT_TS 2 +#define SYS_VTQ_COMMIT_TS 3 { STRUCT_FLD(field_name, "commit_ts"), STRUCT_FLD(field_length, 6), STRUCT_FLD(field_type, MYSQL_TYPE_TIMESTAMP), @@ -9687,13 +9696,12 @@ static ST_FIELD_INFO innodb_vtq_fields_info[] = STRUCT_FLD(old_name, ""), STRUCT_FLD(open_method, SKIP_OPEN_TABLE) }, -#define SYS_VTQ_CONCURR_TRX 3 - { STRUCT_FLD(field_name, "concurr_trx"), - // 3 for "..." if list is truncated - STRUCT_FLD(field_length, I_S_MAX_CONCURR_TRX * (TRX_ID_MAX_LEN + 1) + 3), +#define SYS_VTQ_ISO_LEVEL 4 + { STRUCT_FLD(field_name, "iso_level"), + STRUCT_FLD(field_length, 2), STRUCT_FLD(field_type, MYSQL_TYPE_STRING), STRUCT_FLD(value, 0), - STRUCT_FLD(field_flags, MY_I_S_MAYBE_NULL), + STRUCT_FLD(field_flags, 0), STRUCT_FLD(old_name, ""), STRUCT_FLD(open_method, SKIP_OPEN_TABLE) }, @@ -9709,21 +9717,35 @@ int i_s_dict_fill_vtq( /*========================*/ THD* thd, /*!< in: thread */ - ullong col_trx_id, /*!< in: table fields */ - timeval& col_begin_ts, - timeval& col_commit_ts, - char* col_concurr_trx, + vtq_record_t& vtq, /*!< in: table fields */ TABLE* table_to_fill) /*!< in/out: fill this table */ { Field** fields; + const char* iso_level; DBUG_ENTER("i_s_dict_fill_vtq"); fields = table_to_fill->field; - OK(field_store_ullong(fields[SYS_VTQ_TRX_ID], col_trx_id)); - OK(field_store_timeval(fields[SYS_VTQ_BEGIN_TS], col_begin_ts, thd)); - OK(field_store_timeval(fields[SYS_VTQ_COMMIT_TS], col_commit_ts, thd)); - OK(field_store_string(fields[SYS_VTQ_CONCURR_TRX], col_concurr_trx)); + switch (vtq.iso_level) { + case TRX_ISO_REPEATABLE_READ: + iso_level = "RR"; + break; + case TRX_ISO_READ_COMMITTED: + iso_level = "RC"; + break; + case TRX_ISO_SERIALIZABLE: + iso_level = "S"; + break; + case TRX_ISO_READ_UNCOMMITTED: + iso_level = "RU"; + break; + } + + OK(field_store_ullong(fields[SYS_VTQ_TRX_ID], vtq.trx_id)); + OK(field_store_ullong(fields[SYS_VTQ_COMMIT_ID], vtq.commit_id)); + OK(field_store_timeval(fields[SYS_VTQ_BEGIN_TS], vtq.begin_ts, thd)); + OK(field_store_timeval(fields[SYS_VTQ_COMMIT_TS], vtq.commit_ts, thd)); + OK(field_store_string(fields[SYS_VTQ_ISO_LEVEL], iso_level)); OK(schema_table_store_record(thd, table_to_fill)); @@ -9768,19 +9790,13 @@ i_s_sys_vtq_fill_table( for (int i = 0; rec && i < I_S_SYS_VTQ_LIMIT; ++i) { const char* err_msg; - trx_id_t col_trx_id; - timeval col_begin_ts; - timeval col_commit_ts; - char* col_concurr_trx; + vtq_record_t fields; /* Extract necessary information from SYS_VTQ row */ err_msg = dict_process_sys_vtq( heap, rec, - &col_trx_id, - &col_begin_ts, - &col_commit_ts, - &col_concurr_trx); + fields); mtr_commit(&mtr); mutex_exit(&dict_sys->mutex); @@ -9788,10 +9804,7 @@ i_s_sys_vtq_fill_table( if (!err_msg) { err = i_s_dict_fill_vtq( thd, - col_trx_id, - col_begin_ts, - col_commit_ts, - col_concurr_trx, + fields, tables->table); } else { push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, diff --git a/storage/innobase/include/dict0boot.h b/storage/innobase/include/dict0boot.h index 22b0489386d..bc9fed90f68 100644 --- a/storage/innobase/include/dict0boot.h +++ b/storage/innobase/include/dict0boot.h @@ -325,11 +325,16 @@ enum dict_fld_sys_datafiles_enum { DICT_FLD__SYS_DATAFILES__PATH = 3, DICT_NUM_FIELDS__SYS_DATAFILES = 4 }; + /* The columns in SYS_VTQ */ enum dict_col_sys_vtq_enum { DICT_COL__SYS_VTQ__TRX_ID = 0, - DICT_NUM_COLS__SYS_VTQ = 1 + DICT_COL__SYS_VTQ__COMMIT_ID = 1, + DICT_COL__SYS_VTQ__BEGIN_TS = 2, + DICT_COL__SYS_VTQ__COMMIT_TS = 3, + DICT_COL__SYS_VTQ__ISOLATION_LEVEL = 4, + DICT_NUM_COLS__SYS_VTQ = 5 }; /* The field numbers in the SYS_VTQ clustered index */ enum dict_fld_sys_vtq_enum @@ -337,10 +342,11 @@ enum dict_fld_sys_vtq_enum DICT_FLD__SYS_VTQ__TRX_ID = 0, DICT_FLD__SYS_VTQ__DB_TRX_ID = 1, DICT_FLD__SYS_VTQ__DB_ROLL_PTR = 2, - DICT_FLD__SYS_VTQ__BEGIN_TS = 3, - DICT_FLD__SYS_VTQ__COMMIT_TS = 4, - DICT_FLD__SYS_VTQ__CONCURR_TRX = 5, - DICT_NUM_FIELDS__SYS_VTQ = 6 + DICT_FLD__SYS_VTQ__COMMIT_ID = 3, + DICT_FLD__SYS_VTQ__BEGIN_TS = 4, + DICT_FLD__SYS_VTQ__COMMIT_TS = 5, + DICT_FLD__SYS_VTQ__ISOLATION_LEVEL = 6, + DICT_NUM_FIELDS__SYS_VTQ = 7 }; /* The columns in SYS_VIRTUAL */ diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index 56ca8325d45..6e79c2e4b8b 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -1737,8 +1737,9 @@ struct dict_sys_t{ dict_table_t* sys_columns; /*!< SYS_COLUMNS table */ dict_table_t* sys_indexes; /*!< SYS_INDEXES table */ dict_table_t* sys_fields; /*!< SYS_FIELDS table */ - dict_table_t* sys_virtual; /*!< SYS_VIRTUAL table */ dict_table_t* sys_vtq; /*!< SYS_VTQ table */ + dict_index_t* vtq_commit_ts_ind; + dict_table_t* sys_virtual; /*!< SYS_VIRTUAL table */ /*=============================*/ UT_LIST_BASE_NODE_T(dict_table_t) diff --git a/storage/innobase/include/dict0load.h b/storage/innobase/include/dict0load.h index d9533240c18..a6a69d9aafb 100644 --- a/storage/innobase/include/dict0load.h +++ b/storage/innobase/include/dict0load.h @@ -31,6 +31,7 @@ Created 4/24/1996 Heikki Tuuri #include "univ.i" #include "dict0types.h" #include "trx0types.h" +#include "trx0vtq.h" #include "ut0byte.h" #include "mem0mem.h" #include "btr0types.h" @@ -320,17 +321,14 @@ dict_process_sys_datafiles( This function parses a SYS_VTQ record, extracts necessary information from the record and returns it to the caller. @return error message, or NULL on success */ -#define I_S_MAX_CONCURR_TRX 100 UNIV_INTERN const char* dict_process_sys_vtq( /*=======================*/ mem_heap_t* heap, /*!< in/out: heap memory */ const rec_t* rec, /*!< in: current rec */ -ullong* col_trx_id, /*!< out: field values */ -timeval* col_begin_ts, -timeval* col_commit_ts, -char** col_concurr_trx); +vtq_record_t& fields /*!< out: field values */ +); /** Update the record for space_id in SYS_TABLESPACES to this filepath. @param[in] space_id Tablespace ID diff --git a/storage/innobase/include/row0ins.ic b/storage/innobase/include/row0ins.ic index 7b91e8b3cac..9f951bda2be 100644 --- a/storage/innobase/include/row0ins.ic +++ b/storage/innobase/include/row0ins.ic @@ -25,35 +25,54 @@ Created 4/20/1996 Heikki Tuuri UNIV_INLINE -void set_row_field_8( - dtuple_t* row, - int field_num, +void set_tuple_col_8( + dtuple_t* tuple, + int col, ib_uint64_t data, mem_heap_t* heap) { static const ulint fsize = sizeof(data); - dfield_t* dfield = dtuple_get_nth_field(row, field_num); + dfield_t* dfield = dtuple_get_nth_field(tuple, col); ut_ad(dfield->type.len == fsize); if (dfield->len == UNIV_SQL_NULL) { byte* buf = reinterpret_cast(mem_heap_alloc(heap, fsize)); dfield_set_data(dfield, buf, fsize); } + ut_ad(dfield->len == dfield->type.len && dfield->data); mach_write_to_8(dfield->data, data); } UNIV_INLINE -void set_row_field_8( - dtuple_t* row, - int field_num, +void set_tuple_col_8( + dtuple_t* tuple, + int col, timeval& data, mem_heap_t* heap) { - dfield_t* dfield = dtuple_get_nth_field(row, field_num); + dfield_t* dfield = dtuple_get_nth_field(tuple, col); ut_ad(dfield->type.len == 8); if (dfield->len == UNIV_SQL_NULL) { byte* buf = reinterpret_cast(mem_heap_alloc(heap, 8)); dfield_set_data(dfield, buf, 8); } + ut_ad(dfield->len == dfield->type.len && dfield->data); mach_write_to_4(reinterpret_cast(dfield->data), (ulint) data.tv_sec); mach_write_to_4(reinterpret_cast(dfield->data) + 4, (ulint) data.tv_usec); } + +UNIV_INLINE +void set_tuple_col_1( + dtuple_t* tuple, + int col, + byte data, + mem_heap_t* heap) +{ + dfield_t* dfield = dtuple_get_nth_field(tuple, col); + ut_ad(dfield->type.len == 1); + if (dfield->len == UNIV_SQL_NULL) { + byte* buf = reinterpret_cast(mem_heap_alloc(heap, 1)); + dfield_set_data(dfield, buf, 1); + } + ut_ad(dfield->len == dfield->type.len && dfield->data); + *(byte*)(dfield->data) = data; +} diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 995929b957c..dd8d1bd524c 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -42,6 +42,7 @@ Created 3/26/1996 Heikki Tuuri #include "que0types.h" #include "mem0mem.h" #include "trx0xa.h" +#include "trx0vtq.h" #include "ut0vec.h" #include "fts0fts.h" #include "srv0srv.h" @@ -829,13 +830,6 @@ typedef enum { TRX_WSREP_ABORT = 1 } trx_abort_t; -struct vtq_query_t -{ - trx_id_t trx_id; - timeval begin_ts; - timeval commit_ts; -}; - /** Represents an instance of rollback segment along with its state variables.*/ struct trx_undo_ptr_t { trx_rseg_t* rseg; /*!< rollback segment assigned to the @@ -1277,8 +1271,6 @@ struct trx_t { bool vtq_notify_on_commit; /*!< Notify VTQ for System Versioned update */ vtq_query_t vtq_query; - trx_id_t* vtq_concurr_trx; - ulint vtq_concurr_n; ulint magic_n; /** @return whether any persistent undo log has been generated */ diff --git a/storage/innobase/include/trx0vtq.h b/storage/innobase/include/trx0vtq.h new file mode 100644 index 00000000000..5767dfeb5a0 --- /dev/null +++ b/storage/innobase/include/trx0vtq.h @@ -0,0 +1,40 @@ +#ifndef trx0vtq_h +#define trx0vtq_h + +/* Copyright (c) 2016, MariaDB Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ + +#include +#include "trx0types.h" +#include "mem0mem.h" +#include "rem0types.h" + +class vtq_query_t +{ +public: + timeval prev_query; + bool backwards; + + vtq_record_t result; + + const char * cache_result(mem_heap_t* heap, const rec_t* rec); + const char * cache_result( + mem_heap_t* heap, + const rec_t* rec, + const timeval &_ts_query, + bool _backwards); +}; + +#endif // trx0vtq_h diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index ef30a434bf6..40d3eccdc34 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -3905,7 +3905,7 @@ Inserts a row to SYS_VTQ, low level. code */ static __attribute__((nonnull, warn_unused_result)) dberr_t -vers_row_ins_vtq_low(trx_t* trx, mem_heap_t* heap, dtuple_t* row) +vers_row_ins_vtq_low(trx_t* trx, mem_heap_t* heap, dtuple_t* tuple) { dberr_t err; dtuple_t* entry; @@ -3916,7 +3916,7 @@ vers_row_ins_vtq_low(trx_t* trx, mem_heap_t* heap, dtuple_t* row) | BTR_NO_LOCKING_FLAG | BTR_NO_UNDO_LOG_FLAG); - entry = row_build_index_entry(row, NULL, index, heap); + entry = row_build_index_entry(tuple, NULL, index, heap); dfield_t* dfield = dtuple_get_nth_field(entry, DATA_TRX_ID); ut_ad(dfield->type.len == DATA_TRX_ID_LEN); @@ -3946,12 +3946,12 @@ vers_row_ins_vtq_low(trx_t* trx, mem_heap_t* heap, dtuple_t* row) n_index++; - entry = row_build_index_entry(row, NULL, index, heap); + entry = row_build_index_entry(tuple, NULL, index, heap); err = row_ins_sec_index_entry_low( flags, BTR_MODIFY_TREE, index, offsets_heap, heap, entry, trx->id, NULL, false, trx); } while (err == DB_SUCCESS); - ut_ad(n_index == 2 || err != DB_SUCCESS); + ut_ad(n_index == 3 || err != DB_SUCCESS); mem_heap_free(offsets_heap); return err; @@ -3964,31 +3964,26 @@ void vers_notify_vtq(trx_t* trx) { dberr_t err; mem_heap_t* heap = mem_heap_create(1024); - dtuple_t* row = dtuple_create(heap, dict_table_get_n_cols(dict_sys->sys_vtq)); + dtuple_t* tuple = dtuple_create(heap, dict_table_get_n_cols(dict_sys->sys_vtq)); timeval begin_ts, commit_ts; begin_ts.tv_sec = trx->start_time; begin_ts.tv_usec = trx->start_time_micro; - ut_usectime((ulong*)&commit_ts.tv_sec, (ulong*)&commit_ts.tv_usec); - dict_table_copy_types(row, dict_sys->sys_vtq); - set_row_field_8(row, DICT_FLD__SYS_VTQ__TRX_ID, trx->id, heap); - set_row_field_8(row, DICT_FLD__SYS_VTQ__BEGIN_TS - 2, begin_ts, heap); - set_row_field_8(row, DICT_FLD__SYS_VTQ__COMMIT_TS - 2, commit_ts, heap); + mutex_enter(&trx_sys->mutex); + trx_id_t commit_id = trx_sys_get_new_trx_id(); + ut_usectime((ulint *)&commit_ts.tv_sec, (ulint *)&commit_ts.tv_usec); + mutex_exit(&trx_sys->mutex); - dfield_t* dfield = dtuple_get_nth_field(row, DICT_FLD__SYS_VTQ__CONCURR_TRX - 2); - ulint count = 0; - byte* buf = NULL; - if (trx->vtq_concurr_n > 0) { - buf = static_cast(mem_heap_alloc(heap, trx->vtq_concurr_n * 8)); - for (byte* ptr = buf; count < trx->vtq_concurr_n; ++count) { - mach_write_to_8(ptr, trx->vtq_concurr_trx[count]); - ptr += 8; - } - } - dfield_set_data(dfield, buf, count * 8); + dict_table_copy_types(tuple, dict_sys->sys_vtq); + set_tuple_col_8(tuple, DICT_COL__SYS_VTQ__TRX_ID, trx->id, heap); + set_tuple_col_8(tuple, DICT_COL__SYS_VTQ__COMMIT_ID, commit_id, heap); + set_tuple_col_8(tuple, DICT_COL__SYS_VTQ__BEGIN_TS, begin_ts, heap); + set_tuple_col_8(tuple, DICT_COL__SYS_VTQ__COMMIT_TS, commit_ts, heap); + ut_ad(trx->isolation_level < 256); + set_tuple_col_1(tuple, DICT_COL__SYS_VTQ__ISOLATION_LEVEL, trx->isolation_level, heap); - err = vers_row_ins_vtq_low(trx, heap, row); + err = vers_row_ins_vtq_low(trx, heap, tuple); if (DB_SUCCESS != err) fprintf(stderr, "InnoDB: failed to insert VTQ record (error %d)\n", err); diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 60b221a4e4a..5edf3c1af54 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -1495,15 +1495,15 @@ row_insert_for_mysql( ut_ad(t->mysql_col_len == 8); if (historical) { - set_row_field_8(node->row, table->vers_row_end, trx->id, node->entry_sys_heap); + set_tuple_col_8(node->row, table->vers_row_end, trx->id, node->entry_sys_heap); int8store(&mysql_rec[t->mysql_col_offset], trx->id); } else { - set_row_field_8(node->row, table->vers_row_end, IB_UINT64_MAX, node->entry_sys_heap); + set_tuple_col_8(node->row, table->vers_row_end, IB_UINT64_MAX, node->entry_sys_heap); int8store(&mysql_rec[t->mysql_col_offset], IB_UINT64_MAX); t = &prebuilt->mysql_template[table->vers_row_start]; ut_ad(t->mysql_col_len == 8); - set_row_field_8(node->row, table->vers_row_start, trx->id, node->entry_sys_heap); + set_tuple_col_8(node->row, table->vers_row_start, trx->id, node->entry_sys_heap); int8store(&mysql_rec[t->mysql_col_offset], trx->id); } } diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 7e1666c1703..7298fc62b4c 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -316,10 +316,6 @@ struct TrxFactory { trx->lock.table_locks.~lock_pool_t(); trx->hit_list.~hit_list_t(); - - if (trx->vtq_concurr_trx) { - ut_free(trx->vtq_concurr_trx); - } } /** Enforce any invariants here, this is called before the transaction @@ -1332,13 +1328,6 @@ trx_start_low( || srv_read_only_mode || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO); - if (UT_LIST_GET_LEN(trx_sys->rw_trx_list) > 0) { - trx->vtq_concurr_trx = static_cast( - ut_malloc_nokey(UT_LIST_GET_LEN(trx_sys->rw_trx_list) * sizeof(trx_id_t))); - copy_trx_ids f(trx->vtq_concurr_trx, trx->vtq_concurr_n); - ut_list_map(trx_sys->rw_trx_list, f); - } - UT_LIST_ADD_FIRST(trx_sys->rw_trx_list, trx); ut_d(trx->in_rw_trx_list = true); -- cgit v1.2.1 From a5feb98c47786e3825ec324d0d3bb403da448d4e Mon Sep 17 00:00:00 2001 From: Kosov Eugene Date: Sun, 13 Nov 2016 18:37:03 +0300 Subject: Scripts: collect and reprint warnings Closes #73 --- BUILD/capture_warnings.sh | 17 +++++++++++++++++ CMakeLists.txt | 14 ++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 BUILD/capture_warnings.sh diff --git a/BUILD/capture_warnings.sh b/BUILD/capture_warnings.sh new file mode 100644 index 00000000000..88fd2576c05 --- /dev/null +++ b/BUILD/capture_warnings.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +warn_path=$1 +shift +warn_file="$warn_path/compile.warnings" + +set -o pipefail +exec 3>&1 +x=$(("$@" >&2) 2>&1 1>&3) +error=${PIPESTATUS} + +if ! [[ -z "$x" ]]; then + echo -n "$x" >> $warn_file + echo -n "$x" >&2 +fi + +exit ${error} diff --git a/CMakeLists.txt b/CMakeLists.txt index 869e65baf8d..a1dea914043 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -480,3 +480,17 @@ IF(NON_DISTRIBUTABLE_WARNING) MESSAGE(WARNING " You have linked MariaDB with GPLv3 libraries! You may not distribute the resulting binary. If you do, you will put yourself into a legal problem with Free Software Foundation.") ENDIF() + +IF (CMAKE_BUILD_TYPE MATCHES "Debug") + SET_DIRECTORY_PROPERTIES(PROPERTIES RULE_LAUNCH_COMPILE + "bash ${CMAKE_SOURCE_DIR}/BUILD/capture_warnings.sh ${CMAKE_BINARY_DIR}") + SET_DIRECTORY_PROPERTIES(PROPERTY ADDITIONAL_MAKE_CLEAN_FILES + "${CMAKE_BINARY_DIR}/compile.warnings") + ADD_CUSTOM_TARGET(REMOVE_WARNINGS_FILE ALL + COMMAND rm -f "compile.warnings" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + ADD_CUSTOM_TARGET(REPRINT ALL + COMMAND if [ -f "compile.warnings" ]; then cat "compile.warnings" \; fi + DEPENDS mysql udf_example explain_filename-t REMOVE_WARNINGS_FILE + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}") +ENDIF() -- cgit v1.2.1 From be0f58697209e6da2b7ccc6fecaf83e5aaddca5a Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 16 Nov 2016 13:05:40 +0000 Subject: Scripts: print warnings fixes --- BUILD/capture_warnings.sh | 13 +++++++------ CMakeLists.txt | 14 +------------- cmake/print_warnings.cmake | 13 +++++++++++++ 3 files changed, 21 insertions(+), 19 deletions(-) mode change 100644 => 100755 BUILD/capture_warnings.sh create mode 100644 cmake/print_warnings.cmake diff --git a/BUILD/capture_warnings.sh b/BUILD/capture_warnings.sh old mode 100644 new mode 100755 index 88fd2576c05..c101493a09e --- a/BUILD/capture_warnings.sh +++ b/BUILD/capture_warnings.sh @@ -3,15 +3,16 @@ warn_path=$1 shift warn_file="$warn_path/compile.warnings" +suppress_file="$warn_path/suppress.warnings" -set -o pipefail exec 3>&1 -x=$(("$@" >&2) 2>&1 1>&3) -error=${PIPESTATUS} +cmderr=$("$@" 2>&1 1>&3) +error=$? -if ! [[ -z "$x" ]]; then - echo -n "$x" >> $warn_file - echo -n "$x" >&2 +if [[ -n "$cmderr" ]]; then + echo "$cmderr" >&2 + [[ "$cmderr" =~ warning:(.+)$ ]] && + echo -n "$cmderr" >> "$warn_file" fi exit ${error} diff --git a/CMakeLists.txt b/CMakeLists.txt index a1dea914043..2673b3fdc4e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -481,16 +481,4 @@ IF(NON_DISTRIBUTABLE_WARNING) You have linked MariaDB with GPLv3 libraries! You may not distribute the resulting binary. If you do, you will put yourself into a legal problem with Free Software Foundation.") ENDIF() -IF (CMAKE_BUILD_TYPE MATCHES "Debug") - SET_DIRECTORY_PROPERTIES(PROPERTIES RULE_LAUNCH_COMPILE - "bash ${CMAKE_SOURCE_DIR}/BUILD/capture_warnings.sh ${CMAKE_BINARY_DIR}") - SET_DIRECTORY_PROPERTIES(PROPERTY ADDITIONAL_MAKE_CLEAN_FILES - "${CMAKE_BINARY_DIR}/compile.warnings") - ADD_CUSTOM_TARGET(REMOVE_WARNINGS_FILE ALL - COMMAND rm -f "compile.warnings" - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) - ADD_CUSTOM_TARGET(REPRINT ALL - COMMAND if [ -f "compile.warnings" ]; then cat "compile.warnings" \; fi - DEPENDS mysql udf_example explain_filename-t REMOVE_WARNINGS_FILE - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}") -ENDIF() +INCLUDE(${CMAKE_SOURCE_DIR}/cmake/print_warnings.cmake) diff --git a/cmake/print_warnings.cmake b/cmake/print_warnings.cmake new file mode 100644 index 00000000000..d88d86b189b --- /dev/null +++ b/cmake/print_warnings.cmake @@ -0,0 +1,13 @@ +IF (CMAKE_BUILD_TYPE MATCHES "Debug") + SET_DIRECTORY_PROPERTIES(PROPERTIES RULE_LAUNCH_COMPILE + "bash ${CMAKE_SOURCE_DIR}/BUILD/capture_warnings.sh ${CMAKE_BINARY_DIR}") + SET_DIRECTORY_PROPERTIES(PROPERTY ADDITIONAL_MAKE_CLEAN_FILES + "${CMAKE_BINARY_DIR}/compile.warnings") + ADD_CUSTOM_TARGET(rm_compile.warnings ALL + COMMAND rm -f compile.warnings + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + ADD_CUSTOM_TARGET(print_warnings ALL + COMMAND bash -c '[ -f compile.warnings ] && { echo "Warnings found:" \; cat compile.warnings \; echo "" \; } \; true' + DEPENDS mysql udf_example explain_filename-t rm_compile.warnings + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}") +ENDIF() -- cgit v1.2.1 From 52a6812595be85f5a18c0bca6c6f003f3cca84a4 Mon Sep 17 00:00:00 2001 From: kevg Date: Sat, 19 Nov 2016 13:59:12 +0300 Subject: Scripts: flag to disable warnings reprinting --- cmake/print_warnings.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/print_warnings.cmake b/cmake/print_warnings.cmake index d88d86b189b..a697e1bd11f 100644 --- a/cmake/print_warnings.cmake +++ b/cmake/print_warnings.cmake @@ -1,4 +1,4 @@ -IF (CMAKE_BUILD_TYPE MATCHES "Debug") +IF (NOT DEFINED WITHOUT_REPRINT AND CMAKE_BUILD_TYPE MATCHES "Debug") SET_DIRECTORY_PROPERTIES(PROPERTIES RULE_LAUNCH_COMPILE "bash ${CMAKE_SOURCE_DIR}/BUILD/capture_warnings.sh ${CMAKE_BINARY_DIR}") SET_DIRECTORY_PROPERTIES(PROPERTY ADDITIONAL_MAKE_CLEAN_FILES -- cgit v1.2.1 From 303d72a0f411fa8094d69ef6300966c5d13bd595 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Sat, 19 Nov 2016 12:29:07 +0000 Subject: SQL: redundant error codes reduced Replaced codes: ER_NO_VERSIONED_FIELDS_IN_VERSIONED_TABLE ER_MISSING_WITH_SYSTEM_VERSIONING ER_SYS_START_NOT_SPECIFIED ER_SYS_END_NOT_SPECIFIED ER_MISSING_PERIOD_FOR_SYSTEM_TIME ER_PERIOD_FOR_SYSTEM_TIME_CONTAINS_WRONG_START_COLUMN ER_PERIOD_FOR_SYSTEM_TIME_CONTAINS_WRONG_END_COLUMN ER_SYS_START_AND_SYS_END_SAME ER_SYS_START_MORE_THAN_ONCE ER_SYS_END_MORE_THAN_ONCE with: ER_VERS_WRONG_PARAMS ER_VERS_FIELD_WRONG_TYPE --- mysql-test/suite/versioning/r/create.result | 32 ++++----- .../suite/versioning/r/optimized_fields.result | 20 +++--- mysql-test/suite/versioning/t/create.test | 32 ++++----- sql/handler.cc | 75 ++++++++++------------ sql/handler.h | 6 +- sql/share/errmsg-utf8.txt | 44 ++----------- sql/sql_parse.cc | 7 +- sql/sql_table.cc | 17 ----- sql/sql_yacc.yy | 14 ++-- sql/table.cc | 8 +-- 10 files changed, 104 insertions(+), 151 deletions(-) diff --git a/mysql-test/suite/versioning/r/create.result b/mysql-test/suite/versioning/r/create.result index 0238d189690..ea3c791cc23 100644 --- a/mysql-test/suite/versioning/r/create.result +++ b/mysql-test/suite/versioning/r/create.result @@ -32,14 +32,14 @@ Sys_start2 timestamp(6) generated always as row start, Sys_end timestamp(6) generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning; -ERROR HY000: 'Generated as row start' specified more than once +ERROR HY000: Wrong parameters for versioned table `t1`: multiple 'GENERATED ALWAYS AS ROW START' create or replace table t1 ( XNo int unsigned, Sys_start timestamp(6) generated always as row start, Sys_end2 timestamp(6) generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning; -ERROR HY000: Second column in 'period for system time' must be equal to 'generated as row end' column +ERROR HY000: Wrong parameters for versioned table `t1`: 'PERIOD FOR SYSTEM_TIME' and 'GENERATED AS ROW END' mismatch create or replace table t1 ( XNo int unsigned, Sys_start timestamp(6) generated always as row start, @@ -47,12 +47,12 @@ Sys_end timestamp(6) generated always as row end, Sys_end2 timestamp(6) generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning; -ERROR HY000: Generated as row end specified more than once +ERROR HY000: Wrong parameters for versioned table `t1`: multiple 'GENERATED ALWAYS AS ROW END' create or replace table t1 ( XNo int unsigned, period for system_time (Sys_start, Sys_end) ) with system versioning; -ERROR HY000: 'Generated as row start' not specified +ERROR HY000: Wrong parameters for versioned table `t1`: 'GENERATED AS ROW START' column missing create or replace table t1 ( XNo int unsigned, Sys_start timestamp(6) generated always as row start, @@ -60,63 +60,63 @@ Sys_end timestamp(6) generated always as row end, Sys_end2 timestamp(6) generated always as row end, period for system_time (Sys_start, Sys_end) ); -ERROR HY000: Generated as row end specified more than once +ERROR HY000: Wrong parameters for versioned table `t1`: multiple 'GENERATED ALWAYS AS ROW END' create or replace table t1 ( XNo int unsigned, Sys_start timestamp(6) generated always as row start, Sys_end timestamp(6) generated always as row end, period for system_time (sys_insert, sys_remove) ) with system versioning; -ERROR HY000: First column in 'period for system time' must be equal to 'generated as row start' column +ERROR HY000: Wrong parameters for versioned table `t1`: 'PERIOD FOR SYSTEM_TIME' and 'GENERATED AS ROW START' mismatch create or replace table t1 ( XNo int unsigned, Sys_start timestamp(6) generated always as row start, Sys_end timestamp(6) generated always as row end, period for system_time (Sys_start, Sys_end) ); -ERROR HY000: 'With system versioning' is missing +ERROR HY000: Wrong parameters for versioned table `t1`: 'WITH SYSTEM VERSIONING' missing create or replace table t1 ( XNo int unsigned, Sys_start timestamp(6) generated always as row start, Sys_end timestamp(6) generated always as row end, period for system_time (Sys_start, Sys_start) ); -ERROR HY000: 'Period for system_time' must contain two different columns +ERROR HY000: Wrong parameters for versioned table `t1`: 'PERIOD FOR SYSTEM_TIME' columns must be different create or replace table t1 ( XNo int unsigned, Sys_start int generated always as row start, Sys_end timestamp(6) generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning; -ERROR HY000: System start field must be of type TIMESTAMP +ERROR HY000: `Sys_start` must be of type `TIMESTAMP` for versioned table `t1` create or replace table t1 ( XNo int unsigned, Sys_start timestamp(6) generated always as row start, Sys_end int generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning; -ERROR HY000: System end field must be of type TIMESTAMP +ERROR HY000: `Sys_end` must be of type `TIMESTAMP` for versioned table `t1` create or replace table t1 ( XNo int unsigned, Sys_start timestamp(6) generated always as row start, Sys_end bigint generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning engine innodb; -ERROR HY000: System start field must be of type BIGINT UNSIGNED +ERROR HY000: `Sys_start` must be of type `BIGINT UNSIGNED` for versioned table `t1` create or replace table t1 ( XNo int unsigned, Sys_start bigint generated always as row start, Sys_end bigint generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning engine innodb; -ERROR HY000: System start field must be of type BIGINT UNSIGNED +ERROR HY000: `Sys_start` must be of type `BIGINT UNSIGNED` for versioned table `t1` create or replace table t1 ( XNo int unsigned, Sys_start bigint unsigned generated always as row start, Sys_end bigint generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning engine innodb; -ERROR HY000: System end field must be of type BIGINT UNSIGNED +ERROR HY000: `Sys_end` must be of type `BIGINT UNSIGNED` for versioned table `t1` create or replace table t1 ( A int with system versioning, B int @@ -147,7 +147,7 @@ create or replace table t1 ( A int, B int without system versioning ); -ERROR HY000: Every field specified unversioned in versioned table +ERROR HY000: Wrong parameters for versioned table `t1`: 'WITH SYSTEM VERSIONING' missing create or replace table t1 ( A int, B int without system versioning @@ -190,9 +190,9 @@ t1 CREATE TABLE `t1` ( create or replace table t1 ( A int without system versioning ); -ERROR HY000: Every field specified unversioned in versioned table +ERROR HY000: Wrong parameters for versioned table `t1`: 'WITH SYSTEM VERSIONING' missing create or replace table t1 ( A int without system versioning ) with system versioning; -ERROR HY000: Every field specified unversioned in versioned table +ERROR HY000: Wrong parameters for versioned table `t1`: versioned fields missing drop table t1; diff --git a/mysql-test/suite/versioning/r/optimized_fields.result b/mysql-test/suite/versioning/r/optimized_fields.result index aa1f1d3696b..3fbc8017931 100644 --- a/mysql-test/suite/versioning/r/optimized_fields.result +++ b/mysql-test/suite/versioning/r/optimized_fields.result @@ -17,50 +17,50 @@ a b b+0 1 NULL NULL 3 NULL NULL Warnings: -Warning 4067 Attempt to read unversioned field 'b' in historical query +Warning 4055 Attempt to read unversioned field 'b' in historical query select * from t for system_time as of timestamp now(6); a b 1 NULL 3 NULL Warnings: -Warning 4067 Attempt to read unversioned field 'b' in historical query +Warning 4055 Attempt to read unversioned field 'b' in historical query select count(*) from t group by b for system_time as of timestamp now(6); count(*) 2 Warnings: -Warning 4067 Attempt to read unversioned field 'b' in historical query +Warning 4055 Attempt to read unversioned field 'b' in historical query select * from t for system_time as of timestamp now(6) order by b asc; a b 1 NULL 3 NULL Warnings: -Warning 4067 Attempt to read unversioned field 'b' in historical query +Warning 4055 Attempt to read unversioned field 'b' in historical query select * from t for system_time as of timestamp now(6) order by b desc; a b 1 NULL 3 NULL Warnings: -Warning 4067 Attempt to read unversioned field 'b' in historical query +Warning 4055 Attempt to read unversioned field 'b' in historical query select * from t group by a having a=2 for system_time as of timestamp now(6); a b Warnings: -Warning 4067 Attempt to read unversioned field 'b' in historical query +Warning 4055 Attempt to read unversioned field 'b' in historical query select * from t group by b having b=2 for system_time as of timestamp now(6); a b Warnings: -Warning 4067 Attempt to read unversioned field 'b' in historical query +Warning 4055 Attempt to read unversioned field 'b' in historical query select a from t where b=2 for system_time as of timestamp now(6); a Warnings: -Warning 4067 Attempt to read unversioned field 'b' in historical query +Warning 4055 Attempt to read unversioned field 'b' in historical query select a from t where b=NULL for system_time as of timestamp now(6); a Warnings: -Warning 4067 Attempt to read unversioned field 'b' in historical query +Warning 4055 Attempt to read unversioned field 'b' in historical query select count(*), b from t group by b having b=NULL for system_time as of timestamp now(6); count(*) b Warnings: -Warning 4067 Attempt to read unversioned field 'b' in historical query +Warning 4055 Attempt to read unversioned field 'b' in historical query select a, b from t; a b 1 2 diff --git a/mysql-test/suite/versioning/t/create.test b/mysql-test/suite/versioning/t/create.test index 098f71087dc..4310b57d90b 100644 --- a/mysql-test/suite/versioning/t/create.test +++ b/mysql-test/suite/versioning/t/create.test @@ -18,7 +18,7 @@ create or replace table t1 ( ) with system versioning; show create table t1; ---error ER_SYS_START_MORE_THAN_ONCE +--error ER_VERS_WRONG_PARAMS create or replace table t1 ( XNo int unsigned, Sys_start timestamp(6) generated always as row start, @@ -27,7 +27,7 @@ create or replace table t1 ( period for system_time (Sys_start, Sys_end) ) with system versioning; ---error ER_PERIOD_FOR_SYSTEM_TIME_CONTAINS_WRONG_END_COLUMN +--error ER_VERS_WRONG_PARAMS create or replace table t1 ( XNo int unsigned, Sys_start timestamp(6) generated always as row start, @@ -35,7 +35,7 @@ create or replace table t1 ( period for system_time (Sys_start, Sys_end) ) with system versioning; ---error ER_SYS_END_MORE_THAN_ONCE +--error ER_VERS_WRONG_PARAMS create or replace table t1 ( XNo int unsigned, Sys_start timestamp(6) generated always as row start, @@ -44,13 +44,13 @@ create or replace table t1 ( period for system_time (Sys_start, Sys_end) ) with system versioning; ---error ER_SYS_START_NOT_SPECIFIED +--error ER_VERS_WRONG_PARAMS create or replace table t1 ( XNo int unsigned, period for system_time (Sys_start, Sys_end) ) with system versioning; ---error ER_SYS_END_MORE_THAN_ONCE +--error ER_VERS_WRONG_PARAMS create or replace table t1 ( XNo int unsigned, Sys_start timestamp(6) generated always as row start, @@ -59,7 +59,7 @@ create or replace table t1 ( period for system_time (Sys_start, Sys_end) ); ---error ER_PERIOD_FOR_SYSTEM_TIME_CONTAINS_WRONG_START_COLUMN +--error ER_VERS_WRONG_PARAMS create or replace table t1 ( XNo int unsigned, Sys_start timestamp(6) generated always as row start, @@ -67,7 +67,7 @@ create or replace table t1 ( period for system_time (sys_insert, sys_remove) ) with system versioning; ---error ER_MISSING_WITH_SYSTEM_VERSIONING +--error ER_VERS_WRONG_PARAMS create or replace table t1 ( XNo int unsigned, Sys_start timestamp(6) generated always as row start, @@ -75,7 +75,7 @@ create or replace table t1 ( period for system_time (Sys_start, Sys_end) ); ---error ER_SYS_START_AND_SYS_END_SAME +--error ER_VERS_WRONG_PARAMS create or replace table t1 ( XNo int unsigned, Sys_start timestamp(6) generated always as row start, @@ -83,7 +83,7 @@ create or replace table t1 ( period for system_time (Sys_start, Sys_start) ); ---error ER_SYS_START_FIELD_MUST_BE_TIMESTAMP +--error ER_VERS_FIELD_WRONG_TYPE create or replace table t1 ( XNo int unsigned, Sys_start int generated always as row start, @@ -91,7 +91,7 @@ create or replace table t1 ( period for system_time (Sys_start, Sys_end) ) with system versioning; ---error ER_SYS_END_FIELD_MUST_BE_TIMESTAMP +--error ER_VERS_FIELD_WRONG_TYPE create or replace table t1 ( XNo int unsigned, Sys_start timestamp(6) generated always as row start, @@ -99,7 +99,7 @@ create or replace table t1 ( period for system_time (Sys_start, Sys_end) ) with system versioning; ---error ER_SYS_START_FIELD_MUST_BE_BIGINT +--error ER_VERS_FIELD_WRONG_TYPE create or replace table t1 ( XNo int unsigned, Sys_start timestamp(6) generated always as row start, @@ -107,7 +107,7 @@ create or replace table t1 ( period for system_time (Sys_start, Sys_end) ) with system versioning engine innodb; ---error ER_SYS_START_FIELD_MUST_BE_BIGINT +--error ER_VERS_FIELD_WRONG_TYPE create or replace table t1 ( XNo int unsigned, Sys_start bigint generated always as row start, @@ -115,7 +115,7 @@ create or replace table t1 ( period for system_time (Sys_start, Sys_end) ) with system versioning engine innodb; ---error ER_SYS_END_FIELD_MUST_BE_BIGINT +--error ER_VERS_FIELD_WRONG_TYPE create or replace table t1 ( XNo int unsigned, Sys_start bigint unsigned generated always as row start, @@ -135,7 +135,7 @@ create or replace table t1 ( ) with system versioning; show create table t1; ---error ER_NO_VERSIONED_FIELDS_IN_VERSIONED_TABLE +--error ER_VERS_WRONG_PARAMS create or replace table t1 ( A int, B int without system versioning @@ -159,12 +159,12 @@ create or replace table t1 ( ) with system versioning; show create table t1; ---error ER_NO_VERSIONED_FIELDS_IN_VERSIONED_TABLE +--error ER_VERS_WRONG_PARAMS create or replace table t1 ( A int without system versioning ); ---error ER_NO_VERSIONED_FIELDS_IN_VERSIONED_TABLE +--error ER_VERS_WRONG_PARAMS create or replace table t1 ( A int without system versioning ) with system versioning; diff --git a/sql/handler.cc b/sql/handler.cc index 0badaa3fa24..c62dcb067be 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6593,15 +6593,11 @@ static bool create_sys_trx_field(THD *thd, const char *field_name, return false; } -bool Vers_parse_info::add_versioning_info( +bool Vers_parse_info::fix_implicit( THD *thd, Alter_info *alter_info, bool integer_fields) { - if (!declared_system_versioning && !has_versioned_fields) - return false; - - bool without_system_versioning_by_default= !declared_system_versioning; List_iterator it(alter_info->create_list); while (Create_field *f= it++) { @@ -6615,11 +6611,11 @@ bool Vers_parse_info::add_versioning_info( continue; if (f->versioning == Column_definition::VERSIONING_NOT_SET && - without_system_versioning_by_default) - f->flags|= VERS_OPTIMIZED_UPDATE_FLAG; - - else if (f->versioning == Column_definition::WITHOUT_VERSIONING) + !declared_system_versioning || + f->versioning == Column_definition::WITHOUT_VERSIONING) + { f->flags|= VERS_OPTIMIZED_UPDATE_FLAG; + } } // If user specified some of these he must specify the others too. Do nothing. @@ -6637,7 +6633,11 @@ bool Vers_parse_info::add_versioning_info( "sys_trx_end"); } -bool Vers_parse_info::check(THD *thd, Alter_info *alter_info, bool integer_fields) +bool Vers_parse_info::check_and_fix_implicit( + THD *thd, + Alter_info *alter_info, + bool integer_fields, + const char* table_name) { if (!( has_versioned_fields || @@ -6651,10 +6651,14 @@ bool Vers_parse_info::check(THD *thd, Alter_info *alter_info, bool integer_field return false; } - if (add_versioning_info(thd, alter_info, integer_fields)) + if (!declared_system_versioning && !has_versioned_fields) + { + my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, "'WITH SYSTEM VERSIONING' missing"); return true; + } - bool r= false; + if (fix_implicit(thd, alter_info, integer_fields)) + return true; { int not_set= 0; @@ -6685,51 +6689,42 @@ bool Vers_parse_info::check(THD *thd, Alter_info *alter_info, bool integer_field if ((table_with_system_versioning && not_set == 0 && with == 0) || (!table_with_system_versioning && with == 0)) { - r= true; - my_error(ER_NO_VERSIONED_FIELDS_IN_VERSIONED_TABLE, MYF(0)); + my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, "versioned fields missing"); + return true; } } - if (!declared_system_versioning && !has_versioned_fields) - { - r= true; - my_error(ER_MISSING_WITH_SYSTEM_VERSIONING, MYF(0)); - } - if (!generated_as_row.start) { - r= true; - my_error(ER_SYS_START_NOT_SPECIFIED, MYF(0)); + my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, "'GENERATED AS ROW START' column missing"); + return true; } if (!generated_as_row.end) { - r= true; - my_error(ER_SYS_END_NOT_SPECIFIED, MYF(0)); + my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, "'GENERATED AS ROW END' column missing"); + return true; } if (!period_for_system_time.start || !period_for_system_time.end) { - r= true; - my_error(ER_MISSING_PERIOD_FOR_SYSTEM_TIME, MYF(0)); + my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, "'PERIOD FOR SYSTEM_TIME' missing"); + return true; } - if (!r) + if (my_strcasecmp(system_charset_info, generated_as_row.start->c_ptr(), + period_for_system_time.start->c_ptr())) { - if (my_strcasecmp(system_charset_info, generated_as_row.start->c_ptr(), - period_for_system_time.start->c_ptr())) - { - r= true; - my_error(ER_PERIOD_FOR_SYSTEM_TIME_CONTAINS_WRONG_START_COLUMN, MYF(0)); - } + my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, "'PERIOD FOR SYSTEM_TIME' and 'GENERATED AS ROW START' mismatch"); + return true; + } - if (my_strcasecmp(system_charset_info, generated_as_row.end->c_ptr(), - period_for_system_time.end->c_ptr())) - { - r= true; - my_error(ER_PERIOD_FOR_SYSTEM_TIME_CONTAINS_WRONG_END_COLUMN, MYF(0)); - } + if (my_strcasecmp(system_charset_info, generated_as_row.end->c_ptr(), + period_for_system_time.end->c_ptr())) + { + my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, "'PERIOD FOR SYSTEM_TIME' and 'GENERATED AS ROW END' mismatch"); + return true; } - return r; // false means no error + return false; } diff --git a/sql/handler.h b/sql/handler.h index 964880b0b62..394d6276e4f 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1697,8 +1697,10 @@ struct Vers_parse_info period_for_system_time.end = end; } - bool add_versioning_info(THD *thd, Alter_info *alter_info, bool integer_fields); - bool check(THD *thd, Alter_info *alter_info, bool integer_fields); +private: + bool fix_implicit(THD *thd, Alter_info *alter_info, bool integer_fields); +public: + bool check_and_fix_implicit(THD *thd, Alter_info *alter_info, bool integer_fields, const char* table_name); /** User has added 'WITH SYSTEM VERSIONING' to table definition */ bool declared_system_versioning : 1; diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index e39677765a2..c8615943ff2 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7487,56 +7487,20 @@ ER_UNKNOWN_VIEW 42S02 # MariaDB error numbers related to System Versioning -ER_SYS_START_NOT_SPECIFIED - eng "'Generated as row start' not specified" - -ER_SYS_END_NOT_SPECIFIED - eng "'Generated as row end' not specified" - -ER_SYS_START_MORE_THAN_ONCE - eng "'Generated as row start' specified more than once" - -ER_SYS_END_MORE_THAN_ONCE - eng "Generated as row end specified more than once" - -ER_MISSING_PERIOD_FOR_SYSTEM_TIME - eng "'Period for system time' is missing" - ER_TABLE_DOESNT_SUPPORT_SYSTEM_VERSIONING eng "Table '%s' doesn't support system versioning" -ER_MISSING_WITH_SYSTEM_VERSIONING - eng "'With system versioning' is missing" - -ER_PERIOD_FOR_SYSTEM_TIME_CONTAINS_WRONG_START_COLUMN - eng "First column in 'period for system time' must be equal to 'generated as row start' column" - -ER_PERIOD_FOR_SYSTEM_TIME_CONTAINS_WRONG_END_COLUMN - eng "Second column in 'period for system time' must be equal to 'generated as row end' column" - -ER_SYS_START_AND_SYS_END_SAME - eng "'Period for system_time' must contain two different columns" - ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER eng "Generated field for System Versioning cannot be set by user" ER_UPDATE_INFO_WITH_SYSTEM_VERSIONING eng "Rows matched: %ld Changed: %ld Inserted: %ld Warnings: %ld" -ER_SYS_START_FIELD_MUST_BE_TIMESTAMP - eng "System start field must be of type TIMESTAMP" - -ER_SYS_END_FIELD_MUST_BE_TIMESTAMP - eng "System end field must be of type TIMESTAMP" - -ER_SYS_START_FIELD_MUST_BE_BIGINT - eng "System start field must be of type BIGINT UNSIGNED" - -ER_SYS_END_FIELD_MUST_BE_BIGINT - eng "System end field must be of type BIGINT UNSIGNED" +ER_VERS_FIELD_WRONG_TYPE + eng "%`s must be of type %`s for versioned table %`s" -ER_NO_VERSIONED_FIELDS_IN_VERSIONED_TABLE - eng "Every field specified unversioned in versioned table" +ER_VERS_WRONG_PARAMS + eng "Wrong parameters for versioned table %`s: %s" ER_VERS_TRX_ID_UNSUPPORTED eng "Engine does not support versioned TRX_ID" diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 611e1c1a021..75e608a0377 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3877,8 +3877,13 @@ mysql_execute_command(THD *thd) create_info.use_default_db_type(thd); DBUG_ASSERT(create_info.db_type); - if (create_info.vers_info.check(thd, &alter_info, create_info.db_type->versioned())) + if (create_info.vers_info.check_and_fix_implicit(thd, + &alter_info, + create_info.db_type->flags & HTON_SUPPORTS_SYS_VERSIONING, + create_table->table_name)) + { goto end_with_restore_list; + } /* If we are using SET CHARSET without DEFAULT, add an implicit diff --git a/sql/sql_table.cc b/sql/sql_table.cc index ae697b61eb1..288c36ee7ab 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3470,23 +3470,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, */ if (sql_field->stored_in_db()) record_offset+= sql_field->pack_length; - - if (create_info->versioned()) - { - const bool is_generated_as_row_start = - !my_strcasecmp(system_charset_info, - create_info->vers_info.generated_as_row.start->c_ptr(), - sql_field->field_name); - const bool is_generated_as_row_end = - !my_strcasecmp(system_charset_info, - create_info->vers_info.generated_as_row.end->c_ptr(), - sql_field->field_name); - if (is_generated_as_row_start && is_generated_as_row_end) - { - my_error(ER_SYS_START_AND_SYS_END_SAME, MYF(0), sql_field->field_name); - DBUG_RETURN(TRUE); - } - } } /* Update virtual fields' offset*/ it.rewind(); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 0f810d72f66..6b55582be0b 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -6065,7 +6065,9 @@ period_for_system_time: Vers_parse_info &info= Lex->vers_get_info(); if (!my_strcasecmp(system_charset_info, $4->c_ptr(), $6->c_ptr())) { - my_error(ER_SYS_START_AND_SYS_END_SAME, MYF(0), $4->c_ptr()); + my_error(ER_VERS_WRONG_PARAMS, MYF(0), + Lex->create_last_non_select_table->table_name, + "'PERIOD FOR SYSTEM_TIME' columns must be different"); MYSQL_YYABORT; } info.set_period_for_system_time($4, $6); @@ -6174,17 +6176,19 @@ field_def: if (!field_name) MYSQL_YYABORT; + const char *table_name= Lex->create_last_non_select_table->table_name; + String **p= NULL; - int err_nr= 0; + const char* err; switch ($4) { case 1: p= &info.generated_as_row.start; - err_nr= ER_SYS_START_MORE_THAN_ONCE; + err= "multiple 'GENERATED ALWAYS AS ROW START'"; break; case 0: p= &info.generated_as_row.end; - err_nr= ER_SYS_END_MORE_THAN_ONCE; + err= "multiple 'GENERATED ALWAYS AS ROW END'"; break; default: /* Not Reachable */ @@ -6193,7 +6197,7 @@ field_def: } if (*p) { - my_error(err_nr, MYF(0), field_name->c_ptr()); + my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, err); MYSQL_YYABORT; } *p= field_name; diff --git a/sql/table.cc b/sql/table.cc index 622ced5f60f..1bda4607dcf 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2566,13 +2566,13 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, if (vers_start_field()->type() != MYSQL_TYPE_LONGLONG || !(vers_start_field()->flags & UNSIGNED_FLAG)) { - my_error(ER_SYS_START_FIELD_MUST_BE_BIGINT, MYF(0), share->table_name); + my_error(ER_VERS_FIELD_WRONG_TYPE, MYF(0), vers_start_field()->field_name, "BIGINT UNSIGNED", share->table_name); goto err; } if (vers_end_field()->type() != MYSQL_TYPE_LONGLONG || !(vers_end_field()->flags & UNSIGNED_FLAG)) { - my_error(ER_SYS_END_FIELD_MUST_BE_BIGINT, MYF(0), share->table_name); + my_error(ER_VERS_FIELD_WRONG_TYPE, MYF(0), vers_end_field()->field_name, "BIGINT UNSIGNED", share->table_name); goto err; } } @@ -2580,12 +2580,12 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, { if (vers_start_field()->type() != MYSQL_TYPE_TIMESTAMP) { - my_error(ER_SYS_START_FIELD_MUST_BE_TIMESTAMP, MYF(0), share->table_name); + my_error(ER_VERS_FIELD_WRONG_TYPE, MYF(0), vers_start_field()->field_name, "TIMESTAMP", share->table_name); goto err; } if (vers_end_field()->type() != MYSQL_TYPE_TIMESTAMP) { - my_error(ER_SYS_END_FIELD_MUST_BE_TIMESTAMP, MYF(0), share->table_name); + my_error(ER_VERS_FIELD_WRONG_TYPE, MYF(0), vers_end_field()->field_name, "TIMESTAMP", share->table_name); goto err; } } // if (db_type()->versioned()) -- cgit v1.2.1 From b98f09fcbfc5f2309b64d63d613fe3516a15ac1a Mon Sep 17 00:00:00 2001 From: kevg Date: Sun, 20 Nov 2016 22:17:35 +0300 Subject: Scripts: Three modes of warning printing. WARN_MODE=early print warnings at compilation stage WARN_MODE=late print warnings at build finish stage WARN_MODE=both print both at early and at later stages --- BUILD/capture_warnings.sh | 8 +++++--- cmake/print_warnings.cmake | 18 ++++++++++++++++-- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/BUILD/capture_warnings.sh b/BUILD/capture_warnings.sh index c101493a09e..c469d2f1991 100755 --- a/BUILD/capture_warnings.sh +++ b/BUILD/capture_warnings.sh @@ -1,7 +1,8 @@ #!/bin/bash - warn_path=$1 -shift +warn_mode=$2 +shift 2 + warn_file="$warn_path/compile.warnings" suppress_file="$warn_path/suppress.warnings" @@ -10,7 +11,8 @@ cmderr=$("$@" 2>&1 1>&3) error=$? if [[ -n "$cmderr" ]]; then - echo "$cmderr" >&2 + [[ "$warn_mode" == "both" ]] && + echo "$cmderr" >&2 [[ "$cmderr" =~ warning:(.+)$ ]] && echo -n "$cmderr" >> "$warn_file" fi diff --git a/cmake/print_warnings.cmake b/cmake/print_warnings.cmake index a697e1bd11f..ea61085b5cc 100644 --- a/cmake/print_warnings.cmake +++ b/cmake/print_warnings.cmake @@ -1,6 +1,20 @@ -IF (NOT DEFINED WITHOUT_REPRINT AND CMAKE_BUILD_TYPE MATCHES "Debug") +IF(NOT DEFINED WARN_MODE) + IF(CMAKE_BUILD_TYPE MATCHES "Debug") + SET(WARN_MODE "late") + ELSE() + SET(WARN_MODE "early") + ENDIF() +ENDIF() + +IF(NOT WARN_MODE STREQUAL "early" AND + NOT WARN_MODE STREQUAL "late" AND + NOT WARN_MODE STREQUAL "both") + MESSAGE(FATAL_ERROR "Unknown WARN_MODE: expected 'early', 'late' or 'both'") +ENDIF() + +IF(NOT WARN_MODE MATCHES "early") SET_DIRECTORY_PROPERTIES(PROPERTIES RULE_LAUNCH_COMPILE - "bash ${CMAKE_SOURCE_DIR}/BUILD/capture_warnings.sh ${CMAKE_BINARY_DIR}") + "bash ${CMAKE_SOURCE_DIR}/BUILD/capture_warnings.sh ${CMAKE_BINARY_DIR} ${WARN_MODE}") SET_DIRECTORY_PROPERTIES(PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_BINARY_DIR}/compile.warnings") ADD_CUSTOM_TARGET(rm_compile.warnings ALL -- cgit v1.2.1 From a1c36f2e15170ca6b14db8848b95427df03ab3b8 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Sun, 20 Nov 2016 18:17:28 +0000 Subject: SQL: default NULL for sys fields + misc fixes * sys fields are NULL by default (with exceptions, see comment about NOT_NULL_FLAG in #77); * error codes renamed, messages cleared out; * SHOW CREATE TABLE fixed; * set_max() fix; * redundant flag setters/getters removed; * flags are set in sql_yacc.yy, redundant copy_info_about_generated_fields() eliminated. --- cmake/print_warnings.cmake | 2 +- include/mysql_com.h | 4 +- mysql-test/suite/versioning/r/create.result | 28 ++++++------- mysql-test/suite/versioning/r/insert.result | 8 ++-- .../suite/versioning/r/optimized_fields.result | 20 ++++----- mysql-test/suite/versioning/t/insert.test | 8 ++-- sql/field.cc | 2 + sql/field.h | 49 +--------------------- sql/handler.cc | 17 ++++---- sql/item.cc | 2 +- sql/share/errmsg-utf8.txt | 8 ++-- sql/sql_base.cc | 8 ++-- sql/sql_insert.cc | 2 +- sql/sql_show.cc | 14 +++---- sql/sql_table.cc | 35 +--------------- sql/sql_yacc.yy | 9 ++-- sql/table.cc | 8 ++-- 17 files changed, 77 insertions(+), 147 deletions(-) diff --git a/cmake/print_warnings.cmake b/cmake/print_warnings.cmake index ea61085b5cc..7f6f9635d8e 100644 --- a/cmake/print_warnings.cmake +++ b/cmake/print_warnings.cmake @@ -22,6 +22,6 @@ IF(NOT WARN_MODE MATCHES "early") WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) ADD_CUSTOM_TARGET(print_warnings ALL COMMAND bash -c '[ -f compile.warnings ] && { echo "Warnings found:" \; cat compile.warnings \; echo "" \; } \; true' - DEPENDS mysql udf_example explain_filename-t rm_compile.warnings + DEPENDS mysql udf_example rm_compile.warnings WORKING_DIRECTORY "${CMAKE_BINARY_DIR}") ENDIF() diff --git a/include/mysql_com.h b/include/mysql_com.h index 990a7160bd1..58c28f6d074 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -184,10 +184,10 @@ enum enum_indicator_type #define FIELD_FLAGS_COLUMN_FORMAT_MASK (3U << FIELD_FLAGS_COLUMN_FORMAT) #define FIELD_IS_DROPPED (1U << 26) /* Intern: Field is being dropped */ -#define GENERATED_ROW_START_FLAG (1 << 27) /* autogenerated column declared with +#define VERS_SYS_START_FLAG (1 << 27) /* autogenerated column declared with `generated always at row start` (see II.a SQL Standard) */ -#define GENERATED_ROW_END_FLAG (1 << 28) /* autogenerated column declared with +#define VERS_SYS_END_FLAG (1 << 28) /* autogenerated column declared with `generated always at row end` (see II.a SQL Standard).*/ #define VERS_OPTIMIZED_UPDATE_FLAG (1 << 29) /* column that doesn't support diff --git a/mysql-test/suite/versioning/r/create.result b/mysql-test/suite/versioning/r/create.result index ea3c791cc23..8f69b9c2fac 100644 --- a/mysql-test/suite/versioning/r/create.result +++ b/mysql-test/suite/versioning/r/create.result @@ -9,8 +9,8 @@ show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `XNo` int(10) unsigned DEFAULT NULL, - `Sys_start` timestamp(6) NOT NULL GENERATED AS ROW START, - `Sys_end` timestamp(6) NOT NULL GENERATED AS ROW END, + `Sys_start` timestamp(6) NOT NULL GENERATED ALWAYS AS ROW START, + `Sys_end` timestamp(6) NOT NULL GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (`Sys_start`, `Sys_end`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING # Implicit fields test @@ -21,8 +21,8 @@ show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `XNo` int(10) unsigned DEFAULT NULL, - `sys_trx_start` timestamp(6) NOT NULL GENERATED AS ROW START, - `sys_trx_end` timestamp(6) NOT NULL GENERATED AS ROW END, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING create or replace table t1 ( @@ -126,8 +126,8 @@ Table Create Table t1 CREATE TABLE `t1` ( `A` int(11) DEFAULT NULL, `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, - `sys_trx_start` timestamp(6) NOT NULL GENERATED AS ROW START, - `sys_trx_end` timestamp(6) NOT NULL GENERATED AS ROW END, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING create or replace table t1 ( @@ -139,8 +139,8 @@ Table Create Table t1 CREATE TABLE `t1` ( `A` int(11) DEFAULT NULL, `B` int(11) DEFAULT NULL, - `sys_trx_start` timestamp(6) NOT NULL GENERATED AS ROW START, - `sys_trx_end` timestamp(6) NOT NULL GENERATED AS ROW END, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING create or replace table t1 ( @@ -157,8 +157,8 @@ Table Create Table t1 CREATE TABLE `t1` ( `A` int(11) DEFAULT NULL, `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, - `sys_trx_start` timestamp(6) NOT NULL GENERATED AS ROW START, - `sys_trx_end` timestamp(6) NOT NULL GENERATED AS ROW END, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING create or replace table t1 ( @@ -170,8 +170,8 @@ Table Create Table t1 CREATE TABLE `t1` ( `A` int(11) DEFAULT NULL, `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, - `sys_trx_start` timestamp(6) NOT NULL GENERATED AS ROW START, - `sys_trx_end` timestamp(6) NOT NULL GENERATED AS ROW END, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING create or replace table t1 ( @@ -183,8 +183,8 @@ Table Create Table t1 CREATE TABLE `t1` ( `A` int(11) DEFAULT NULL, `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, - `sys_trx_start` timestamp(6) NOT NULL GENERATED AS ROW START, - `sys_trx_end` timestamp(6) NOT NULL GENERATED AS ROW END, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING create or replace table t1 ( diff --git a/mysql-test/suite/versioning/r/insert.result b/mysql-test/suite/versioning/r/insert.result index fdac34f6759..8527f763c4e 100644 --- a/mysql-test/suite/versioning/r/insert.result +++ b/mysql-test/suite/versioning/r/insert.result @@ -188,9 +188,9 @@ x y sys_end 1002 2002 2038-01-19 03:14:07.000000 3001 4001 2038-01-19 03:14:07.000000 insert into t1(x, y, sys_end) values(8001, 9001, '2015-1-1 1:1:1'); -ERROR HY000: Generated field for System Versioning cannot be set by user +ERROR HY000: System field `sys_end` is read-only insert into vt1_2 values(3002, 4002, '2015-2-2 2:2:2'); -ERROR HY000: Generated field for System Versioning cannot be set by user +ERROR HY000: System field `sys_end` is read-only drop table t1; drop view vt1_1; drop view vt1_2; @@ -211,9 +211,9 @@ x y vtq_commit_ts(sys_end) 1002 2002 2038-01-19 03:14:07.000000 3001 4001 2038-01-19 03:14:07.000000 insert into t1(x, y, sys_end) values(8001, 9001, 1111111); -ERROR HY000: Generated field for System Versioning cannot be set by user +ERROR HY000: System field `sys_end` is read-only insert into vt1_2 values(3002, 4002, 2222222); -ERROR HY000: Generated field for System Versioning cannot be set by user +ERROR HY000: System field `sys_end` is read-only drop table t1; drop view vt1_1; drop view vt1_2; diff --git a/mysql-test/suite/versioning/r/optimized_fields.result b/mysql-test/suite/versioning/r/optimized_fields.result index 3fbc8017931..4d7878e8b9e 100644 --- a/mysql-test/suite/versioning/r/optimized_fields.result +++ b/mysql-test/suite/versioning/r/optimized_fields.result @@ -17,50 +17,50 @@ a b b+0 1 NULL NULL 3 NULL NULL Warnings: -Warning 4055 Attempt to read unversioned field 'b' in historical query +Warning 4075 Attempt to read unversioned field `b` in historical query select * from t for system_time as of timestamp now(6); a b 1 NULL 3 NULL Warnings: -Warning 4055 Attempt to read unversioned field 'b' in historical query +Warning 4075 Attempt to read unversioned field `b` in historical query select count(*) from t group by b for system_time as of timestamp now(6); count(*) 2 Warnings: -Warning 4055 Attempt to read unversioned field 'b' in historical query +Warning 4075 Attempt to read unversioned field `b` in historical query select * from t for system_time as of timestamp now(6) order by b asc; a b 1 NULL 3 NULL Warnings: -Warning 4055 Attempt to read unversioned field 'b' in historical query +Warning 4075 Attempt to read unversioned field `b` in historical query select * from t for system_time as of timestamp now(6) order by b desc; a b 1 NULL 3 NULL Warnings: -Warning 4055 Attempt to read unversioned field 'b' in historical query +Warning 4075 Attempt to read unversioned field `b` in historical query select * from t group by a having a=2 for system_time as of timestamp now(6); a b Warnings: -Warning 4055 Attempt to read unversioned field 'b' in historical query +Warning 4075 Attempt to read unversioned field `b` in historical query select * from t group by b having b=2 for system_time as of timestamp now(6); a b Warnings: -Warning 4055 Attempt to read unversioned field 'b' in historical query +Warning 4075 Attempt to read unversioned field `b` in historical query select a from t where b=2 for system_time as of timestamp now(6); a Warnings: -Warning 4055 Attempt to read unversioned field 'b' in historical query +Warning 4075 Attempt to read unversioned field `b` in historical query select a from t where b=NULL for system_time as of timestamp now(6); a Warnings: -Warning 4055 Attempt to read unversioned field 'b' in historical query +Warning 4075 Attempt to read unversioned field `b` in historical query select count(*), b from t group by b having b=NULL for system_time as of timestamp now(6); count(*) b Warnings: -Warning 4055 Attempt to read unversioned field 'b' in historical query +Warning 4075 Attempt to read unversioned field `b` in historical query select a, b from t; a b 1 2 diff --git a/mysql-test/suite/versioning/t/insert.test b/mysql-test/suite/versioning/t/insert.test index 80eded07d2c..6b9ebeef708 100644 --- a/mysql-test/suite/versioning/t/insert.test +++ b/mysql-test/suite/versioning/t/insert.test @@ -150,18 +150,18 @@ call test_02('timestamp(6)', 'myisam', 'sys_end'); call test_02('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); call test_03('timestamp(6)', 'myisam', 'sys_end'); ---ERROR ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER +--ERROR ER_VERS_READONLY_FIELD insert into t1(x, y, sys_end) values(8001, 9001, '2015-1-1 1:1:1'); ---ERROR ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER +--ERROR ER_VERS_READONLY_FIELD insert into vt1_2 values(3002, 4002, '2015-2-2 2:2:2'); drop table t1; drop view vt1_1; drop view vt1_2; call test_03('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); ---ERROR ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER +--ERROR ER_VERS_READONLY_FIELD insert into t1(x, y, sys_end) values(8001, 9001, 1111111); ---ERROR ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER +--ERROR ER_VERS_READONLY_FIELD insert into vt1_2 values(3002, 4002, 2222222); drop table t1; drop view vt1_1; diff --git a/sql/field.cc b/sql/field.cc index a7108924f57..295b22ad8ec 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4359,6 +4359,7 @@ void Field_longlong::sql_type(String &res) const bool Field_longlong::set_max() { ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + set_notnull(); int8store(ptr, unsigned_flag ? ULONGLONG_MAX : LONGLONG_MAX); return FALSE; } @@ -5448,6 +5449,7 @@ bool Field_timestampf::set_max() DBUG_ENTER("Field_timestampf::set_max"); ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + set_notnull(); mi_int4store(ptr, TIMESTAMP_MAX_VALUE); memset(ptr + 4, 0x0, value_length() - 4); diff --git a/sql/field.h b/sql/field.h index f3c29c29cac..a479ec569ff 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1407,54 +1407,9 @@ public: FIELD_FLAGS_COLUMN_FORMAT; } - /* - System versioning support. - */ - - bool is_generated() - { - return flags & (GENERATED_ROW_START_FLAG | GENERATED_ROW_END_FLAG); - } - - bool is_generated_row_start() - { - return flags & GENERATED_ROW_START_FLAG; - } - - bool is_generated_row_end() - { - return flags & GENERATED_ROW_END_FLAG; - } - - bool is_versioning_disabled() - { - return flags & VERS_OPTIMIZED_UPDATE_FLAG; - } - - /* Mark a field as auto-generated row start column. */ - void set_generated_row_start() - { - //DBUG_ASSERT((flags & GENERATED_ROW_END_FLAG) == 0); - flags |= GENERATED_ROW_START_FLAG; - } - - /* Mark a field as auto-generated row start column. */ - void set_generated_row_end() - { - //DBUG_ASSERT((flags & GENERATED_ROW_START_FLAG) == 0); - flags |= GENERATED_ROW_END_FLAG; - } - - /* Disable a field versioning for a versioned table. */ - void disable_versioning() - { - flags |= VERS_OPTIMIZED_UPDATE_FLAG; - } - - /* Inherit a field versioning status from the table. */ - void inherit_versioning() + bool vers_sys_field() { - flags &= ~VERS_OPTIMIZED_UPDATE_FLAG; + return flags & (VERS_SYS_START_FLAG | VERS_SYS_END_FLAG); } /* diff --git a/sql/handler.cc b/sql/handler.cc index c62dcb067be..14b751c0628 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6561,6 +6561,7 @@ static bool create_string(MEM_ROOT *mem_root, String **s, const char *value) static bool create_sys_trx_field(THD *thd, const char *field_name, Alter_info *alter_info, String **s, + int flags, bool integer_fields) { Create_field *f= new (thd->mem_root) Create_field(); @@ -6570,12 +6571,12 @@ static bool create_sys_trx_field(THD *thd, const char *field_name, memset(f, 0, sizeof(*f)); f->field_name= field_name; f->charset= system_charset_info; - f->flags= NOT_NULL_FLAG | HIDDEN_FLAG; + f->flags= flags | HIDDEN_FLAG; if (integer_fields) { f->sql_type= MYSQL_TYPE_LONGLONG; f->flags|= UNSIGNED_FLAG; - f->length= MY_INT64_NUM_DECIMAL_DIGITS; + f->length= MY_INT64_NUM_DECIMAL_DIGITS - 1; } else { @@ -6610,8 +6611,8 @@ bool Vers_parse_info::fix_implicit( !strncmp(name, generated_as_row.end->c_ptr(), len)) continue; - if (f->versioning == Column_definition::VERSIONING_NOT_SET && - !declared_system_versioning || + if ((f->versioning == Column_definition::VERSIONING_NOT_SET && + !declared_system_versioning) || f->versioning == Column_definition::WITHOUT_VERSIONING) { f->flags|= VERS_OPTIMIZED_UPDATE_FLAG; @@ -6623,10 +6624,12 @@ bool Vers_parse_info::fix_implicit( period_for_system_time.start || period_for_system_time.end) return false; - return create_sys_trx_field(thd, "sys_trx_start", alter_info, - &generated_as_row.start, integer_fields) || + return create_sys_trx_field(thd,"sys_trx_start", alter_info, + &generated_as_row.start, VERS_SYS_START_FLAG, + integer_fields) || create_sys_trx_field(thd, "sys_trx_end", alter_info, - &generated_as_row.end, integer_fields) || + &generated_as_row.end, VERS_SYS_END_FLAG, + integer_fields) || create_string(thd->mem_root, &period_for_system_time.start, "sys_trx_start") || create_string(thd->mem_root, &period_for_system_time.end, diff --git a/sql/item.cc b/sql/item.cc index ec4ed9ab07f..e36fadea957 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2760,7 +2760,7 @@ void Item_field::set_field(Field *field_par) if (field->table->s->tmp_table == SYSTEM_TMP_TABLE) any_privileges= 0; - if (field->is_versioning_disabled() && context && context->select_lex && + if (field->flags & VERS_OPTIMIZED_UPDATE_FLAG && context && context->select_lex && context->select_lex->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED && !field->force_null) diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index c8615943ff2..19bda09cc39 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7488,10 +7488,10 @@ ER_UNKNOWN_VIEW 42S02 # MariaDB error numbers related to System Versioning ER_TABLE_DOESNT_SUPPORT_SYSTEM_VERSIONING - eng "Table '%s' doesn't support system versioning" + eng "Table %`s doesn't support system versioning" -ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER - eng "Generated field for System Versioning cannot be set by user" +ER_VERS_READONLY_FIELD + eng "System field %`s is read-only" ER_UPDATE_INFO_WITH_SYSTEM_VERSIONING eng "Rows matched: %ld Changed: %ld Inserted: %ld Warnings: %ld" @@ -7509,4 +7509,4 @@ ER_VERS_RANGE_UNITS_MISMATCH eng "Range units mismatch" ER_NON_VERSIONED_FIELD_IN_VERSIONED_QUERY - eng "Attempt to read unversioned field '%s' in historical query" + eng "Attempt to read unversioned field %`s in historical query" diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 6d288483818..eb8bcf2148f 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7971,10 +7971,10 @@ fill_record(THD *thd, TABLE *table_arg, List &fields, List &values, ER_THD(thd, ER_WARNING_NON_DEFAULT_VALUE_FOR_VIRTUAL_COLUMN), rfield->field_name, table->s->table_name.str); } - if (table->versioned() && rfield->is_generated() && + if (table->versioned() && rfield->vers_sys_field() && !ignore_errors) { - my_error(ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER, MYF(0)); + my_error(ER_VERS_READONLY_FIELD, MYF(0), rfield->field_name); goto err; } @@ -8225,10 +8225,10 @@ fill_record(THD *thd, TABLE *table, Field **ptr, List &values, } } - if (table->versioned() && field->is_generated() && + if (table->versioned() && field->vers_sys_field() && !ignore_errors) { - my_error(ER_GENERATED_FIELD_CANNOT_BE_SET_BY_USER, MYF(0)); + my_error(ER_VERS_READONLY_FIELD, MYF(0), field->field_name); goto err; } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 4a588ea0cc2..50b98678271 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2045,8 +2045,8 @@ int check_that_all_fields_are_given_values(THD *thd, TABLE *entry, TABLE_LIST *t for (Field **field=entry->field ; *field ; field++) { if (!bitmap_is_set(write_set, (*field)->field_index) && + !(*field)->vers_sys_field() && has_no_default_value(thd, *field, table_list) && - !((*field)->flags & (GENERATED_ROW_START_FLAG | GENERATED_ROW_END_FLAG)) && ((*field)->real_type() != MYSQL_TYPE_ENUM)) err=1; } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index cc7f2b0a017..5a640ccb613 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1666,7 +1666,7 @@ static bool get_field_default_value(THD *thd, Field *field, String *def_value, has_default= (field->default_value || (!(field->flags & NO_DEFAULT_VALUE_FLAG) && - !field->is_generated() && + !field->vers_sys_field() && field->unireg_check != Field::NEXT_NUMBER)); def_value->length(0); @@ -2109,7 +2109,7 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, { if (flags & NOT_NULL_FLAG) packet->append(STRING_WITH_LEN(" NOT NULL")); - else if (field->type() == MYSQL_TYPE_TIMESTAMP) + else if (field->type() == MYSQL_TYPE_TIMESTAMP && !field->vers_sys_field()) { /* TIMESTAMP field require explicit NULL flag, because unlike @@ -2124,16 +2124,16 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, packet->append(STRING_WITH_LEN(" DEFAULT ")); packet->append(def_value.ptr(), def_value.length(), system_charset_info); } - else if (field->is_generated_row_start()) + else if (field->flags & VERS_SYS_START_FLAG) { - packet->append(STRING_WITH_LEN(" GENERATED AS ROW START")); + packet->append(STRING_WITH_LEN(" GENERATED ALWAYS AS ROW START")); } - else if (field->is_generated_row_end()) + else if (field->flags & VERS_SYS_END_FLAG) { - packet->append(STRING_WITH_LEN(" GENERATED AS ROW END")); + packet->append(STRING_WITH_LEN(" GENERATED ALWAYS AS ROW END")); } - if (field->is_versioning_disabled()) + if (field->flags & VERS_OPTIMIZED_UPDATE_FLAG) { packet->append(STRING_WITH_LEN(" WITHOUT SYSTEM VERSIONING")); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 288c36ee7ab..68504ffddba 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3051,7 +3051,7 @@ void promote_first_timestamp_column(List *column_definitions) column_definition->default_value == NULL && // no constant default, column_definition->unireg_check == Field::NONE && // no function default column_definition->vcol_info == NULL && - !(column_definition->flags & (GENERATED_ROW_START_FLAG | GENERATED_ROW_END_FLAG))) // column isn't generated + !(column_definition->flags & (VERS_SYS_START_FLAG | VERS_SYS_END_FLAG))) // column isn't generated { DBUG_PRINT("info", ("First TIMESTAMP column '%s' was promoted to " "DEFAULT CURRENT_TIMESTAMP ON UPDATE " @@ -3146,37 +3146,6 @@ static void check_duplicate_key(THD *thd, Key *key, KEY *key_info, } } -static void -copy_info_about_generated_fields(Alter_info *dst_alter_info, - HA_CREATE_INFO *src_create_info) -{ - if (!src_create_info->versioned()) - return; - - const char *row_start_field = src_create_info->vers_info.generated_as_row.start->c_ptr(); - DBUG_ASSERT(row_start_field); - const char *row_end_field = src_create_info->vers_info.generated_as_row.end->c_ptr(); - DBUG_ASSERT(row_end_field); - - List_iterator it(dst_alter_info->create_list); - Create_field *column_definition = NULL; - while ( (column_definition = it++) ) - { - if (!my_strcasecmp(system_charset_info, - row_start_field, - column_definition->field_name)) - { - column_definition->flags |= GENERATED_ROW_START_FLAG; - } - else if (!my_strcasecmp(system_charset_info, - row_end_field, - column_definition->field_name)) - { - column_definition->flags |= GENERATED_ROW_END_FLAG; - } - } -} - /* Preparation for table creation @@ -5039,8 +5008,6 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, else create_table_mode= C_ASSISTED_DISCOVERY; - copy_info_about_generated_fields(alter_info, create_info); - if (!opt_explicit_defaults_for_timestamp) promote_first_timestamp_column(&alter_info->create_list); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 6b55582be0b..fb2bbb9ad64 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -6170,13 +6170,14 @@ field_def: vcol_opt_specifier vcol_opt_attribute | opt_generated_always AS ROW_SYM start_or_end { - Vers_parse_info &info= Lex->vers_get_info(); + LEX *lex= Lex; + Vers_parse_info &info= lex->vers_get_info(); String *field_name= new (thd->mem_root) - String((const char*)Lex->last_field->field_name, system_charset_info); + String((const char*)lex->last_field->field_name, system_charset_info); if (!field_name) MYSQL_YYABORT; - const char *table_name= Lex->create_last_non_select_table->table_name; + const char *table_name= lex->create_last_non_select_table->table_name; String **p= NULL; const char* err; @@ -6185,10 +6186,12 @@ field_def: case 1: p= &info.generated_as_row.start; err= "multiple 'GENERATED ALWAYS AS ROW START'"; + lex->last_field->flags|= VERS_SYS_START_FLAG; break; case 0: p= &info.generated_as_row.end; err= "multiple 'GENERATED ALWAYS AS ROW END'"; + lex->last_field->flags|= VERS_SYS_END_FLAG; break; default: /* Not Reachable */ diff --git a/sql/table.cc b/sql/table.cc index 1bda4607dcf..4b41a59a750 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2001,7 +2001,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, { uchar flags= *extra2_field_flags++; if (flags & VERS_OPTIMIZED_UPDATE) - reg_field->disable_versioning(); + reg_field->flags|= VERS_OPTIMIZED_UPDATE_FLAG; if (flags & HIDDEN) reg_field->flags|= HIDDEN_FLAG; } @@ -2557,8 +2557,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, goto err; DBUG_PRINT("info", ("Columns with system versioning: [%d, %d]", row_start, row_end)); share->enable_system_versioning(row_start, row_end); - vers_start_field()->set_generated_row_start(); - vers_end_field()->set_generated_row_end(); + vers_start_field()->flags|= VERS_SYS_START_FLAG; + vers_end_field()->flags|= VERS_SYS_END_FLAG; DBUG_ASSERT(db_type()); if (db_type()->versioned()) @@ -3148,7 +3148,7 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, outparam->non_generated_field = fptr; for (i=0 ; i < share->fields; i++) { - if (outparam->field[i]->is_generated()) + if (outparam->field[i]->vers_sys_field()) continue; *fptr++ = outparam->field[i]; } -- cgit v1.2.1 From 53d9e614ae411e75a588ff78550450cb87263bc6 Mon Sep 17 00:00:00 2001 From: kevg Date: Mon, 21 Nov 2016 15:44:20 +0300 Subject: Scripts: reprint warnings fix --- BUILD/capture_warnings.sh | 4 ++-- cmake/print_warnings.cmake | 24 +++++++++++------------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/BUILD/capture_warnings.sh b/BUILD/capture_warnings.sh index c469d2f1991..36d717c9902 100755 --- a/BUILD/capture_warnings.sh +++ b/BUILD/capture_warnings.sh @@ -11,9 +11,9 @@ cmderr=$("$@" 2>&1 1>&3) error=$? if [[ -n "$cmderr" ]]; then - [[ "$warn_mode" == "both" ]] && + [[ "$warn_mode" != "late" ]] && echo "$cmderr" >&2 - [[ "$cmderr" =~ warning:(.+)$ ]] && + [[ "$warn_mode" != "early" && "$cmderr" =~ warning:(.+)$ ]] && echo -n "$cmderr" >> "$warn_file" fi diff --git a/cmake/print_warnings.cmake b/cmake/print_warnings.cmake index 7f6f9635d8e..2d4bd39a332 100644 --- a/cmake/print_warnings.cmake +++ b/cmake/print_warnings.cmake @@ -12,16 +12,14 @@ IF(NOT WARN_MODE STREQUAL "early" AND MESSAGE(FATAL_ERROR "Unknown WARN_MODE: expected 'early', 'late' or 'both'") ENDIF() -IF(NOT WARN_MODE MATCHES "early") - SET_DIRECTORY_PROPERTIES(PROPERTIES RULE_LAUNCH_COMPILE - "bash ${CMAKE_SOURCE_DIR}/BUILD/capture_warnings.sh ${CMAKE_BINARY_DIR} ${WARN_MODE}") - SET_DIRECTORY_PROPERTIES(PROPERTY ADDITIONAL_MAKE_CLEAN_FILES - "${CMAKE_BINARY_DIR}/compile.warnings") - ADD_CUSTOM_TARGET(rm_compile.warnings ALL - COMMAND rm -f compile.warnings - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) - ADD_CUSTOM_TARGET(print_warnings ALL - COMMAND bash -c '[ -f compile.warnings ] && { echo "Warnings found:" \; cat compile.warnings \; echo "" \; } \; true' - DEPENDS mysql udf_example rm_compile.warnings - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}") -ENDIF() +SET_DIRECTORY_PROPERTIES(PROPERTIES RULE_LAUNCH_COMPILE + "bash ${CMAKE_SOURCE_DIR}/BUILD/capture_warnings.sh ${CMAKE_BINARY_DIR} ${WARN_MODE}") +SET_DIRECTORY_PROPERTIES(PROPERTY ADDITIONAL_MAKE_CLEAN_FILES + "${CMAKE_BINARY_DIR}/compile.warnings") +ADD_CUSTOM_TARGET(rm_compile.warnings ALL + COMMAND rm -f compile.warnings + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +ADD_CUSTOM_TARGET(print_warnings ALL + COMMAND bash -c '[ -f compile.warnings ] && { echo "Warnings found:" \; cat compile.warnings \; echo "" \; } \; true' + DEPENDS mysql udf_example rm_compile.warnings + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}") -- cgit v1.2.1 From 9a7a9ae9b9ae05e0289e2c01d9d0f7262b35a006 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 21 Nov 2016 13:16:46 +0000 Subject: Scripts: capture_warnings.sh fix --- BUILD/capture_warnings.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/BUILD/capture_warnings.sh b/BUILD/capture_warnings.sh index 36d717c9902..bb6341fd799 100755 --- a/BUILD/capture_warnings.sh +++ b/BUILD/capture_warnings.sh @@ -7,8 +7,11 @@ warn_file="$warn_path/compile.warnings" suppress_file="$warn_path/suppress.warnings" exec 3>&1 -cmderr=$("$@" 2>&1 1>&3) -error=$? +cmderr=$("$@" 2>&1 1>&3) || { + error=$? + echo "$cmderr" >&2 + exit $error +} if [[ -n "$cmderr" ]]; then [[ "$warn_mode" != "late" ]] && @@ -17,4 +20,5 @@ if [[ -n "$cmderr" ]]; then echo -n "$cmderr" >> "$warn_file" fi -exit ${error} +true + -- cgit v1.2.1 From eff649eba4cb6b9d8b0aaf5ea4d0c8945a3c4fda Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 21 Nov 2016 16:41:51 +0000 Subject: Parser: syntax extension FOR SYSTEM_TIME ALL --- mysql-test/suite/versioning/r/select.result | 25 +++++++++++++++++++++++++ mysql-test/suite/versioning/t/select.test | 9 +++++---- sql/sql_yacc.yy | 10 ++++++++++ 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index 92e5c25fc6e..f73fe9a0130 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -59,6 +59,7 @@ select x as FROMTO_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to select x as BETWAND_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; select x as FROMTO_ext_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; select x as BETWAND_ext_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; +select x as ALL_x, y from t1 for system_time all; if engine = 'innodb' then select x as ASOF2_x, y from t1 for system_time as of transaction @x0; select x as FROMTO2_x, y from t1 for system_time from transaction 0 to transaction @x1; @@ -169,6 +170,18 @@ BETWAND_ext_x y 8 108 9 109 3 33 +ALL_x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +3 33 call test_01('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_start)'); x y 0 100 @@ -236,6 +249,18 @@ BETWAND_ext_x y 8 108 9 109 3 33 +ALL_x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +3 33 ASOF2_x y 0 100 1 101 diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index 3db024b6624..7828af04c9f 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -48,6 +48,7 @@ begin select x as BETWAND_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; select x as FROMTO_ext_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; select x as BETWAND_ext_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; + select x as ALL_x, y from t1 for system_time all; if engine = 'innodb' then select x as ASOF2_x, y from t1 for system_time as of transaction @x0; @@ -77,18 +78,18 @@ begin prepare stmt from @str; execute stmt; drop prepare stmt; set @str= concat('create or replace table t2', @str0); prepare stmt from @str; execute stmt; drop prepare stmt; - + insert into t1 values (1, 1), (1, 2), (1, 3), (4, 4), (5, 5); insert into t2 values (1, 2), (2, 1), (3, 1); set @t0= now(6); - + select t1.x as IJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x; select t1.x as LJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x; select t1.x as RJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x; - + delete from t1; delete from t2; - + select t1.x as IJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x for system_time as of timestamp @t0; select t1.x as LJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index fb2bbb9ad64..a38c0861656 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -8712,6 +8712,16 @@ opt_for_system_time_clause: MYSQL_YYABORT; Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_AS_OF, UNIT_TIMESTAMP, item); } + | FOR_SYSTEM_TIME_SYM ALL + { + static MYSQL_TIME min= { TIMESTAMP_MIN_YEAR, 1, 1, 0, 0, 0, 0, false, MYSQL_TIMESTAMP_DATETIME }; + static MYSQL_TIME max= { TIMESTAMP_MAX_YEAR, 12, 31, 23, 59, 59, 0, false, MYSQL_TIMESTAMP_DATETIME }; + Item *t0= new (thd->mem_root) Item_datetime_literal(thd, &min); + Item *t1= new (thd->mem_root) Item_datetime_literal(thd, &max); + if (!t0 || !t1) + MYSQL_YYABORT; + Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_BETWEEN, UNIT_TIMESTAMP, t0, t1); + } | FOR_SYSTEM_TIME_SYM FROM trans_or_timestamp -- cgit v1.2.1 From 6c516e77d5b3ad6aabf4f95f38884701820f2f01 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 23 Nov 2016 12:20:48 +0000 Subject: IB: notify VTQ on innobase_commit_ordered() [fixes #79] --- storage/innobase/handler/ha_innodb.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 6d7f541c749..4a3a74d1a78 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -4710,6 +4710,14 @@ innobase_commit_ordered_2( /* Don't do write + flush right now. For group commit to work we want to do the flush later. */ trx->flush_log_later = true; + + /* Notify VTQ on System Versioned tables update */ + if (trx->vtq_notify_on_commit) { + vers_notify_vtq(trx); + trx->vtq_notify_on_commit = false; + } + } else { + DBUG_ASSERT(!trx->vtq_notify_on_commit); } innobase_commit_low(trx); -- cgit v1.2.1 From dd3099a00d81fe9365d83f811e8ebc34a0d8c4f4 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Thu, 24 Nov 2016 04:00:28 +0000 Subject: SQL: unsupported engine fix for VTQ funcs --- sql/item_timefunc.cc | 9 +++++++++ sql/share/errmsg-utf8.txt | 4 ++-- sql/sql_select.cc | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 1f9d1076060..9a0c8efb031 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -3322,6 +3322,11 @@ VTQ_common::init_hton() hton= plugin_hton(plugin_int_to_ref(innodb_plugin)); DBUG_ASSERT(hton); } + if (hton && !hton->versioned()) + { + my_error(ER_VERS_ENGINE_UNSUPPORTED, MYF(0), Item::name ? Item::name : this->func_name()); + hton= NULL; + } } } @@ -3343,6 +3348,7 @@ Item_func_vtq_ts::get_date(MYSQL_TIME *res, ulonglong fuzzy_date) if (!hton) return true; + DBUG_ASSERT(hton->vers_query_trx_id); null_value= !hton->vers_query_trx_id(thd, res, trx_id, vtq_field); return false; @@ -3394,6 +3400,7 @@ Item_func_vtq_id::get_by_trx_id(ulonglong trx_id) return 0; } + DBUG_ASSERT(hton->vers_query_trx_id); null_value= !hton->vers_query_trx_id(thd, &res, trx_id, vtq_field); return res; } @@ -3404,6 +3411,7 @@ Item_func_vtq_id::get_by_commit_ts(MYSQL_TIME &commit_ts, bool backwards) THD *thd= current_thd; // can it differ from constructor's? DBUG_ASSERT(thd); + DBUG_ASSERT(hton->vers_query_commit_ts); null_value= !hton->vers_query_commit_ts(thd, &cached_result, commit_ts, VTQ_ALL, backwards); if (null_value) { @@ -3516,6 +3524,7 @@ Item_func_vtq_trx_sees::val_int() return true; } + DBUG_ASSERT(hton->vers_trx_sees); bool result= false; null_value= !hton->vers_trx_sees(thd, result, trx_id1, trx_id0, commit_id1, iso_level1, commit_id0); return result; diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 19bda09cc39..695c118db4a 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7502,8 +7502,8 @@ ER_VERS_FIELD_WRONG_TYPE ER_VERS_WRONG_PARAMS eng "Wrong parameters for versioned table %`s: %s" -ER_VERS_TRX_ID_UNSUPPORTED - eng "Engine does not support versioned TRX_ID" +ER_VERS_ENGINE_UNSUPPORTED + eng "Engine does not support System Versioning for %`s" ER_VERS_RANGE_UNITS_MISMATCH eng "Range units mismatch" diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 4c2ba3caa02..68212eb8fef 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -769,7 +769,7 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LE { if (slex->vers_conditions.unit == UNIT_TRX_ID) { - my_error(ER_VERS_TRX_ID_UNSUPPORTED, MYF(0), table->table_name); + my_error(ER_VERS_ENGINE_UNSUPPORTED, MYF(0), table->table_name); DBUG_RETURN(-1); } } -- cgit v1.2.1 From 48d924693f49c197763a286362c7cd4f322373a1 Mon Sep 17 00:00:00 2001 From: kevg Date: Wed, 23 Nov 2016 22:30:14 +0300 Subject: IB: do not insert into VTQ on optimized fields only update [closes #80] --- mysql-test/suite/versioning/r/update.result | 2 -- storage/innobase/row/row0mysql.cc | 6 +++++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/versioning/r/update.result b/mysql-test/suite/versioning/r/update.result index da626cf425d..19820660146 100644 --- a/mysql-test/suite/versioning/r/update.result +++ b/mysql-test/suite/versioning/r/update.result @@ -520,8 +520,6 @@ No A B C D 18 1 1 1 1 19 1 1 1 1 20 1 1 1 1 -21 1 1 1 1 -22 1 1 1 1 drop procedure test_01; drop procedure test_02; drop procedure test_03; diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 5edf3c1af54..14a393830af 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -2198,7 +2198,11 @@ run_again: } } - if (DICT_TF2_FLAG_IS_SET(node->table, DICT_TF2_VERSIONED)) { + if (DICT_TF2_FLAG_IS_SET(node->table, DICT_TF2_VERSIONED) && + (node->versioned || node->vers_delete || + // TODO: imrove this check (check if we touch only + // unversioned fields in foreigh table + node->foreign)) { trx->vtq_notify_on_commit = true; } -- cgit v1.2.1 From 1bedafb733fd2bffe1c896ba7d01ca91cafd4df5 Mon Sep 17 00:00:00 2001 From: kevg Date: Thu, 24 Nov 2016 17:36:02 +0300 Subject: fix build and some warnings --- sql/sql_class.cc | 2 +- storage/xtradb/include/fsp0fsp.h | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 06a592b8d51..1a422fd9966 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1979,7 +1979,7 @@ bool THD::notify_shared_lock(MDL_context_owner *ctx_in_use, if (!thd_table->needs_reopen()) { signalled|= mysql_lock_abort_for_thread(this, thd_table); - if (this && WSREP(this) && wsrep_thd_is_BF(this, FALSE)) + if (WSREP(this) && wsrep_thd_is_BF(this, FALSE)) { WSREP_DEBUG("remove_table_from_cache: %llu", (unsigned long long) this->real_id); diff --git a/storage/xtradb/include/fsp0fsp.h b/storage/xtradb/include/fsp0fsp.h index 6ed78eba6f9..ad462eb4471 100644 --- a/storage/xtradb/include/fsp0fsp.h +++ b/storage/xtradb/include/fsp0fsp.h @@ -156,15 +156,14 @@ these are only used in MySQL 5.7 and used for compatibility. */ #define FSP_FLAGS_MASK_PAGE_COMPRESSION \ ((~(~0U << FSP_FLAGS_WIDTH_PAGE_COMPRESSION)) \ << FSP_FLAGS_POS_PAGE_COMPRESSION) - -/** Bit mask of the in-memory ATOMIC_WRITES field */ -#define FSP_FLAGS_MASK_MEM_ATOMIC_WRITES \ - (3U << FSP_FLAGS_MEM_ATOMIC_WRITES) - -/** Bit mask of the in-memory COMPRESSION_LEVEL field */ -#define FSP_FLAGS_MASK_MEM_COMPRESSION_LEVEL \ - (15U << FSP_FLAGS_MEM_COMPRESSION_LEVEL) - +/** Bit mask of the PAGE_COMPRESSION_LEVEL field */ +#define FSP_FLAGS_MASK_PAGE_COMPRESSION_LEVEL \ + ((~(~0U << FSP_FLAGS_WIDTH_PAGE_COMPRESSION_LEVEL)) \ + << FSP_FLAGS_POS_PAGE_COMPRESSION_LEVEL) +/** Bit mask of the ATOMIC_WRITES field */ +#define FSP_FLAGS_MASK_ATOMIC_WRITES \ + ((~(~0U << FSP_FLAGS_WIDTH_ATOMIC_WRITES)) \ + << FSP_FLAGS_POS_ATOMIC_WRITES) /** Return the value of the POST_ANTELOPE field */ #define FSP_FLAGS_GET_POST_ANTELOPE(flags) \ ((flags & FSP_FLAGS_MASK_POST_ANTELOPE) \ -- cgit v1.2.1 From 695c5aabadbb08eed58f963e4af9c2cc268ad6c1 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Fri, 9 Dec 2016 06:36:31 +0000 Subject: SQL: error on FOR SYSTEM_TIME without any versioned tables [fixes #88] --- mysql-test/suite/versioning/r/select.result | 4 ++++ mysql-test/suite/versioning/t/select.test | 8 ++++++-- sql/share/errmsg-utf8.txt | 4 ++-- sql/sql_select.cc | 13 ++++++++++--- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index f73fe9a0130..696f339e355 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -398,6 +398,10 @@ insert into t1 values(1); select * from t1; A 1 +create or replace table t1 (x int); +insert into t1 values (1); +select * from t1 for system_time all; +ERROR HY000: System Versioning required: `FOR SYSTEM_TIME` query drop table t1; call verify_vtq; No A B C D diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index 7828af04c9f..566c6ad4a50 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -108,7 +108,7 @@ call test_01('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_start)'); call test_02('timestamp(6)', 'myisam', 'sys_start'); call test_02('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_start)'); -# Test wildcard expansion on hidden fields. +# wildcard expansion on hidden fields. create table t1( A int ) with system versioning engine=myisam; @@ -121,8 +121,12 @@ create or replace table t1( insert into t1 values(1); select * from t1; +create or replace table t1 (x int); +insert into t1 values (1); +--error ER_VERSIONING_REQUIRED +select * from t1 for system_time all; + drop table t1; -# End test wildcard expansion. call verify_vtq; diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 695c118db4a..f37070d9394 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7487,8 +7487,8 @@ ER_UNKNOWN_VIEW 42S02 # MariaDB error numbers related to System Versioning -ER_TABLE_DOESNT_SUPPORT_SYSTEM_VERSIONING - eng "Table %`s doesn't support system versioning" +ER_VERSIONING_REQUIRED + eng "System Versioning required: %s" ER_VERS_READONLY_FIELD eng "System field %`s is read-only" diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 68212eb8fef..7078936ca6f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -668,9 +668,9 @@ setup_without_group(THD *thd, Ref_ptr_array ref_pointer_array, } static int -setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LEX *slex) +vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LEX *slex) { - DBUG_ENTER("setup_for_system_time"); + DBUG_ENTER("vers_setup_select"); #define newx new (thd->mem_root) TABLE_LIST *table; @@ -693,7 +693,14 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LE } if (versioned_tables == 0) + { + if (slex->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED) + { + my_error(ER_VERSIONING_REQUIRED, MYF(0), "`FOR SYSTEM_TIME` query"); + DBUG_RETURN(-1); + } DBUG_RETURN(0); + } /* For prepared statements we create items on statement arena, because they must outlive execution phase for multiple executions. */ @@ -980,7 +987,7 @@ JOIN::prepare(TABLE_LIST *tables_init, } /* Handle FOR SYSTEM_TIME clause. */ - if (setup_for_system_time(thd, tables_list, &conds, select_lex) < 0) + if (vers_setup_select(thd, tables_list, &conds, select_lex) < 0) DBUG_RETURN(-1); /* -- cgit v1.2.1 From 65e900ff049b0c198350fce9cf9874d0bd3f3256 Mon Sep 17 00:00:00 2001 From: kevg Date: Fri, 9 Dec 2016 23:08:31 +0300 Subject: IB: remove unused function --- storage/innobase/handler/ha_innodb.cc | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 4a3a74d1a78..4ad15369ac5 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -23286,19 +23286,6 @@ not_found: DBUG_RETURN(found); } -static -inline -trx_id_t rec_get_trx_id(const rec_t* rec, ulint nfield) -{ - ulint len; - const byte* field; - field = rec_get_nth_field_old( - rec, nfield, &len); - - ut_ad(len == sizeof(trx_id_t)); - return mach_read_from_8(field); -} - static inline void rec_get_timeval(const rec_t* rec, ulint nfield, timeval& out) -- cgit v1.2.1 From a17b8f707fb6e3bb7f665ea7617daf310f3a3d6b Mon Sep 17 00:00:00 2001 From: kevg Date: Wed, 7 Dec 2016 15:15:47 +0300 Subject: 0.5: basic support for ALTER TABLE for InnoDB and other storage engines [closes #57] --- mysql-test/suite/versioning/r/alter.result | 364 ++++++++++++++++++++++++++++ mysql-test/suite/versioning/r/create.result | 38 ++- mysql-test/suite/versioning/t/alter.test | 170 +++++++++++++ mysql-test/suite/versioning/t/create.test | 35 +++ sql/field.h | 1 + sql/handler.cc | 290 +++++++++++++++++----- sql/handler.h | 31 ++- sql/sql_table.cc | 44 ++++ sql/sql_yacc.yy | 37 ++- sql/table.cc | 37 +-- storage/innobase/handler/handler0alter.cc | 18 ++ 11 files changed, 956 insertions(+), 109 deletions(-) create mode 100644 mysql-test/suite/versioning/r/alter.result create mode 100644 mysql-test/suite/versioning/t/alter.test diff --git a/mysql-test/suite/versioning/r/alter.result b/mysql-test/suite/versioning/r/alter.result new file mode 100644 index 00000000000..5011302f151 --- /dev/null +++ b/mysql-test/suite/versioning/r/alter.result @@ -0,0 +1,364 @@ +create table t( +a int +); +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +alter table t without system versioning; +ERROR HY000: Wrong parameters for versioned table `t`: table is not versioned +alter table t with system versioning without system versioning; +ERROR HY000: Wrong parameters for versioned table `t`: Versioning specified more than once for the same table +alter table t with system versioning; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +alter table t without system versioning; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +alter table t +add column trx_start bigint(20) unsigned generated always as row start, +add column trx_end bigint(20) unsigned generated always as row end, +add period for system_time(trx_start, trx_end), +with system versioning; +ERROR HY000: `trx_start` must be of type `TIMESTAMP(6)` for versioned table `t` +alter table t +add column trx_start timestamp generated always as row start, +add column trx_end timestamp generated always as row end, +add period for system_time(trx_start, trx_end), +with system versioning; +ERROR HY000: `trx_start` must be of type `TIMESTAMP(6)` for versioned table `t` +alter table t +add column trx_start timestamp(6) not null generated always as row start, +add column trx_end timestamp(6) not null generated always as row end, +add period for system_time(trx_start, trx_end), +with system versioning; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'generated always as row start, +add column trx_end timestamp(6) not null generate' at line 2 +alter table t +add column trx_start timestamp(6) generated always as row start, +add column trx_end timestamp(6) generated always as row end, +add period for system_time(trx_start, trx_end), +with system versioning; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL, + `trx_start` timestamp(6) NOT NULL GENERATED ALWAYS AS ROW START, + `trx_end` timestamp(6) NOT NULL GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (`trx_start`, `trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +alter table t without system versioning; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +alter table t with system versioning; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +alter table t add column b int; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +alter table t add column c int; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +alter table t add column d int first; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `d` int(11) DEFAULT NULL, + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +alter table t add column e int after d; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `d` int(11) DEFAULT NULL, + `e` int(11) DEFAULT NULL, + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +alter table t add column f int after sys_trx_start; +ERROR HY000: Wrong parameters for versioned table `t`: Can not put new field after system versioning field +alter table t add column f int after sys_trx_end; +ERROR HY000: Wrong parameters for versioned table `t`: Can not put new field after system versioning field +alter table t drop column a; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `d` int(11) DEFAULT NULL, + `e` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +alter table t drop column sys_trx_start; +ERROR HY000: Wrong parameters for versioned table `t`: Can not drop system versioning field +alter table t drop column sys_trx_end; +ERROR HY000: Wrong parameters for versioned table `t`: Can not drop system versioning field +create or replace table t( +a int +); +insert into t values(1); +alter table t with system versioning; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +insert into t values(2); +select * from t for system_time all; +a +1 +2 +select * from t; +a +1 +2 +update t set a=3 where a=1; +select * from t; +a +3 +2 +select * from t for system_time all; +a +3 +2 +1 +select sys_trx_start from t where a=3 into @tm; +alter table t add column b int; +select @tm=sys_trx_start from t where a=3; +@tm=sys_trx_start +1 +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +select * from t; +a b +3 NULL +2 NULL +select * from t for system_time all; +a b +3 NULL +2 NULL +1 NULL +alter table t without system versioning; +select * from t; +a b +3 NULL +2 NULL +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +alter table t modify a int with system versioning; +ERROR HY000: Wrong parameters for versioned table `t`: Can not change fields versioning mode in a non-versioned table +alter table t modify a int with system versioning with system versioning; +ERROR HY000: Wrong parameters for versioned table `t`: Versioning specified more than once for the same field +alter table t modify a int with system versioning without system versioning; +ERROR HY000: Wrong parameters for versioned table `t`: Versioning specified more than once for the same field +alter table t with system versioning; +alter table t modify a int without system versioning; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, + `b` int(11) DEFAULT NULL, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +alter table t modify a int with system versioning; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +set @@session.time_zone='+00:00'; +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +create procedure if not exists verify_vtq() +begin +set @i= 0; +select +@i:= @i + 1 as No, +trx_id > 0 as A, +commit_id >= trx_id as B, +begin_ts > '1-1-1 0:0:0' as C, +commit_ts > begin_ts as D +from information_schema.innodb_vtq +where trx_id > @start_trx_id; +select ifnull(max(trx_id), 0) +into @start_trx_id +from information_schema.innodb_vtq; +end~~ +create or replace table t( +a int +) engine=innodb; +insert into t values(1); +select * from t; +a +1 +alter table t +add column trx_start timestamp(6) generated always as row start, +add column trx_end timestamp(6) generated always as row end, +add period for system_time(trx_start, trx_end), +with system versioning; +ERROR HY000: `trx_start` must be of type `BIGINT(20) UNSIGNED` for versioned table `t` +alter table t +add column trx_start bigint(20) unsigned generated always as row start, +add column trx_end bigint(20) unsigned generated always as row end, +add period for system_time(trx_start, trx_end), +with system versioning; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL, + `trx_start` bigint(20) unsigned GENERATED ALWAYS AS ROW START, + `trx_end` bigint(20) unsigned GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (`trx_start`, `trx_end`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +alter table t without system versioning; +alter table t with system versioning, algorithm=inplace; +ERROR 0A000: ALGORITHM=INPLACE is not supported for this operation. Try ALGORITHM=COPY. +alter table t with system versioning, algorithm=copy; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL, + `sys_trx_start` bigint(20) unsigned GENERATED ALWAYS AS ROW START, + `sys_trx_end` bigint(20) unsigned GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +update t set a=2; +select * from t for system_time all; +a +2 +1 +alter table t add column b int, algorithm=copy; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + `sys_trx_start` bigint(20) unsigned GENERATED ALWAYS AS ROW START, + `sys_trx_end` bigint(20) unsigned GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +select * from t; +a b +2 NULL +1 NULL +alter table t drop column b, algorithm=copy; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL, + `sys_trx_start` bigint(20) unsigned GENERATED ALWAYS AS ROW START, + `sys_trx_end` bigint(20) unsigned GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +select * from t for system_time all; +a +2 +1 +alter table t add column b int, algorithm=inplace; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + `sys_trx_start` bigint(20) unsigned GENERATED ALWAYS AS ROW START, + `sys_trx_end` bigint(20) unsigned GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +select * from t; +a b +2 NULL +1 NULL +alter table t drop column b, algorithm=inplace; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL, + `sys_trx_start` bigint(20) unsigned GENERATED ALWAYS AS ROW START, + `sys_trx_end` bigint(20) unsigned GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +select * from t for system_time all; +a +2 +1 +alter table t without system versioning, algorithm=inplace; +ERROR 0A000: ALGORITHM=INPLACE is not supported for this operation. Try ALGORITHM=COPY. +alter table t without system versioning, algorithm=copy; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +call verify_vtq; +No A B C D +1 1 1 1 1 +2 1 1 1 1 +3 1 1 1 1 +4 1 1 1 1 +5 1 1 1 1 +drop table t; +drop procedure verify_vtq; diff --git a/mysql-test/suite/versioning/r/create.result b/mysql-test/suite/versioning/r/create.result index 8f69b9c2fac..be9f9ae7ea9 100644 --- a/mysql-test/suite/versioning/r/create.result +++ b/mysql-test/suite/versioning/r/create.result @@ -88,35 +88,35 @@ Sys_start int generated always as row start, Sys_end timestamp(6) generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning; -ERROR HY000: `Sys_start` must be of type `TIMESTAMP` for versioned table `t1` +ERROR HY000: `Sys_start` must be of type `TIMESTAMP(6)` for versioned table `t1` create or replace table t1 ( XNo int unsigned, Sys_start timestamp(6) generated always as row start, Sys_end int generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning; -ERROR HY000: `Sys_end` must be of type `TIMESTAMP` for versioned table `t1` +ERROR HY000: `Sys_end` must be of type `TIMESTAMP(6)` for versioned table `t1` create or replace table t1 ( XNo int unsigned, Sys_start timestamp(6) generated always as row start, Sys_end bigint generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning engine innodb; -ERROR HY000: `Sys_start` must be of type `BIGINT UNSIGNED` for versioned table `t1` +ERROR HY000: `Sys_start` must be of type `BIGINT(20) UNSIGNED` for versioned table `t1` create or replace table t1 ( XNo int unsigned, Sys_start bigint generated always as row start, Sys_end bigint generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning engine innodb; -ERROR HY000: `Sys_start` must be of type `BIGINT UNSIGNED` for versioned table `t1` +ERROR HY000: `Sys_start` must be of type `BIGINT(20) UNSIGNED` for versioned table `t1` create or replace table t1 ( XNo int unsigned, Sys_start bigint unsigned generated always as row start, Sys_end bigint generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning engine innodb; -ERROR HY000: `Sys_end` must be of type `BIGINT UNSIGNED` for versioned table `t1` +ERROR HY000: `Sys_end` must be of type `BIGINT(20) UNSIGNED` for versioned table `t1` create or replace table t1 ( A int with system versioning, B int @@ -195,4 +195,32 @@ create or replace table t1 ( A int without system versioning ) with system versioning; ERROR HY000: Wrong parameters for versioned table `t1`: versioned fields missing +create or replace table t1 ( +A int without system versioning with system versioning +); +ERROR HY000: Wrong parameters for versioned table `t1`: Versioning specified more than once for the same field +create or replace table t1 ( +A int with system versioning without system versioning +); +ERROR HY000: Wrong parameters for versioned table `t1`: Versioning specified more than once for the same field +create table t( +a int +) without system versioning; +ERROR HY000: Wrong parameters for versioned table `t`: 'WITHOUT SYSTEM VERSIONING' is not allowed +create or replace table t1 ( +A int +) without system versioning with system versioning; +ERROR HY000: Wrong parameters for versioned table `t1`: Versioning specified more than once for the same table +create or replace table t1 ( +A int +) with system versioning without system versioning; +ERROR HY000: Wrong parameters for versioned table `t1`: Versioning specified more than once for the same table +create or replace table t1 ( +A int +) with system versioning with system versioning; +ERROR HY000: Wrong parameters for versioned table `t1`: Versioning specified more than once for the same table +create or replace table t1 ( +A int +) without system versioning without system versioning; +ERROR HY000: Wrong parameters for versioned table `t1`: Versioning specified more than once for the same table drop table t1; diff --git a/mysql-test/suite/versioning/t/alter.test b/mysql-test/suite/versioning/t/alter.test new file mode 100644 index 00000000000..2fdd59979dc --- /dev/null +++ b/mysql-test/suite/versioning/t/alter.test @@ -0,0 +1,170 @@ +create table t( + a int +); +show create table t; +--error ER_VERS_WRONG_PARAMS +alter table t without system versioning; +--error ER_VERS_WRONG_PARAMS +alter table t with system versioning without system versioning; + +alter table t with system versioning; +show create table t; + +alter table t without system versioning; +show create table t; + +--error ER_VERS_FIELD_WRONG_TYPE +alter table t + add column trx_start bigint(20) unsigned generated always as row start, + add column trx_end bigint(20) unsigned generated always as row end, + add period for system_time(trx_start, trx_end), + with system versioning; + +--error ER_VERS_FIELD_WRONG_TYPE +alter table t + add column trx_start timestamp generated always as row start, + add column trx_end timestamp generated always as row end, + add period for system_time(trx_start, trx_end), + with system versioning; + +--error ER_PARSE_ERROR +alter table t + add column trx_start timestamp(6) not null generated always as row start, + add column trx_end timestamp(6) not null generated always as row end, + add period for system_time(trx_start, trx_end), + with system versioning; + +alter table t + add column trx_start timestamp(6) generated always as row start, + add column trx_end timestamp(6) generated always as row end, + add period for system_time(trx_start, trx_end), + with system versioning; +show create table t; + +alter table t without system versioning; +show create table t; + +alter table t with system versioning; +show create table t; + +alter table t add column b int; +show create table t; + +alter table t add column c int; +show create table t; + +alter table t add column d int first; +show create table t; + +alter table t add column e int after d; +show create table t; + +--error ER_VERS_WRONG_PARAMS +alter table t add column f int after sys_trx_start; +--error ER_VERS_WRONG_PARAMS +alter table t add column f int after sys_trx_end; + +alter table t drop column a; +show create table t; + +--error ER_VERS_WRONG_PARAMS +alter table t drop column sys_trx_start; +--error ER_VERS_WRONG_PARAMS +alter table t drop column sys_trx_end; + +create or replace table t( + a int +); +insert into t values(1); +alter table t with system versioning; +show create table t; +insert into t values(2); +select * from t for system_time all; +select * from t; + +update t set a=3 where a=1; +select * from t; +select * from t for system_time all; +select sys_trx_start from t where a=3 into @tm; +alter table t add column b int; +select @tm=sys_trx_start from t where a=3; +show create table t; +select * from t; +select * from t for system_time all; + +alter table t without system versioning; +select * from t; +show create table t; + +--error ER_VERS_WRONG_PARAMS +alter table t modify a int with system versioning; +--error ER_VERS_WRONG_PARAMS +alter table t modify a int with system versioning with system versioning; +--error ER_VERS_WRONG_PARAMS +alter table t modify a int with system versioning without system versioning; + +alter table t with system versioning; + +alter table t modify a int without system versioning; +show create table t; + +alter table t modify a int with system versioning; +show create table t; + +-- source suite/versioning/common.inc +create or replace table t( + a int +) engine=innodb; + +insert into t values(1); +select * from t; + +--error ER_VERS_FIELD_WRONG_TYPE +alter table t + add column trx_start timestamp(6) generated always as row start, + add column trx_end timestamp(6) generated always as row end, + add period for system_time(trx_start, trx_end), + with system versioning; + +alter table t + add column trx_start bigint(20) unsigned generated always as row start, + add column trx_end bigint(20) unsigned generated always as row end, + add period for system_time(trx_start, trx_end), + with system versioning; +show create table t; +alter table t without system versioning; + +--error ER_ALTER_OPERATION_NOT_SUPPORTED +alter table t with system versioning, algorithm=inplace; + +alter table t with system versioning, algorithm=copy; +show create table t; + +update t set a=2; +select * from t for system_time all; + +alter table t add column b int, algorithm=copy; +show create table t; +select * from t; + +alter table t drop column b, algorithm=copy; +show create table t; +select * from t for system_time all; + +alter table t add column b int, algorithm=inplace; +show create table t; +select * from t; + +alter table t drop column b, algorithm=inplace; +show create table t; +select * from t for system_time all; + +--error ER_ALTER_OPERATION_NOT_SUPPORTED +alter table t without system versioning, algorithm=inplace; + +alter table t without system versioning, algorithm=copy; +show create table t; + +call verify_vtq; +drop table t; +drop procedure verify_vtq; diff --git a/mysql-test/suite/versioning/t/create.test b/mysql-test/suite/versioning/t/create.test index 4310b57d90b..db07f5b2521 100644 --- a/mysql-test/suite/versioning/t/create.test +++ b/mysql-test/suite/versioning/t/create.test @@ -169,4 +169,39 @@ create or replace table t1 ( A int without system versioning ) with system versioning; +--error ER_VERS_WRONG_PARAMS +create or replace table t1 ( + A int without system versioning with system versioning +); + +--error ER_VERS_WRONG_PARAMS +create or replace table t1 ( + A int with system versioning without system versioning +); + +--error ER_VERS_WRONG_PARAMS +create table t( + a int +) without system versioning; + +--error ER_VERS_WRONG_PARAMS +create or replace table t1 ( + A int +) without system versioning with system versioning; + +--error ER_VERS_WRONG_PARAMS +create or replace table t1 ( + A int +) with system versioning without system versioning; + +--error ER_VERS_WRONG_PARAMS +create or replace table t1 ( + A int +) with system versioning with system versioning; + +--error ER_VERS_WRONG_PARAMS +create or replace table t1 ( + A int +) without system versioning without system versioning; + drop table t1; diff --git a/sql/field.h b/sql/field.h index a479ec569ff..ab480b84fda 100644 --- a/sql/field.h +++ b/sql/field.h @@ -4208,6 +4208,7 @@ public: uint from_length,to_length; Field *from_field,*to_field; String tmp; // For items + MYSQL_TIME now; // Used for sys_trx_start Copy_field() {} ~Copy_field() {} diff --git a/sql/handler.cc b/sql/handler.cc index 14b751c0628..f9391729e99 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6553,6 +6553,18 @@ int del_global_index_stat(THD *thd, TABLE* table, KEY* key_info) DBUG_RETURN(res); } +bool Vers_parse_info::is_trx_start(const char *name) const +{ + DBUG_ASSERT(name); + return generated_as_row.start && + !strcmp(generated_as_row.start->c_ptr(), name); +} +bool Vers_parse_info::is_trx_end(const char *name) const +{ + DBUG_ASSERT(name); + return generated_as_row.end && !strcmp(generated_as_row.end->c_ptr(), name); +} + static bool create_string(MEM_ROOT *mem_root, String **s, const char *value) { *s= new (mem_root) String(value, system_charset_info); @@ -6581,7 +6593,7 @@ static bool create_sys_trx_field(THD *thd, const char *field_name, else { f->sql_type= MYSQL_TYPE_TIMESTAMP2; - f->length= 6; + f->length= MAX_DATETIME_PRECISION; } if (f->check(thd)) @@ -6594,37 +6606,17 @@ static bool create_sys_trx_field(THD *thd, const char *field_name, return false; } -bool Vers_parse_info::fix_implicit( - THD *thd, - Alter_info *alter_info, - bool integer_fields) +bool Vers_parse_info::fix_implicit(THD *thd, Alter_info *alter_info, + bool integer_fields) { - List_iterator it(alter_info->create_list); - while (Create_field *f= it++) - { - const char *name= f->field_name; - size_t len= strlen(name); - if (generated_as_row.start && - !strncmp(name, generated_as_row.start->c_ptr(), len)) - continue; - if (generated_as_row.end && - !strncmp(name, generated_as_row.end->c_ptr(), len)) - continue; - - if ((f->versioning == Column_definition::VERSIONING_NOT_SET && - !declared_system_versioning) || - f->versioning == Column_definition::WITHOUT_VERSIONING) - { - f->flags|= VERS_OPTIMIZED_UPDATE_FLAG; - } - } - // If user specified some of these he must specify the others too. Do nothing. if (generated_as_row.start || generated_as_row.end || period_for_system_time.start || period_for_system_time.end) return false; - return create_sys_trx_field(thd,"sys_trx_start", alter_info, + alter_info->flags|= Alter_info::ALTER_ADD_COLUMN; + + return create_sys_trx_field(thd, "sys_trx_start", alter_info, &generated_as_row.start, VERS_SYS_START_FLAG, integer_fields) || create_sys_trx_field(thd, "sys_trx_end", alter_info, @@ -6642,92 +6634,256 @@ bool Vers_parse_info::check_and_fix_implicit( bool integer_fields, const char* table_name) { - if (!( - has_versioned_fields || - has_unversioned_fields || - declared_system_versioning || - period_for_system_time.start || - period_for_system_time.end || - generated_as_row.start || - generated_as_row.end)) - { + if (!need_to_check()) return false; + + if (declared_without_system_versioning) + { + my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, + "'WITHOUT SYSTEM VERSIONING' is not allowed"); + return true; } - if (!declared_system_versioning && !has_versioned_fields) + if (!declared_with_system_versioning && !has_versioned_fields) { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, "'WITH SYSTEM VERSIONING' missing"); + my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, + "'WITH SYSTEM VERSIONING' missing"); return true; } + List_iterator it(alter_info->create_list); + while (Create_field *f= it++) + { + if (is_trx_start(f->field_name) || is_trx_end(f->field_name)) + continue; + + if ((f->versioning == Column_definition::VERSIONING_NOT_SET && + !declared_with_system_versioning) || + f->versioning == Column_definition::WITHOUT_VERSIONING) + { + f->flags|= VERS_OPTIMIZED_UPDATE_FLAG; + } + } + if (fix_implicit(thd, alter_info, integer_fields)) return true; + int not_set= 0; + int with= 0; + it.rewind(); + while (const Create_field *f= it++) { - int not_set= 0; - int with= 0; - List_iterator it(alter_info->create_list); - while (const Create_field *f= it++) - { - const char *name= f->field_name; - size_t len= strlen(name); - if (generated_as_row.start && - !strncmp(name, generated_as_row.start->c_ptr(), len)) - continue; - if (generated_as_row.end && - !strncmp(name, generated_as_row.end->c_ptr(), len)) - continue; + if (is_trx_start(f->field_name) || is_trx_end(f->field_name)) + continue; - if (f->versioning == Column_definition::VERSIONING_NOT_SET) - not_set++; - else if (f->versioning == Column_definition::WITH_VERSIONING) - with++; - } + if (f->versioning == Column_definition::VERSIONING_NOT_SET) + not_set++; + else if (f->versioning == Column_definition::WITH_VERSIONING) + with++; + } + + bool table_with_system_versioning= + generated_as_row.start || generated_as_row.end || + period_for_system_time.start || period_for_system_time.end; + + if (with == 0 && (not_set == 0 || !table_with_system_versioning)) + { + my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, + "versioned fields missing"); + return true; + } + + return check_with_conditions(table_name) || + check_generated_type(table_name, alter_info, integer_fields); +} + +static bool add_field_to_drop_list(THD *thd, Alter_info *alter_info, + Field *field) +{ + DBUG_ASSERT(field); + DBUG_ASSERT(field->field_name); + Alter_drop *ad= new (thd->mem_root) + Alter_drop(Alter_drop::COLUMN, field->field_name, false); + return !ad || alter_info->drop_list.push_back(ad, thd->mem_root); +} + +bool Vers_parse_info::check_and_fix_alter(THD *thd, Alter_info *alter_info, + HA_CREATE_INFO *create_info, + TABLE_SHARE *share) +{ + bool integer_fields= + create_info->db_type->flags & HTON_SUPPORTS_SYS_VERSIONING; + const char *table_name= share->table_name.str; - bool table_with_system_versioning= - declared_system_versioning || generated_as_row.start || - generated_as_row.end || period_for_system_time.start || - period_for_system_time.end; + if (!need_to_check() && !share->versioned) + return false; - if ((table_with_system_versioning && not_set == 0 && with == 0) || - (!table_with_system_versioning && with == 0)) + if (declared_without_system_versioning) + { + if (!share->versioned) { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, "versioned fields missing"); + my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, + "table is not versioned"); + return true; + } + + if (add_field_to_drop_list(thd, alter_info, share->vers_start_field()) || + add_field_to_drop_list(thd, alter_info, share->vers_end_field())) return true; + + alter_info->flags|= Alter_info::ALTER_DROP_COLUMN; + return false; + } + + if ((has_versioned_fields || has_unversioned_fields) && !share->versioned) + { + my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, + "Can not change fields versioning mode in a non-versioned table"); + return true; + } + + if (share->versioned) + { + // copy info from existing table + create_info->options|= HA_VERSIONED_TABLE; + + DBUG_ASSERT(share->vers_start_field() && share->vers_end_field()); + const char *start= share->vers_start_field()->field_name; + const char *end= share->vers_end_field()->field_name; + DBUG_ASSERT(start && end); + + if (create_string(thd->mem_root, &generated_as_row.start, start) || + create_string(thd->mem_root, &generated_as_row.end, end) || + create_string(thd->mem_root, &period_for_system_time.start, start) || + create_string(thd->mem_root, &period_for_system_time.end, end)) + return true; + + if (alter_info->create_list.elements) + { + DBUG_ASSERT(share->fields > 2); + const char *after_this= share->field[share->fields - 3]->field_name; + List_iterator it(alter_info->create_list); + while (Create_field *f= it++) + { + if (f->versioning == Column_definition::WITHOUT_VERSIONING) + f->flags|= VERS_OPTIMIZED_UPDATE_FLAG; + + if (f->change) + continue; + + if (f->after) + { + if (is_trx_start(f->after) || is_trx_end(f->after)) + { + my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, + "Can not put new field after system versioning field"); + return true; + } + + continue; + } + + // TODO: ALTER_COLUMN_ORDER? + f->after= after_this; + } } + + if (alter_info->drop_list.elements) + { + List_iterator it(alter_info->drop_list); + while (Alter_drop* d= it++) + { + if (is_trx_start(d->name) || is_trx_end(d->name)) + { + my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, + "Can not drop system versioning field"); + return true; + } + } + } + + return false; } + return fix_implicit(thd, alter_info, integer_fields) || + (declared_with_system_versioning && + (check_with_conditions(table_name) || + check_generated_type(table_name, alter_info, integer_fields))); +} + +bool Vers_parse_info::check_with_conditions(const char *table_name) const +{ if (!generated_as_row.start) { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, "'GENERATED AS ROW START' column missing"); + my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, + "'GENERATED AS ROW START' column missing"); return true; } if (!generated_as_row.end) { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, "'GENERATED AS ROW END' column missing"); + my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, + "'GENERATED AS ROW END' column missing"); return true; } if (!period_for_system_time.start || !period_for_system_time.end) { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, "'PERIOD FOR SYSTEM_TIME' missing"); + my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, + "'PERIOD FOR SYSTEM_TIME' missing"); return true; } if (my_strcasecmp(system_charset_info, generated_as_row.start->c_ptr(), period_for_system_time.start->c_ptr())) { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, "'PERIOD FOR SYSTEM_TIME' and 'GENERATED AS ROW START' mismatch"); + my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, + "'PERIOD FOR SYSTEM_TIME' and 'GENERATED AS ROW START' mismatch"); return true; } if (my_strcasecmp(system_charset_info, generated_as_row.end->c_ptr(), period_for_system_time.end->c_ptr())) { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, "'PERIOD FOR SYSTEM_TIME' and 'GENERATED AS ROW END' mismatch"); + my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, + "'PERIOD FOR SYSTEM_TIME' and 'GENERATED AS ROW END' mismatch"); return true; } return false; } + +bool Vers_parse_info::check_generated_type(const char *table_name, + Alter_info *alter_info, + bool integer_fields) const +{ + List_iterator it(alter_info->create_list); + while (Create_field *f= it++) + { + if (is_trx_start(f->field_name) || is_trx_end(f->field_name)) + { + if (integer_fields) + { + if (f->sql_type != MYSQL_TYPE_LONGLONG || !(f->flags & UNSIGNED_FLAG) || + f->length != (MY_INT64_NUM_DECIMAL_DIGITS - 1)) + { + my_error(ER_VERS_FIELD_WRONG_TYPE, MYF(0), f->field_name, + "BIGINT(20) UNSIGNED", table_name); + return true; + } + } + else + { + if (f->sql_type != MYSQL_TYPE_TIMESTAMP2 || + f->length != MAX_DATETIME_FULL_WIDTH) + { + my_error(ER_VERS_FIELD_WRONG_TYPE, MYF(0), f->field_name, + "TIMESTAMP(6)", table_name); + return true; + } + } + } + } + + return false; +} diff --git a/sql/handler.h b/sql/handler.h index 394d6276e4f..ced716ed11a 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1674,7 +1674,8 @@ struct Schema_specification_st struct Vers_parse_info { Vers_parse_info() : - declared_system_versioning(false), + declared_with_system_versioning(false), + declared_without_system_versioning(false), has_versioned_fields(false), has_unversioned_fields(false) {} @@ -1698,12 +1699,36 @@ struct Vers_parse_info } private: + bool is_trx_start(const char *name) const; + bool is_trx_end(const char *name) const; bool fix_implicit(THD *thd, Alter_info *alter_info, bool integer_fields); + bool need_to_check() const + { + return + has_versioned_fields || + has_unversioned_fields || + declared_with_system_versioning || + declared_without_system_versioning || + period_for_system_time.start || + period_for_system_time.end || + generated_as_row.start || + generated_as_row.end; + } + bool check_with_conditions(const char *table_name) const; + bool check_generated_type(const char *table_name, Alter_info *alter_info, + bool integer_fields) const; + public: - bool check_and_fix_implicit(THD *thd, Alter_info *alter_info, bool integer_fields, const char* table_name); + bool check_and_fix_implicit(THD *thd, Alter_info *alter_info, + bool integer_fields, const char *table_name); + bool check_and_fix_alter(THD *thd, Alter_info *alter_info, + HA_CREATE_INFO *create_info, TABLE_SHARE *share); /** User has added 'WITH SYSTEM VERSIONING' to table definition */ - bool declared_system_versioning : 1; + bool declared_with_system_versioning : 1; + + /** Use has added 'WITHOUT SYSTEM VERSIONING' to ALTER TABLE */ + bool declared_without_system_versioning : 1; /** At least one field was specified 'WITH SYSTEM VERSIONING'. Useful for diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 68504ffddba..9ad37134c86 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -55,6 +55,8 @@ #include "transaction.h" #include "sql_audit.h" #include "sql_sequence.h" +#include "tztime.h" + #ifdef __WIN__ #include @@ -8718,6 +8720,12 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, if (check_engine(thd, alter_ctx.new_db, alter_ctx.new_name, create_info)) DBUG_RETURN(true); + if (create_info->vers_info.check_and_fix_alter(thd, alter_info, create_info, + table->s)) + { + DBUG_RETURN(true); + } + if ((create_info->db_type != table->s->db_type() || alter_info->flags & Alter_info::ALTER_PARTITION) && !table->file->can_switch_engines()) @@ -9654,6 +9662,10 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, sql_mode_t save_sql_mode= thd->variables.sql_mode; ulonglong prev_insert_id, time_to_report_progress; Field **dfield_ptr= to->default_field; + bool make_versioned= !from->versioned() && to->versioned(); + bool make_unversioned= from->versioned() && !to->versioned(); + Field *to_sys_trx_start= NULL, *from_sys_trx_end= NULL, *to_sys_trx_end= NULL; + MYSQL_TIME now; DBUG_ENTER("copy_data_between_tables"); /* Two or 3 stages; Sorting, copying data and update indexes */ @@ -9753,6 +9765,19 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, thd_progress_next_stage(thd); } + if (make_versioned) + { + thd->variables.time_zone->gmt_sec_to_TIME(&now, thd->query_start()); + now.second_part= thd->query_start_sec_part(); + thd->time_zone_used= 1; + to_sys_trx_start= to->field[to->s->row_start_field]; + to_sys_trx_end= to->field[to->s->row_end_field]; + } + else if (make_unversioned) + { + from_sys_trx_end= from->field[from->s->row_end_field]; + } + THD_STAGE_INFO(thd, stage_copy_to_tmp_table); /* Tell handler that we have values for all columns in the to table */ to->use_all_columns(); @@ -9806,6 +9831,25 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, { copy_ptr->do_copy(copy_ptr); } + + if (make_versioned) + { + to_sys_trx_start->set_notnull(to_sys_trx_start->null_offset()); + // TODO: write directly to record bypassing the same checks on every call + to_sys_trx_start->store_time(&now); + + static const timeval max_tv= {0x7fffffff, 0}; + static const uint dec= 6; + to_sys_trx_end->set_notnull(to_sys_trx_end->null_offset()); + my_timestamp_to_binary(&max_tv, to_sys_trx_end->ptr, dec); + } + else if (make_unversioned) + { + // Drop history rows. + if (!from_sys_trx_end->is_max()) + continue; + } + prev_insert_id= to->file->next_insert_id; if (to->default_field) to->update_default_fields(0, ignore); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index a38c0861656..bc5d65264a0 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5855,10 +5855,31 @@ create_table_option: } | WITH_SYSTEM_SYM VERSIONING { + const char *table_name= + Lex->create_last_non_select_table->table_name; Vers_parse_info &info= Lex->vers_get_info(); - info.declared_system_versioning= true; + if (info.declared_with_system_versioning || + info.declared_without_system_versioning) + my_yyabort_error( + (ER_VERS_WRONG_PARAMS, MYF(0), table_name, + "Versioning specified more than once for the same table")); + + info.declared_with_system_versioning= true; Lex->create_info.options|= HA_VERSIONED_TABLE; } + | WITHOUT SYSTEM VERSIONING + { + const char *table_name= + Lex->create_last_non_select_table->table_name; + Vers_parse_info &info= Lex->vers_get_info(); + if (info.declared_with_system_versioning || + info.declared_without_system_versioning) + my_yyabort_error( + (ER_VERS_WRONG_PARAMS, MYF(0), table_name, + "Versioning specified more than once for the same table")); + + info.declared_without_system_versioning= true; + } ; default_charset: @@ -6679,12 +6700,26 @@ serial_attribute: } | WITH_SYSTEM_SYM VERSIONING { + if (Lex->last_field->versioning != + Column_definition::VERSIONING_NOT_SET) + my_yyabort_error( + (ER_VERS_WRONG_PARAMS, MYF(0), + Lex->create_last_non_select_table->table_name, + "Versioning specified more than once for the same field")); + Lex->last_field->versioning = Column_definition::WITH_VERSIONING; Lex->create_info.vers_info.has_versioned_fields= true; Lex->create_info.options|= HA_VERSIONED_TABLE; } | WITHOUT SYSTEM VERSIONING { + if (Lex->last_field->versioning != + Column_definition::VERSIONING_NOT_SET) + my_yyabort_error( + (ER_VERS_WRONG_PARAMS, MYF(0), + Lex->create_last_non_select_table->table_name, + "Versioning specified more than once for the same field")); + Lex->last_field->versioning = Column_definition::WITHOUT_VERSIONING; Lex->create_info.vers_info.has_unversioned_fields= true; Lex->create_info.options|= HA_VERSIONED_TABLE; diff --git a/sql/table.cc b/sql/table.cc index 4b41a59a750..ad44f896621 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2551,44 +2551,15 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, else { DBUG_PRINT("info", ("Setting system versioning informations")); - uint16 row_start = uint2korr(system_period); - uint16 row_end = uint2korr(system_period + sizeof(uint16)); + uint16 row_start= uint2korr(system_period); + uint16 row_end= uint2korr(system_period + sizeof(uint16)); if (row_start >= share->fields || row_end >= share->fields) goto err; - DBUG_PRINT("info", ("Columns with system versioning: [%d, %d]", row_start, row_end)); + DBUG_PRINT("info", ("Columns with system versioning: [%d, %d]", row_start, + row_end)); share->enable_system_versioning(row_start, row_end); vers_start_field()->flags|= VERS_SYS_START_FLAG; vers_end_field()->flags|= VERS_SYS_END_FLAG; - - DBUG_ASSERT(db_type()); - if (db_type()->versioned()) - { - if (vers_start_field()->type() != MYSQL_TYPE_LONGLONG - || !(vers_start_field()->flags & UNSIGNED_FLAG)) - { - my_error(ER_VERS_FIELD_WRONG_TYPE, MYF(0), vers_start_field()->field_name, "BIGINT UNSIGNED", share->table_name); - goto err; - } - if (vers_end_field()->type() != MYSQL_TYPE_LONGLONG - || !(vers_end_field()->flags & UNSIGNED_FLAG)) - { - my_error(ER_VERS_FIELD_WRONG_TYPE, MYF(0), vers_end_field()->field_name, "BIGINT UNSIGNED", share->table_name); - goto err; - } - } - else - { - if (vers_start_field()->type() != MYSQL_TYPE_TIMESTAMP) - { - my_error(ER_VERS_FIELD_WRONG_TYPE, MYF(0), vers_start_field()->field_name, "TIMESTAMP", share->table_name); - goto err; - } - if (vers_end_field()->type() != MYSQL_TYPE_TIMESTAMP) - { - my_error(ER_VERS_FIELD_WRONG_TYPE, MYF(0), vers_end_field()->field_name, "TIMESTAMP", share->table_name); - goto err; - } - } // if (db_type()->versioned()) } // if (system_period == NULL) delete handler_file; diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 27fa7e84aa3..0e36bf04fde 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -588,6 +588,15 @@ ha_innobase::check_if_supported_inplace_alter( DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); } + // It looks like it's actually possible to do this INPLACE, but we + // disallow this for now. + if (ha_alter_info->create_info->vers_info + .declared_with_system_versioning || + ha_alter_info->create_info->vers_info + .declared_without_system_versioning) { + DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); + } + update_thd(); trx_assert_no_search_latch(m_prebuilt->trx); @@ -4625,6 +4634,15 @@ prepare_inplace_alter_table_dict( field_type |= DATA_UNSIGNED; } + if (altered_table->versioned()) { + if (i == altered_table->s->row_start_field) { + field_type |= DATA_VERS_ROW_START; + } else if (i == + altered_table->s->row_end_field) { + field_type |= DATA_VERS_ROW_END; + } + } + if (dtype_is_string_type(col_type)) { charset_no = (ulint) field->charset()->number; -- cgit v1.2.1 From 1742561b4e750b9ec1b1640f4725a218d79b50b1 Mon Sep 17 00:00:00 2001 From: kevg Date: Sat, 10 Dec 2016 18:33:40 +0300 Subject: fix use-after-free [closes #89] --- mysql-test/suite/versioning/r/alter.result | 4 ++-- .../suite/versioning/r/optimized_fields.result | 1 + sql/item.cc | 22 +++++++++------------- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/mysql-test/suite/versioning/r/alter.result b/mysql-test/suite/versioning/r/alter.result index 5011302f151..a8019c66c37 100644 --- a/mysql-test/suite/versioning/r/alter.result +++ b/mysql-test/suite/versioning/r/alter.result @@ -276,7 +276,7 @@ t CREATE TABLE `t` ( ) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING alter table t without system versioning; alter table t with system versioning, algorithm=inplace; -ERROR 0A000: ALGORITHM=INPLACE is not supported for this operation. Try ALGORITHM=COPY. +ERROR 0A000: ALGORITHM=INPLACE is not supported for this operation. Try ALGORITHM=COPY alter table t with system versioning, algorithm=copy; show create table t; Table Create Table @@ -346,7 +346,7 @@ a 2 1 alter table t without system versioning, algorithm=inplace; -ERROR 0A000: ALGORITHM=INPLACE is not supported for this operation. Try ALGORITHM=COPY. +ERROR 0A000: ALGORITHM=INPLACE is not supported for this operation. Try ALGORITHM=COPY alter table t without system versioning, algorithm=copy; show create table t; Table Create Table diff --git a/mysql-test/suite/versioning/r/optimized_fields.result b/mysql-test/suite/versioning/r/optimized_fields.result index 4d7878e8b9e..ea5b174f6dd 100644 --- a/mysql-test/suite/versioning/r/optimized_fields.result +++ b/mysql-test/suite/versioning/r/optimized_fields.result @@ -18,6 +18,7 @@ a b b+0 3 NULL NULL Warnings: Warning 4075 Attempt to read unversioned field `b` in historical query +Warning 4075 Attempt to read unversioned field `b` in historical query select * from t for system_time as of timestamp now(6); a b 1 NULL diff --git a/sql/item.cc b/sql/item.cc index e36fadea957..4bcdb477a51 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2760,19 +2760,17 @@ void Item_field::set_field(Field *field_par) if (field->table->s->tmp_table == SYSTEM_TMP_TABLE) any_privileges= 0; - if (field->flags & VERS_OPTIMIZED_UPDATE_FLAG && context && context->select_lex && - context->select_lex->vers_conditions.type != - FOR_SYSTEM_TIME_UNSPECIFIED && - !field->force_null) + field->force_null= false; + if (field->flags & VERS_OPTIMIZED_UPDATE_FLAG && context && + context->select_lex && + context->select_lex->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED) { - DBUG_ASSERT(context->select_lex->parent_lex && - context->select_lex->parent_lex->thd); field->force_null= true; - THD *thd= context->select_lex->parent_lex->thd; - push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, - ER_NON_VERSIONED_FIELD_IN_VERSIONED_QUERY, - ER_THD(thd, ER_NON_VERSIONED_FIELD_IN_VERSIONED_QUERY), - field_name); + push_warning_printf( + current_thd, Sql_condition::WARN_LEVEL_WARN, + ER_NON_VERSIONED_FIELD_IN_VERSIONED_QUERY, + ER_THD(current_thd, ER_NON_VERSIONED_FIELD_IN_VERSIONED_QUERY), + field_name); } } @@ -5922,8 +5920,6 @@ void Item_field::cleanup() it will be linked correctly next time by name of field and table alias. I.e. we can drop 'field'. */ - if (field) - field->force_null= false; field= 0; item_equal= NULL; null_value= FALSE; -- cgit v1.2.1 From 1dc021360b34fda70385bfd92d25d31ae9896c1b Mon Sep 17 00:00:00 2001 From: kevg Date: Sat, 10 Dec 2016 19:26:09 +0300 Subject: Scripts: valgrind with test suite --- .travis.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1066e983a67..311c45fabbe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -63,10 +63,12 @@ addons: - libjemalloc-dev - devscripts # implicit for any build on Ubuntu - libtcmalloc-minimal4 + - valgrind env: - - BUILD_TYPE=-DCMAKE_BUILD_TYPE=Debug -DWITH_JEMALLOC=yes -DSECURITY_HARDENED=no -DWITH_PIC=no -DCMAKE_CXX_FLAGS_DEBUG="-g -O0" -DCMAKE_C_FLAGS_DEBUG="-g -O0" "${TRAVIS_BUILD_DIR}" - - BUILD_TYPE=-DCMAKE_BUILD_TYPE=Release -DWITH_JEMALLOC=yes -DSECURITY_HARDENED=yes -DCMAKE_CXX_FLAGS_RELEASE="-g" -DCMAKE_C_FLAGS_RELEASE="-g" "${TRAVIS_BUILD_DIR}" + - BUILD_TYPE="-DCMAKE_BUILD_TYPE=Debug -DWITH_JEMALLOC=yes -DSECURITY_HARDENED=no -DWITH_PIC=no ${TRAVIS_BUILD_DIR}" MTR_FLAGS="" + - BUILD_TYPE="-DCMAKE_BUILD_TYPE=Debug -DSECURITY_HARDENED=no -DWITH_PIC=no ${TRAVIS_BUILD_DIR}" MTR_FLAGS="--valgrind --valgrind-option=--show-reachable=no --valgrind-option=--num-callers=120" + - BUILD_TYPE="-DCMAKE_BUILD_TYPE=RelWithDebInfo -DWITH_JEMALLOC=yes -DSECURITY_HARDENED=yes ${TRAVIS_BUILD_DIR}" MTR_FLAGS="" # libsnappy-dev # https://github.com/travis-ci/apt-package-whitelist/issues/3880 # liblzma-dev # https://github.com/travis-ci/apt-package-whitelist/issues/3879 @@ -77,4 +79,4 @@ script: - export MYSQL_BUILD_CC=/usr/bin/gcc-${GCC_VERSION} MYSQL_BUILD_CXX=/usr/bin/g++-${GCC_VERSION} - ${MYSQL_BUILD_CC} --version ; ${MYSQL_BUILD_CXX} --version - cd "${TRAVIS_BUILD_DIR}" - - "LD_PRELOAD=/usr/lib/libtcmalloc_minimal.so.4 cmake -DWITH_INNOBASE_STORAGE_ENGINE=yes $BUILD_TYPE && LD_PRELOAD=/usr/lib/libtcmalloc_minimal.so.4 make -j $(grep -c processor /proc/cpuinfo) && cd ./mysql-test && ./mtr --suite=versioning --force --max-test-fail=0" + - "LD_PRELOAD=/usr/lib/libtcmalloc_minimal.so.4 cmake -DWITH_INNOBASE_STORAGE_ENGINE=yes $BUILD_TYPE && LD_PRELOAD=/usr/lib/libtcmalloc_minimal.so.4 make -j $(grep -c processor /proc/cpuinfo) && cd ./mysql-test && ./mtr $MTR_FLAGS --suite=versioning --force --max-test-fail=0" -- cgit v1.2.1 From dc4ef66fee4efd9e8edd9c14288b5c58274c0800 Mon Sep 17 00:00:00 2001 From: kevg Date: Sat, 10 Dec 2016 21:56:32 +0300 Subject: SQL: optimize FOR SYSTEM_TIME ALL queries [closes #85] --- sql/sql_select.cc | 11 +++++++---- sql/sql_yacc.yy | 8 +------- sql/table.h | 5 +++-- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 7078936ca6f..1aef44397b2 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -676,11 +676,9 @@ vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LEX *s TABLE_LIST *table; int versioned_tables= 0; Query_arena *arena= 0, backup; - bool is_prepare= thd->stmt_arena->is_stmt_prepare(); - if (!thd->stmt_arena->is_conventional() - && !is_prepare - && !thd->stmt_arena->is_sp_execute()) + if (!thd->stmt_arena->is_conventional() && + !thd->stmt_arena->is_stmt_prepare() && !thd->stmt_arena->is_sp_execute()) { // statement is already prepared DBUG_RETURN(0); @@ -702,6 +700,11 @@ vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LEX *s DBUG_RETURN(0); } + if (slex->vers_conditions.type == FOR_SYSTEM_TIME_ALL) + { + DBUG_RETURN(0); + } + /* For prepared statements we create items on statement arena, because they must outlive execution phase for multiple executions. */ arena= thd->activate_stmt_arena_if_needed(&backup); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index bc5d65264a0..f91568e9fb1 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -8749,13 +8749,7 @@ opt_for_system_time_clause: } | FOR_SYSTEM_TIME_SYM ALL { - static MYSQL_TIME min= { TIMESTAMP_MIN_YEAR, 1, 1, 0, 0, 0, 0, false, MYSQL_TIMESTAMP_DATETIME }; - static MYSQL_TIME max= { TIMESTAMP_MAX_YEAR, 12, 31, 23, 59, 59, 0, false, MYSQL_TIMESTAMP_DATETIME }; - Item *t0= new (thd->mem_root) Item_datetime_literal(thd, &min); - Item *t1= new (thd->mem_root) Item_datetime_literal(thd, &max); - if (!t0 || !t1) - MYSQL_YYABORT; - Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_BETWEEN, UNIT_TIMESTAMP, t0, t1); + Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_ALL, UNIT_TIMESTAMP); } | FOR_SYSTEM_TIME_SYM FROM diff --git a/sql/table.h b/sql/table.h index df0300d498c..b93bb3df5e3 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1817,7 +1817,8 @@ enum vers_range_type_t FOR_SYSTEM_TIME_UNSPECIFIED = 0, FOR_SYSTEM_TIME_AS_OF, FOR_SYSTEM_TIME_FROM_TO, - FOR_SYSTEM_TIME_BETWEEN + FOR_SYSTEM_TIME_BETWEEN, + FOR_SYSTEM_TIME_ALL }; enum vers_range_unit_t @@ -1843,7 +1844,7 @@ struct vers_select_conds_t void init( vers_range_type_t t, vers_range_unit_t u, - Item * s, + Item * s= NULL, Item * e= NULL) { type= t; -- cgit v1.2.1 From e851c140f4a4fdfb7d450aa19a91f4eb65758b81 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Sun, 11 Dec 2016 17:04:11 +0000 Subject: SQL: (0.5) Versioned partitions [closes #77] * one `AS OF NOW`, multiple `VERSIONING` partitions; * rotation of `VERSIONING` partitions by record count, time period; * rotation is multi-threaded; * conventional subpartitions as bottom level for versioned partitions; * `DEFAULT` keyword selects first `VERSIONING` partition; * ALTER TABLE ADD/DROP partition; * REBUILD PARTITION basic operation. --- mysql-test/r/parser.result | 4 +- mysql-test/r/partition.result | 2 +- mysql-test/r/partition_error.result | 14 +- .../suite/parts/r/partition_syntax_innodb.result | 2 +- .../suite/parts/r/partition_syntax_myisam.result | 2 +- mysql-test/suite/versioning/r/alter.result | 18 +- mysql-test/suite/versioning/r/create.result | 36 +-- mysql-test/suite/versioning/r/partition.result | 237 +++++++++++++++++ mysql-test/suite/versioning/t/partition.test | 190 ++++++++++++++ mysql-test/t/parser.test | 2 - sql/field.cc | 11 +- sql/field.h | 9 +- sql/ha_partition.cc | 7 +- sql/ha_partition.h | 34 ++- sql/handler.cc | 13 +- sql/handler.h | 14 +- sql/item_timefunc.cc | 4 +- sql/lex.h | 4 +- sql/mysqld.cc | 7 +- sql/mysqld.h | 4 +- sql/partition_element.h | 55 +++- sql/partition_info.cc | 291 ++++++++++++++++++++- sql/partition_info.h | 109 ++++++++ sql/share/errmsg-utf8.txt | 20 +- sql/sql_delete.cc | 3 +- sql/sql_partition.cc | 172 +++++++++++- sql/sql_show.cc | 5 + sql/sql_yacc.yy | 99 ++++++- sql/table.cc | 26 +- sql/table.h | 47 +++- .../tokudb_parts/r/partition_syntax_tokudb.result | 2 +- 31 files changed, 1327 insertions(+), 116 deletions(-) create mode 100644 mysql-test/suite/versioning/r/partition.result create mode 100644 mysql-test/suite/versioning/t/partition.test diff --git a/mysql-test/r/parser.result b/mysql-test/r/parser.result index f197fbe6a19..c57e2c2c803 100644 --- a/mysql-test/r/parser.result +++ b/mysql-test/r/parser.result @@ -64,10 +64,8 @@ create table MIN(a int); ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'MIN(a int)' at line 1 create table MIN (a int); drop table MIN; -create table NOW(a int); -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'NOW(a int)' at line 1 create table NOW (a int); -drop table NOW; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'NOW (a int)' at line 1 create table POSITION(a int); ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'POSITION(a int)' at line 1 create table POSITION (a int); diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result index 8489d03f119..8c9490b6f58 100644 --- a/mysql-test/r/partition.result +++ b/mysql-test/r/partition.result @@ -1459,7 +1459,7 @@ ERROR 42000: Wrong number of subpartitions defined, mismatch with previous setti create table t1 (a int) partition by hash (a) (partition p0 (subpartition sp0)); -ERROR HY000: It is only possible to mix RANGE/LIST partitioning with HASH/KEY partitioning for subpartitioning +ERROR HY000: It is only possible to mix RANGE/LIST/SYSTEM_TIME partitioning with HASH/KEY partitioning for subpartitioning create table t1 (a int) partition by range (a) (partition p0 values less than (1)); diff --git a/mysql-test/r/partition_error.result b/mysql-test/r/partition_error.result index e52c1ef7df5..a9bffb4ee9b 100644 --- a/mysql-test/r/partition_error.result +++ b/mysql-test/r/partition_error.result @@ -1023,7 +1023,7 @@ c int not null, primary key (a,b)) partition by key (a) subpartition by key (b); -ERROR HY000: It is only possible to mix RANGE/LIST partitioning with HASH/KEY partitioning for subpartitioning +ERROR HY000: It is only possible to mix RANGE/LIST/SYSTEM_TIME partitioning with HASH/KEY partitioning for subpartitioning select load_file('$MYSQLD_DATADIR/test/t1.par'); load_file('$MYSQLD_DATADIR/test/t1.par') NULL @@ -1034,7 +1034,7 @@ c int not null, primary key (a,b)) partition by key (a) subpartition by key (a, b); -ERROR HY000: It is only possible to mix RANGE/LIST partitioning with HASH/KEY partitioning for subpartitioning +ERROR HY000: It is only possible to mix RANGE/LIST/SYSTEM_TIME partitioning with HASH/KEY partitioning for subpartitioning select load_file('$MYSQLD_DATADIR/test/t1.par'); load_file('$MYSQLD_DATADIR/test/t1.par') NULL @@ -1045,7 +1045,7 @@ c int not null, primary key (a,b)) partition by key (a) subpartition by hash (a+b); -ERROR HY000: It is only possible to mix RANGE/LIST partitioning with HASH/KEY partitioning for subpartitioning +ERROR HY000: It is only possible to mix RANGE/LIST/SYSTEM_TIME partitioning with HASH/KEY partitioning for subpartitioning select load_file('$MYSQLD_DATADIR/test/t1.par'); load_file('$MYSQLD_DATADIR/test/t1.par') NULL @@ -1056,7 +1056,7 @@ c int not null, primary key (a,b)) partition by key (a) subpartition by key (b); -ERROR HY000: It is only possible to mix RANGE/LIST partitioning with HASH/KEY partitioning for subpartitioning +ERROR HY000: It is only possible to mix RANGE/LIST/SYSTEM_TIME partitioning with HASH/KEY partitioning for subpartitioning select load_file('$MYSQLD_DATADIR/test/t1.par'); load_file('$MYSQLD_DATADIR/test/t1.par') NULL @@ -1067,7 +1067,7 @@ c int not null, primary key (a,b)) partition by key (a) subpartition by key (a, b); -ERROR HY000: It is only possible to mix RANGE/LIST partitioning with HASH/KEY partitioning for subpartitioning +ERROR HY000: It is only possible to mix RANGE/LIST/SYSTEM_TIME partitioning with HASH/KEY partitioning for subpartitioning select load_file('$MYSQLD_DATADIR/test/t1.par'); load_file('$MYSQLD_DATADIR/test/t1.par') NULL @@ -1078,7 +1078,7 @@ c int not null, primary key (a,b)) partition by key (a) subpartition by hash (a+b); -ERROR HY000: It is only possible to mix RANGE/LIST partitioning with HASH/KEY partitioning for subpartitioning +ERROR HY000: It is only possible to mix RANGE/LIST/SYSTEM_TIME partitioning with HASH/KEY partitioning for subpartitioning select load_file('$MYSQLD_DATADIR/test/t1.par'); load_file('$MYSQLD_DATADIR/test/t1.par') NULL @@ -1135,7 +1135,7 @@ c int not null, primary key (a,b)) partition by key (a) subpartition by hash (3+4); -ERROR HY000: It is only possible to mix RANGE/LIST partitioning with HASH/KEY partitioning for subpartitioning +ERROR HY000: It is only possible to mix RANGE/LIST/SYSTEM_TIME partitioning with HASH/KEY partitioning for subpartitioning CREATE TABLE t1 ( a int not null, b int not null, diff --git a/mysql-test/suite/parts/r/partition_syntax_innodb.result b/mysql-test/suite/parts/r/partition_syntax_innodb.result index f8de7ca5249..a7e92bf9b00 100644 --- a/mysql-test/suite/parts/r/partition_syntax_innodb.result +++ b/mysql-test/suite/parts/r/partition_syntax_innodb.result @@ -510,7 +510,7 @@ f_charbig VARCHAR(1000) ) PARTITION BY RANGE(f_int1) ( PARTITION part1 VALUES LESS THAN (1000) (SUBPARTITION subpart11)); -ERROR HY000: It is only possible to mix RANGE/LIST partitioning with HASH/KEY partitioning for subpartitioning +ERROR HY000: It is only possible to mix RANGE/LIST/SYSTEM_TIME partitioning with HASH/KEY partitioning for subpartitioning #------------------------------------------------------------------------ # 2.2 Every partition must have the same number of subpartitions. # This is a limitation of MySQL 5.1, which could be removed in diff --git a/mysql-test/suite/parts/r/partition_syntax_myisam.result b/mysql-test/suite/parts/r/partition_syntax_myisam.result index e7ae727ea02..313b53c490e 100644 --- a/mysql-test/suite/parts/r/partition_syntax_myisam.result +++ b/mysql-test/suite/parts/r/partition_syntax_myisam.result @@ -510,7 +510,7 @@ f_charbig VARCHAR(1000) ) PARTITION BY RANGE(f_int1) ( PARTITION part1 VALUES LESS THAN (1000) (SUBPARTITION subpart11)); -ERROR HY000: It is only possible to mix RANGE/LIST partitioning with HASH/KEY partitioning for subpartitioning +ERROR HY000: It is only possible to mix RANGE/LIST/SYSTEM_TIME partitioning with HASH/KEY partitioning for subpartitioning #------------------------------------------------------------------------ # 2.2 Every partition must have the same number of subpartitions. # This is a limitation of MySQL 5.1, which could be removed in diff --git a/mysql-test/suite/versioning/r/alter.result b/mysql-test/suite/versioning/r/alter.result index a8019c66c37..5db4020f7f2 100644 --- a/mysql-test/suite/versioning/r/alter.result +++ b/mysql-test/suite/versioning/r/alter.result @@ -7,9 +7,9 @@ t CREATE TABLE `t` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 alter table t without system versioning; -ERROR HY000: Wrong parameters for versioned table `t`: table is not versioned +ERROR HY000: Wrong parameters for `t`: table is not versioned alter table t with system versioning without system versioning; -ERROR HY000: Wrong parameters for versioned table `t`: Versioning specified more than once for the same table +ERROR HY000: Wrong parameters for `t`: Versioning specified more than once for the same table alter table t with system versioning; show create table t; Table Create Table @@ -119,9 +119,9 @@ t CREATE TABLE `t` ( PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING alter table t add column f int after sys_trx_start; -ERROR HY000: Wrong parameters for versioned table `t`: Can not put new field after system versioning field +ERROR HY000: Wrong parameters for `t`: Can not put new field after system versioning field alter table t add column f int after sys_trx_end; -ERROR HY000: Wrong parameters for versioned table `t`: Can not put new field after system versioning field +ERROR HY000: Wrong parameters for `t`: Can not put new field after system versioning field alter table t drop column a; show create table t; Table Create Table @@ -135,9 +135,9 @@ t CREATE TABLE `t` ( PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING alter table t drop column sys_trx_start; -ERROR HY000: Wrong parameters for versioned table `t`: Can not drop system versioning field +ERROR HY000: Wrong parameters for `t`: Can not drop system versioning field alter table t drop column sys_trx_end; -ERROR HY000: Wrong parameters for versioned table `t`: Can not drop system versioning field +ERROR HY000: Wrong parameters for `t`: Can not drop system versioning field create or replace table t( a int ); @@ -205,11 +205,11 @@ t CREATE TABLE `t` ( `b` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 alter table t modify a int with system versioning; -ERROR HY000: Wrong parameters for versioned table `t`: Can not change fields versioning mode in a non-versioned table +ERROR HY000: Wrong parameters for `t`: Can not change fields versioning mode in a non-versioned table alter table t modify a int with system versioning with system versioning; -ERROR HY000: Wrong parameters for versioned table `t`: Versioning specified more than once for the same field +ERROR HY000: Wrong parameters for `t`: Versioning specified more than once for the same field alter table t modify a int with system versioning without system versioning; -ERROR HY000: Wrong parameters for versioned table `t`: Versioning specified more than once for the same field +ERROR HY000: Wrong parameters for `t`: Versioning specified more than once for the same field alter table t with system versioning; alter table t modify a int without system versioning; show create table t; diff --git a/mysql-test/suite/versioning/r/create.result b/mysql-test/suite/versioning/r/create.result index be9f9ae7ea9..1fcf0c1e6a8 100644 --- a/mysql-test/suite/versioning/r/create.result +++ b/mysql-test/suite/versioning/r/create.result @@ -32,14 +32,14 @@ Sys_start2 timestamp(6) generated always as row start, Sys_end timestamp(6) generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning; -ERROR HY000: Wrong parameters for versioned table `t1`: multiple 'GENERATED ALWAYS AS ROW START' +ERROR HY000: Wrong parameters for `t1`: multiple 'GENERATED ALWAYS AS ROW START' create or replace table t1 ( XNo int unsigned, Sys_start timestamp(6) generated always as row start, Sys_end2 timestamp(6) generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning; -ERROR HY000: Wrong parameters for versioned table `t1`: 'PERIOD FOR SYSTEM_TIME' and 'GENERATED AS ROW END' mismatch +ERROR HY000: Wrong parameters for `t1`: 'PERIOD FOR SYSTEM_TIME' and 'GENERATED AS ROW END' mismatch create or replace table t1 ( XNo int unsigned, Sys_start timestamp(6) generated always as row start, @@ -47,12 +47,12 @@ Sys_end timestamp(6) generated always as row end, Sys_end2 timestamp(6) generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning; -ERROR HY000: Wrong parameters for versioned table `t1`: multiple 'GENERATED ALWAYS AS ROW END' +ERROR HY000: Wrong parameters for `t1`: multiple 'GENERATED ALWAYS AS ROW END' create or replace table t1 ( XNo int unsigned, period for system_time (Sys_start, Sys_end) ) with system versioning; -ERROR HY000: Wrong parameters for versioned table `t1`: 'GENERATED AS ROW START' column missing +ERROR HY000: Wrong parameters for `t1`: 'GENERATED AS ROW START' column missing create or replace table t1 ( XNo int unsigned, Sys_start timestamp(6) generated always as row start, @@ -60,28 +60,28 @@ Sys_end timestamp(6) generated always as row end, Sys_end2 timestamp(6) generated always as row end, period for system_time (Sys_start, Sys_end) ); -ERROR HY000: Wrong parameters for versioned table `t1`: multiple 'GENERATED ALWAYS AS ROW END' +ERROR HY000: Wrong parameters for `t1`: multiple 'GENERATED ALWAYS AS ROW END' create or replace table t1 ( XNo int unsigned, Sys_start timestamp(6) generated always as row start, Sys_end timestamp(6) generated always as row end, period for system_time (sys_insert, sys_remove) ) with system versioning; -ERROR HY000: Wrong parameters for versioned table `t1`: 'PERIOD FOR SYSTEM_TIME' and 'GENERATED AS ROW START' mismatch +ERROR HY000: Wrong parameters for `t1`: 'PERIOD FOR SYSTEM_TIME' and 'GENERATED AS ROW START' mismatch create or replace table t1 ( XNo int unsigned, Sys_start timestamp(6) generated always as row start, Sys_end timestamp(6) generated always as row end, period for system_time (Sys_start, Sys_end) ); -ERROR HY000: Wrong parameters for versioned table `t1`: 'WITH SYSTEM VERSIONING' missing +ERROR HY000: Wrong parameters for `t1`: 'WITH SYSTEM VERSIONING' missing create or replace table t1 ( XNo int unsigned, Sys_start timestamp(6) generated always as row start, Sys_end timestamp(6) generated always as row end, period for system_time (Sys_start, Sys_start) ); -ERROR HY000: Wrong parameters for versioned table `t1`: 'PERIOD FOR SYSTEM_TIME' columns must be different +ERROR HY000: Wrong parameters for `t1`: 'PERIOD FOR SYSTEM_TIME' columns must be different create or replace table t1 ( XNo int unsigned, Sys_start int generated always as row start, @@ -147,7 +147,7 @@ create or replace table t1 ( A int, B int without system versioning ); -ERROR HY000: Wrong parameters for versioned table `t1`: 'WITH SYSTEM VERSIONING' missing +ERROR HY000: Wrong parameters for `t1`: 'WITH SYSTEM VERSIONING' missing create or replace table t1 ( A int, B int without system versioning @@ -190,37 +190,37 @@ t1 CREATE TABLE `t1` ( create or replace table t1 ( A int without system versioning ); -ERROR HY000: Wrong parameters for versioned table `t1`: 'WITH SYSTEM VERSIONING' missing +ERROR HY000: Wrong parameters for `t1`: 'WITH SYSTEM VERSIONING' missing create or replace table t1 ( A int without system versioning ) with system versioning; -ERROR HY000: Wrong parameters for versioned table `t1`: versioned fields missing +ERROR HY000: Wrong parameters for `t1`: versioned fields missing create or replace table t1 ( A int without system versioning with system versioning ); -ERROR HY000: Wrong parameters for versioned table `t1`: Versioning specified more than once for the same field +ERROR HY000: Wrong parameters for `t1`: Versioning specified more than once for the same field create or replace table t1 ( A int with system versioning without system versioning ); -ERROR HY000: Wrong parameters for versioned table `t1`: Versioning specified more than once for the same field +ERROR HY000: Wrong parameters for `t1`: Versioning specified more than once for the same field create table t( a int ) without system versioning; -ERROR HY000: Wrong parameters for versioned table `t`: 'WITHOUT SYSTEM VERSIONING' is not allowed +ERROR HY000: Wrong parameters for `t`: 'WITHOUT SYSTEM VERSIONING' is not allowed create or replace table t1 ( A int ) without system versioning with system versioning; -ERROR HY000: Wrong parameters for versioned table `t1`: Versioning specified more than once for the same table +ERROR HY000: Wrong parameters for `t1`: Versioning specified more than once for the same table create or replace table t1 ( A int ) with system versioning without system versioning; -ERROR HY000: Wrong parameters for versioned table `t1`: Versioning specified more than once for the same table +ERROR HY000: Wrong parameters for `t1`: Versioning specified more than once for the same table create or replace table t1 ( A int ) with system versioning with system versioning; -ERROR HY000: Wrong parameters for versioned table `t1`: Versioning specified more than once for the same table +ERROR HY000: Wrong parameters for `t1`: Versioning specified more than once for the same table create or replace table t1 ( A int ) without system versioning without system versioning; -ERROR HY000: Wrong parameters for versioned table `t1`: Versioning specified more than once for the same table +ERROR HY000: Wrong parameters for `t1`: Versioning specified more than once for the same table drop table t1; diff --git a/mysql-test/suite/versioning/r/partition.result b/mysql-test/suite/versioning/r/partition.result new file mode 100644 index 00000000000..babd1b4bd4f --- /dev/null +++ b/mysql-test/suite/versioning/r/partition.result @@ -0,0 +1,237 @@ +create table t1 (x int) +with system versioning +engine innodb +partition by range columns (x) ( +partition p0 values less than (100), +partition p1 values less than (1000)); +insert into t1 values (3), (300); +select * from t1; +x +3 +300 +select * from t1 partition (p0); +x +3 +select * from t1 partition (p1); +x +300 +delete from t1; +select * from t1; +x +select * from t1 for system_time all; +x +3 +300 +select * from t1 partition (p0) for system_time all; +x +3 +select * from t1 partition (p1) for system_time all; +x +300 +create or replace table t1 (x int) +partition by system_time ( +partition p0 as of now, +partition p1 versioning); +ERROR HY000: System Versioning required: `BY SYSTEM_TIME` partitioning +create or replace table t1 (x int); +alter table t1 +partition by system_time ( +partition p0 as of now, +partition p1 versioning); +ERROR HY000: System Versioning required: `BY SYSTEM_TIME` partitioning +create or replace table t1 (x int) +with system versioning +partition by system_time ( +partition p0 as of now); +ERROR HY000: Wrong parameters for `BY SYSTEM_TIME`: unexpected number of partitions (expected > 1) +create or replace table t1 (x int) +with system versioning +partition by system_time ( +partition p0 as of now, +partition p1 as of now); +ERROR HY000: Wrong parameters for `BY SYSTEM_TIME`: multiple `AS OF NOW` partitions +create or replace table t1 (x int) +with system versioning +partition by system_time ( +partition p0 versioning, +partition p1 versioning); +ERROR HY000: Wrong parameters for `BY SYSTEM_TIME`: no `AS OF NOW` partition defined +create or replace table t1 (x int) +with system versioning +partition by system_time ( +partition p0 as of now, +partition p1 versioning); +alter table t1 add partition ( +partition p2 as of now); +ERROR HY000: Wrong parameters for `BY SYSTEM_TIME`: multiple `AS OF NOW` partitions +alter table t1 add partition ( +partition p2 versioning default); +Warnings: +Warning 4078 Maybe missing parameters: no rotation condition for multiple `VERSIONING` partitions. +alter table t1 drop partition p0; +ERROR HY000: Wrong parameters for `BY SYSTEM_TIME`: `AS OF NOW` partition can not be dropped +alter table t1 drop partition p2; +alter table t1 drop partition p1; +ERROR HY000: Wrong parameters for `BY SYSTEM_TIME`: one `AS OF NOW` and at least one `VERSIONING` partition required +insert into t1 values (1); +select * from t1; +x +1 +select * from t1 partition (p0); +x +1 +select * from t1 partition (p1); +x +delete from t1; +select * from t1 partition (p0) for system_time all; +x +select * from t1 partition (p1) for system_time all; +x +1 +create or replace table t1 (x int) +with system versioning +partition by system_time ( +partition p0 versioning, +partition p1 as of now); +insert into t1 values (1); +select * from t1; +x +1 +select * from t1 partition (p0); +x +select * from t1 partition (p1); +x +1 +delete from t1; +select * from t1 partition (p0) for system_time all; +x +1 +select * from t1 partition (p1) for system_time all; +x +create or replace table t1 (x int) +with system versioning +engine myisam +partition by system_time limit 1 ( +partition p0 as of now, +partition p1 versioning, +partition p2 versioning); +Warnings: +Warning 4078 No `DEFAULT` for `VERSIONING` partitions. Setting `p1` as default. +insert into t1 values (1), (2); +select * from t1 partition (p0); +x +1 +2 +delete from t1; +Warnings: +Note 4079 Switching from partition `p1` to `p2` +select * from t1 partition (p1) for system_time all; +x +1 +select * from t1 partition (p2) for system_time all; +x +2 +insert into t1 values (3); +delete from t1; +Warnings: +Warning 4077 Using full partition `p2`, need more VERSIONING partitions! +select * from t1 partition (p2) for system_time all; +x +2 +3 +create or replace table t1 (x int) +with system versioning +engine myisam +partition by system_time interval 1 second ( +partition p0 as of now, +partition p1 versioning default, +partition p2 versioning); +insert into t1 values (1), (2), (3); +select * from t1 partition (p0); +x +1 +2 +3 +delete from t1; +select * from t1 partition (p1) for system_time all; +x +1 +2 +3 +insert into t1 values (4); +delete from t1; +Warnings: +Note 4079 Switching from partition `p1` to `p2` +select * from t1 partition (p2) for system_time all; +x +4 +create or replace table t1 (x int) +with system versioning +engine myisam +partition by system_time limit 1 ( +partition p0 as of now, +partition p1 versioning default, +partition p2 versioning default); +ERROR HY000: Wrong parameters for `BY SYSTEM_TIME`: multiple `DEFAULT` partitions +create or replace table t1 (x int) +with system versioning +engine myisam +partition by system_time limit 1 ( +partition p0 as of now, +partition p1 versioning, +partition p2 versioning default); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `x` int(11) DEFAULT NULL, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING + PARTITION BY SYSTEM_TIME LIMIT 1 +(PARTITION p0 AS OF NOW ENGINE = MyISAM, + PARTITION p1 VERSIONING ENGINE = MyISAM, + PARTITION p2 VERSIONING DEFAULT ENGINE = MyISAM) +insert into t1 values (4), (5); +delete from t1; +Warnings: +Note 4079 Switching from partition `p2` to `p1` +select * from t1 partition (p2) for system_time all; +x +4 +select * from t1 partition (p1) for system_time all; +x +5 +create or replace table t1 (x int) +with system versioning +engine myisam +partition by system_time limit 1 +subpartition by key (x) +subpartitions 2 ( +partition p0 as of now, +partition p1 versioning default, +partition p2 versioning); +insert into t1 (x) values (1), (2), (3); +select * from t1 partition (p0sp0); +x +1 +3 +select * from t1 partition (p0sp1); +x +2 +delete from t1; +Warnings: +Note 4079 Switching from partition `p1` to `p2` +Warning 4077 Using full partition `p2`, need more VERSIONING partitions! +select * from t1 partition (p1sp0) for system_time all; +x +1 +select * from t1 partition (p1sp1) for system_time all; +x +select * from t1 partition (p2sp0) for system_time all; +x +3 +select * from t1 partition (p2sp1) for system_time all; +x +2 +drop table t1; diff --git a/mysql-test/suite/versioning/t/partition.test b/mysql-test/suite/versioning/t/partition.test new file mode 100644 index 00000000000..c2b7c097a5f --- /dev/null +++ b/mysql-test/suite/versioning/t/partition.test @@ -0,0 +1,190 @@ +--source include/have_innodb.inc +--source include/have_partition.inc + +### check InnoDB versioning and conventional partitioning + +create table t1 (x int) +with system versioning +engine innodb +partition by range columns (x) ( + partition p0 values less than (100), + partition p1 values less than (1000)); + +insert into t1 values (3), (300); +select * from t1; +select * from t1 partition (p0); +select * from t1 partition (p1); + +delete from t1; +select * from t1; +select * from t1 for system_time all; +select * from t1 partition (p0) for system_time all; +select * from t1 partition (p1) for system_time all; + +### check server-level partitioning + +# create errors +--error ER_VERSIONING_REQUIRED +create or replace table t1 (x int) +partition by system_time ( + partition p0 as of now, + partition p1 versioning); + +create or replace table t1 (x int); +--error ER_VERSIONING_REQUIRED +alter table t1 +partition by system_time ( + partition p0 as of now, + partition p1 versioning); + +--error ER_VERS_WRONG_PARAMS +create or replace table t1 (x int) +with system versioning +partition by system_time ( + partition p0 as of now); + +--error ER_VERS_WRONG_PARAMS +create or replace table t1 (x int) +with system versioning +partition by system_time ( + partition p0 as of now, + partition p1 as of now); + +--error ER_VERS_WRONG_PARAMS +create or replace table t1 (x int) +with system versioning +partition by system_time ( + partition p0 versioning, + partition p1 versioning); + +create or replace table t1 (x int) +with system versioning +partition by system_time ( + partition p0 as of now, + partition p1 versioning); + +# alter table +--error ER_VERS_WRONG_PARAMS +alter table t1 add partition ( + partition p2 as of now); + +alter table t1 add partition ( + partition p2 versioning default); + +--error ER_VERS_WRONG_PARAMS +alter table t1 drop partition p0; +alter table t1 drop partition p2; +--error ER_VERS_WRONG_PARAMS +alter table t1 drop partition p1; + +# insertion, deletion +insert into t1 values (1); +select * from t1; +select * from t1 partition (p0); +select * from t1 partition (p1); + +delete from t1; +select * from t1 partition (p0) for system_time all; +select * from t1 partition (p1) for system_time all; + +create or replace table t1 (x int) +with system versioning +partition by system_time ( + partition p0 versioning, + partition p1 as of now); + +insert into t1 values (1); +select * from t1; +select * from t1 partition (p0); +select * from t1 partition (p1); + +delete from t1; +select * from t1 partition (p0) for system_time all; +select * from t1 partition (p1) for system_time all; + +# rotation by LIMIT +create or replace table t1 (x int) +with system versioning +engine myisam +partition by system_time limit 1 ( + partition p0 as of now, + partition p1 versioning, + partition p2 versioning); + +insert into t1 values (1), (2); +select * from t1 partition (p0); +delete from t1; +select * from t1 partition (p1) for system_time all; +select * from t1 partition (p2) for system_time all; + +insert into t1 values (3); +delete from t1; +select * from t1 partition (p2) for system_time all; + +# rotation by INTERVAL +create or replace table t1 (x int) +with system versioning +engine myisam +partition by system_time interval 1 second ( + partition p0 as of now, + partition p1 versioning default, + partition p2 versioning); + +insert into t1 values (1), (2), (3); +select * from t1 partition (p0); +delete from t1; +select * from t1 partition (p1) for system_time all; + +--sleep 2 +insert into t1 values (4); +delete from t1; +select * from t1 partition (p2) for system_time all; + +# DEFAULT partition +--error ER_VERS_WRONG_PARAMS +create or replace table t1 (x int) +with system versioning +engine myisam +partition by system_time limit 1 ( + partition p0 as of now, + partition p1 versioning default, + partition p2 versioning default); + +create or replace table t1 (x int) +with system versioning +engine myisam +partition by system_time limit 1 ( + partition p0 as of now, + partition p1 versioning, + partition p2 versioning default); + +show create table t1; + +insert into t1 values (4), (5); +delete from t1; +select * from t1 partition (p2) for system_time all; +select * from t1 partition (p1) for system_time all; + +# Subpartitions +create or replace table t1 (x int) +with system versioning +engine myisam +partition by system_time limit 1 +subpartition by key (x) +subpartitions 2 ( + partition p0 as of now, + partition p1 versioning default, + partition p2 versioning); + +insert into t1 (x) values (1), (2), (3); +select * from t1 partition (p0sp0); +select * from t1 partition (p0sp1); + +delete from t1; +select * from t1 partition (p1sp0) for system_time all; +select * from t1 partition (p1sp1) for system_time all; +select * from t1 partition (p2sp0) for system_time all; +select * from t1 partition (p2sp1) for system_time all; + +drop table t1; + diff --git a/mysql-test/t/parser.test b/mysql-test/t/parser.test index 98eaa7a7774..3be42eb0595 100644 --- a/mysql-test/t/parser.test +++ b/mysql-test/t/parser.test @@ -104,9 +104,7 @@ create table MIN (a int); drop table MIN; --error ER_PARSE_ERROR -create table NOW(a int); create table NOW (a int); -drop table NOW; --error ER_PARSE_ERROR create table POSITION(a int); diff --git a/sql/field.cc b/sql/field.cc index 295b22ad8ec..a83cbb20eff 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5468,8 +5468,15 @@ my_time_t Field_timestampf::get_timestamp(const uchar *pos, ulong *sec_part) const { struct timeval tm; - my_timestamp_from_binary(&tm, pos, dec); - *sec_part= tm.tv_usec; + if (sec_part) + { + my_timestamp_from_binary(&tm, pos ? pos : ptr, dec); + *sec_part= tm.tv_usec; + } + else + { + my_timestamp_from_binary(&tm, pos ? pos : ptr, 0); + } return tm.tv_sec; } diff --git a/sql/field.h b/sql/field.h index ab480b84fda..a6b1cace962 100644 --- a/sql/field.h +++ b/sql/field.h @@ -679,10 +679,6 @@ public: */ virtual bool set_max() { DBUG_ASSERT(0); return false; } - - /** - Used by System Versioning. - */ virtual bool is_max() { DBUG_ASSERT(0); return false; } @@ -971,6 +967,9 @@ public: } virtual bool set_explicit_default(Item *value); + virtual my_time_t get_timestamp(const uchar *pos= NULL, ulong *sec_part= NULL) const + { DBUG_ASSERT(0); return 0; } + /** Evaluates the @c UPDATE default function, if one exists, and stores the result in the record buffer. If no such function exists for the column, @@ -2544,7 +2543,7 @@ public: bool set_max(); bool is_max(); void store_TIME(my_time_t timestamp, ulong sec_part); - my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const; + my_time_t get_timestamp(const uchar *pos= NULL, ulong *sec_part= NULL) const; uint size_of() const { return sizeof(*this); } }; diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index b27de9dad4d..1ba3210d62b 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -2025,12 +2025,15 @@ int ha_partition::copy_partitions(ulonglong * const copied, else { THD *thd= ha_thd(); + handler *new_file= m_new_file[new_part]; /* Copy record to new handler */ (*copied)++; + if (new_file->ha_external_lock(thd, F_UNLCK) || new_file->ha_external_lock(thd, F_WRLCK)) + goto error; tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */ - result= m_new_file[new_part]->ha_write_row(m_rec0); + result= new_file->ha_write_row(m_rec0); reenable_binlog(thd); - if (result) + if (new_file->ha_external_lock(thd, F_UNLCK) || new_file->ha_external_lock(thd, F_RDLCK) || result) goto error; } } diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 70ec4ae8edb..1ca320eef1a 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -23,7 +23,7 @@ enum partition_keywords { - PKW_HASH= 0, PKW_RANGE, PKW_LIST, PKW_KEY, PKW_MAXVALUE, PKW_LINEAR, + PKW_HASH= 0, PKW_RANGE, PKW_LIST, PKW_SYSTEM_TIME, PKW_KEY, PKW_MAXVALUE, PKW_LINEAR, PKW_COLUMNS, PKW_ALGORITHM }; @@ -1277,6 +1277,38 @@ public: return h; } + virtual bool versioned() const + { + return m_innodb; + } + + virtual ha_rows part_recs_slow(void *_part_elem) + { + partition_element *part_elem= reinterpret_cast(_part_elem); + DBUG_ASSERT(m_part_info); + uint32 sub_factor= m_part_info->num_subparts ? m_part_info->num_subparts : 1; + uint32 part_id= part_elem->id * sub_factor; + uint32 part_id_end= part_id + sub_factor; + DBUG_ASSERT(part_id_end <= m_tot_parts); + ha_rows part_recs= 0; + for (; part_id < part_id_end; ++part_id) + { + handler *file= m_file[part_id]; + DBUG_ASSERT(bitmap_is_set(&(m_part_info->read_partitions), part_id)); + file->info(HA_STATUS_TIME | HA_STATUS_VARIABLE | + HA_STATUS_VARIABLE_EXTRA | HA_STATUS_NO_LOCK); + + part_recs+= file->stats.records; + } + return part_recs; + } + + virtual handler* part_handler(uint32 part_id) + { + DBUG_ASSERT(part_id < m_tot_parts); + return m_file[part_id]; + } + friend int cmp_key_rowid_part_id(void *ptr, uchar *ref1, uchar *ref2); }; diff --git a/sql/handler.cc b/sql/handler.cc index f9391729e99..62c628a01dc 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6571,7 +6571,7 @@ static bool create_string(MEM_ROOT *mem_root, String **s, const char *value) return *s == NULL; } -static bool create_sys_trx_field(THD *thd, const char *field_name, +static bool vers_create_sys_field(THD *thd, const char *field_name, Alter_info *alter_info, String **s, int flags, bool integer_fields) @@ -6616,16 +6616,19 @@ bool Vers_parse_info::fix_implicit(THD *thd, Alter_info *alter_info, alter_info->flags|= Alter_info::ALTER_ADD_COLUMN; - return create_sys_trx_field(thd, "sys_trx_start", alter_info, + static const char * sys_trx_start= "sys_trx_start"; + static const char * sys_trx_end= "sys_trx_end"; + + return vers_create_sys_field(thd, sys_trx_start, alter_info, &generated_as_row.start, VERS_SYS_START_FLAG, integer_fields) || - create_sys_trx_field(thd, "sys_trx_end", alter_info, + vers_create_sys_field(thd, sys_trx_end, alter_info, &generated_as_row.end, VERS_SYS_END_FLAG, integer_fields) || create_string(thd->mem_root, &period_for_system_time.start, - "sys_trx_start") || + sys_trx_start) || create_string(thd->mem_root, &period_for_system_time.end, - "sys_trx_end"); + sys_trx_end); } bool Vers_parse_info::check_and_fix_implicit( diff --git a/sql/handler.h b/sql/handler.h index ced716ed11a..5bcacf1f50b 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1390,7 +1390,6 @@ struct handlerton /* System Versioning */ - bool versioned() const; bool (*vers_query_trx_id)(THD* thd, void *out, ulonglong trx_id, vtq_field_t field); bool (*vers_query_commit_ts)(THD* thd, void *out, const MYSQL_TIME &commit_ts, vtq_field_t field, bool backwards); bool (*vers_trx_sees)(THD *thd, bool &result, ulonglong trx_id1, ulonglong trx_id0, ulonglong commit_id1, uchar iso_level1, ulonglong commit_id0); @@ -4332,6 +4331,13 @@ public: */ virtual int find_unique_row(uchar *record, uint unique_ref) { return -1; /*unsupported */} + + virtual bool versioned() const + { DBUG_ASSERT(ht); return partition_ht()->flags & HTON_SUPPORTS_SYS_VERSIONING; } + virtual ha_rows part_recs_slow(void *_part_elem) + { DBUG_ASSERT(0); return false; } + virtual handler* part_handler(uint32 part_id) + { DBUG_ASSERT(0); return NULL; } protected: Handler_share *get_ha_share_ptr(); void set_ha_share_ptr(Handler_share *arg_ha_share); @@ -4522,10 +4528,4 @@ void print_keydup_error(TABLE *table, KEY *key, myf errflag); int del_global_index_stat(THD *thd, TABLE* table, KEY* key_info); int del_global_table_stat(THD *thd, LEX_STRING *db, LEX_STRING *table); - -inline -bool handlerton::versioned() const -{ - return flags & HTON_SUPPORTS_SYS_VERSIONING; -} #endif /* HANDLER_INCLUDED */ diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 9a0c8efb031..2f9b467408f 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -3314,7 +3314,7 @@ VTQ_common::init_hton() f->field->table && f->field->table->s && f->field->table->s->db_plugin); - hton= plugin_hton(f->field->table->s->db_plugin); + hton= f->field->table->file->partition_ht(); DBUG_ASSERT(hton); } else if (innodb_plugin) @@ -3322,7 +3322,7 @@ VTQ_common::init_hton() hton= plugin_hton(plugin_int_to_ref(innodb_plugin)); DBUG_ASSERT(hton); } - if (hton && !hton->versioned()) + if (hton && !(hton->flags & HTON_SUPPORTS_SYS_VERSIONING)) { my_error(ER_VERS_ENGINE_UNSUPPORTED, MYF(0), Item::name ? Item::name : this->func_name()); hton= NULL; diff --git a/sql/lex.h b/sql/lex.h index dff6624518a..73d661e376a 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -428,6 +428,7 @@ static SYMBOL symbols[] = { { "NONE", SYM(NONE_SYM)}, { "NOT", SYM(NOT_SYM)}, { "NOTFOUND", SYM(NOTFOUND_SYM)}, + { "NOW", SYM(NOW_SYM)}, { "NO_WRITE_TO_BINLOG", SYM(NO_WRITE_TO_BINLOG)}, { "NULL", SYM(NULL_SYM)}, { "NUMBER", SYM(NUMBER_SYM)}, @@ -693,7 +694,7 @@ static SYMBOL symbols[] = { { "VIA", SYM(VIA_SYM)}, { "VIEW", SYM(VIEW_SYM)}, { "VIRTUAL", SYM(VIRTUAL_SYM)}, - { "VERSIONING", SYM(VERSIONING)}, + { "VERSIONING", SYM(VERSIONING_SYM)}, { "WAIT", SYM(WAIT_SYM)}, { "WARNINGS", SYM(WARNINGS)}, { "WEEK", SYM(WEEK_SYM)}, @@ -740,7 +741,6 @@ static SYMBOL sql_functions[] = { { "MAX", SYM(MAX_SYM)}, { "MID", SYM(SUBSTRING)}, /* unireg function */ { "MIN", SYM(MIN_SYM)}, - { "NOW", SYM(NOW_SYM)}, { "NTH_VALUE", SYM(NTH_VALUE_SYM)}, { "NTILE", SYM(NTILE_SYM)}, { "POSITION", SYM(POSITION_SYM)}, diff --git a/sql/mysqld.cc b/sql/mysqld.cc index c497a41673e..acda4b51627 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -933,6 +933,9 @@ PSI_mutex_key key_LOCK_prepare_ordered, key_LOCK_commit_ordered, key_LOCK_slave_background; PSI_mutex_key key_TABLE_SHARE_LOCK_share; +PSI_mutex_key key_TABLE_SHARE_LOCK_rotation; +PSI_cond_key key_TABLE_SHARE_COND_rotation; + static PSI_mutex_info all_server_mutexes[]= { #ifdef HAVE_MMAP @@ -993,6 +996,7 @@ static PSI_mutex_info all_server_mutexes[]= { &key_structure_guard_mutex, "Query_cache::structure_guard_mutex", 0}, { &key_TABLE_SHARE_LOCK_ha_data, "TABLE_SHARE::LOCK_ha_data", 0}, { &key_TABLE_SHARE_LOCK_share, "TABLE_SHARE::LOCK_share", 0}, + { &key_TABLE_SHARE_LOCK_rotation, "TABLE_SHARE::LOCK_rotation", 0}, { &key_LOCK_error_messages, "LOCK_error_messages", PSI_FLAG_GLOBAL}, { &key_LOCK_prepare_ordered, "LOCK_prepare_ordered", PSI_FLAG_GLOBAL}, { &key_LOCK_after_binlog_sync, "LOCK_after_binlog_sync", PSI_FLAG_GLOBAL}, @@ -1108,7 +1112,8 @@ static PSI_cond_info all_server_conds[]= { &key_COND_slave_background, "COND_slave_background", 0}, { &key_COND_start_thread, "COND_start_thread", PSI_FLAG_GLOBAL}, { &key_COND_wait_gtid, "COND_wait_gtid", 0}, - { &key_COND_gtid_ignore_duplicates, "COND_gtid_ignore_duplicates", 0} + { &key_COND_gtid_ignore_duplicates, "COND_gtid_ignore_duplicates", 0}, + { &key_TABLE_SHARE_COND_rotation, "TABLE_SHARE::COND_rotation", 0} }; PSI_thread_key key_thread_bootstrap, key_thread_delayed_insert, diff --git a/sql/mysqld.h b/sql/mysqld.h index 9f9e9a3ae66..8ac0625b755 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -308,7 +308,8 @@ extern PSI_mutex_key key_LOCK_slave_state, key_LOCK_binlog_state, extern PSI_mutex_key key_TABLE_SHARE_LOCK_share, key_LOCK_stats, key_LOCK_global_user_client_stats, key_LOCK_global_table_stats, - key_LOCK_global_index_stats, key_LOCK_wakeup_ready, key_LOCK_wait_commit; + key_LOCK_global_index_stats, key_LOCK_wakeup_ready, key_LOCK_wait_commit, + key_TABLE_SHARE_LOCK_rotation; extern PSI_mutex_key key_LOCK_gtid_waiting; extern PSI_rwlock_key key_rwlock_LOCK_grant, key_rwlock_LOCK_logger, @@ -342,6 +343,7 @@ extern PSI_cond_key key_COND_rpl_thread, key_COND_rpl_thread_queue, key_COND_rpl_thread_stop, key_COND_rpl_thread_pool, key_COND_parallel_entry, key_COND_group_commit_orderer; extern PSI_cond_key key_COND_wait_gtid, key_COND_gtid_ignore_duplicates; +extern PSI_cond_key key_TABLE_SHARE_COND_rotation; extern PSI_thread_key key_thread_bootstrap, key_thread_delayed_insert, key_thread_handle_manager, key_thread_kill_server, key_thread_main, diff --git a/sql/partition_element.h b/sql/partition_element.h index b979b7a58e6..e76558bf7ae 100644 --- a/sql/partition_element.h +++ b/sql/partition_element.h @@ -26,7 +26,8 @@ enum partition_type { NOT_A_PARTITION= 0, RANGE_PARTITION, HASH_PARTITION, - LIST_PARTITION + LIST_PARTITION, + VERSIONING_PARTITION }; enum partition_state { @@ -89,6 +90,37 @@ typedef struct p_elem_val struct st_ddl_log_memory_entry; +class Stat_timestampf : public Sql_alloc +{ + static const uint buf_size= 4 + (TIME_SECOND_PART_DIGITS + 1) / 2; + uchar min_buf[buf_size]; + uchar max_buf[buf_size]; + Field_timestampf min_value; + Field_timestampf max_value; + +public: + Stat_timestampf(const char *field_name, TABLE_SHARE *share) : + min_value(min_buf, NULL, 0, Field::NONE, field_name, share, 6), + max_value(max_buf, NULL, 0, Field::NONE, field_name, share, 6) + { + min_value.set_max(); + memset(max_buf, 0, buf_size); + } + void update(Field *from) + { + from->update_min(&min_value, false); + from->update_max(&max_value, false); + } + my_time_t min_time() + { + return min_value.get_timestamp(); + } + my_time_t max_time() + { + return max_value.get_timestamp(); + } +}; + class partition_element :public Sql_alloc { public: List subpartitions; @@ -109,6 +141,17 @@ public: bool has_null_value; bool signed_flag; // Range value signed bool max_value; // MAXVALUE range + uint32 id; + + enum elem_type + { + CONVENTIONAL= 0, + AS_OF_NOW, + VERSIONING + }; + + elem_type type; + Stat_timestampf *stat_trx_end; partition_element() : part_max_rows(0), part_min_rows(0), range_value(0), @@ -117,7 +160,10 @@ public: data_file_name(NULL), index_file_name(NULL), engine_type(NULL), connect_string(null_lex_str), part_state(PART_NORMAL), nodegroup_id(UNDEF_NODEGROUP), has_null_value(FALSE), - signed_flag(FALSE), max_value(FALSE) + signed_flag(FALSE), max_value(FALSE), + id(UINT32_MAX), + type(CONVENTIONAL), + stat_trx_end(NULL) { } partition_element(partition_element *part_elem) @@ -132,7 +178,10 @@ public: connect_string(null_lex_str), part_state(part_elem->part_state), nodegroup_id(part_elem->nodegroup_id), - has_null_value(FALSE) + has_null_value(FALSE), + id(part_elem->id), + type(part_elem->type), + stat_trx_end(NULL) { } ~partition_element() {} diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 24506434a76..e83fced4495 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -30,6 +30,7 @@ #include "sql_parse.h" #include "sql_acl.h" // *_ACL #include "sql_base.h" // fill_record +#include "sql_statistics.h" // vers_stat_end #ifdef WITH_PARTITION_STORAGE_ENGINE #include "ha_partition.h" @@ -114,6 +115,19 @@ partition_info *partition_info::get_clone(THD *thd) part_clone->list_val_list.push_back(new_val, mem_root); } } + if (part_type == VERSIONING_PARTITION && vers_info) + { + // clone Vers_part_info; set now_part, hist_part + clone->vers_info= new (mem_root) Vers_part_info(*vers_info); + List_iterator it(clone->partitions); + while ((part= it++)) + { + if (vers_info->now_part && part->id == vers_info->now_part->id) + clone->vers_info->now_part= part; + else if (vers_info->hist_part && part->id == vers_info->hist_part->id) + clone->vers_info->hist_part= part; + } // while ((part= it++)) + } // if (part_type == VERSIONING_PARTITION ... DBUG_RETURN(clone); } @@ -777,6 +791,216 @@ bool partition_info::has_unique_name(partition_element *element) DBUG_RETURN(TRUE); } +bool partition_info::vers_init_info(THD * thd) +{ + part_type= VERSIONING_PARTITION; + list_of_part_fields= TRUE; + column_list= TRUE; + vers_info= new (thd->mem_root) Vers_part_info; + if (!vers_info) + { + mem_alloc_error(sizeof(Vers_part_info)); + return true; + } + return false; +} + +bool partition_info::vers_set_interval(const INTERVAL & i) +{ + if (i.neg) + { + my_error(ER_VERS_WRONG_PARAMS, MYF(0), "BY SYSTEM_TIME", "negative INTERVAL"); + return true; + } + if (i.second_part) + { + my_error(ER_VERS_WRONG_PARAMS, MYF(0), "BY SYSTEM_TIME", "second fractions in INTERVAL"); + return true; + } + + DBUG_ASSERT(vers_info); + + // TODO: INTERVAL conversion to seconds leads to mismatch with calendar intervals (MONTH and YEAR) + vers_info->interval= + i.second + + i.minute * 60 + + i.hour * 60 * 60 + + i.day * 24 * 60 * 60 + + i.month * 30 * 24 * 60 * 60 + + i.year * 365 * 30 * 24 * 60 * 60; + + if (vers_info->interval == 0) + { + my_error(ER_VERS_WRONG_PARAMS, MYF(0), "BY SYSTEM_TIME", "zero INTERVAL"); + return true; + } + return false; +} + +bool partition_info::vers_set_limit(ulonglong limit) +{ + if (limit < 1) + { + my_error(ER_VERS_WRONG_PARAMS, MYF(0), "BY SYSTEM_TIME", "non-positive LIMIT"); + return true; + } + DBUG_ASSERT(vers_info); + + vers_info->limit= limit; + return false; +} + +partition_element* +partition_info::vers_part_rotate(THD * thd) +{ + DBUG_ASSERT(table && table->s); + if (table->s->free_parts.is_empty()) + { + push_warning_printf(thd, + Sql_condition::WARN_LEVEL_WARN, + WARN_VERS_PART_FULL, + ER_THD(thd, WARN_VERS_PART_FULL), + vers_info->hist_part->partition_name); + return vers_info->hist_part; + } + + table->s->vers_part_rotate(); + DBUG_ASSERT(table->s->hist_part_id < num_parts); + const char* old_part_name= vers_info->hist_part->partition_name; + vers_hist_part(); + + push_warning_printf(thd, + Sql_condition::WARN_LEVEL_NOTE, + WARN_VERS_PART_ROTATION, + ER_THD(thd, WARN_VERS_PART_ROTATION), + old_part_name, + vers_info->hist_part->partition_name); + + return vers_info->hist_part; +} + +bool partition_info::vers_setup_1(THD * thd) +{ + DBUG_ASSERT(part_type == VERSIONING_PARTITION); + if (!table->versioned()) + { + my_error(ER_VERSIONING_REQUIRED, MYF(0), "`BY SYSTEM_TIME` partitioning"); + return true; + } + Field *sys_trx_end= table->vers_end_field(); + part_field_list.empty(); + part_field_list.push_back(const_cast(sys_trx_end->field_name), thd->mem_root); + sys_trx_end->flags|= GET_FIXED_FIELDS_FLAG; // needed in handle_list_of_fields() + return false; +} + + +// scan table for min/max sys_trx_end +inline +bool partition_info::vers_scan_min_max(THD *thd, partition_element *part) +{ + uint32 sub_factor= num_subparts ? num_subparts : 1; + uint32 part_id= part->id * sub_factor; + uint32 part_id_end= part_id + sub_factor; + for (; part_id < part_id_end; ++part_id) + { + handler *file= table->file->part_handler(part_id); + int rc= file->ha_external_lock(thd, F_RDLCK); + if (rc) + goto error; + rc= file->ha_rnd_init(true); + if (!rc) + { + while ((rc= file->ha_rnd_next(table->record[0])) != HA_ERR_END_OF_FILE) + { + if (thd->killed) + { + file->ha_rnd_end(); + return true; + } + if (rc) + { + if (rc == HA_ERR_RECORD_DELETED) + continue; + break; + } + part->stat_trx_end->update(table->vers_end_field()); + } + file->ha_rnd_end(); + } + file->ha_external_lock(thd, F_UNLCK); + if (rc != HA_ERR_END_OF_FILE) + { + error: + my_error(ER_INTERNAL_ERROR, MYF(0), "partition/subpartition scan failed in versioned partitions setup"); + return true; + } + } + return false; +} + + +// setup at open stage (TABLE_SHARE is initialized) +bool partition_info::vers_setup_2(THD * thd, bool is_create_table_ind) +{ + DBUG_ASSERT(part_type == VERSIONING_PARTITION); + DBUG_ASSERT(vers_info && vers_info->initialized(is_create_table_ind) && vers_info->hist_default != UINT32_MAX); + DBUG_ASSERT(table && table->s); + if (!table->versioned_by_sql()) + { + my_error(ER_VERS_WRONG_PARAMS, MYF(0), table->s->table_name.str, "selected engine is not supported in `BY SYSTEM_TIME` partitioning"); + return true; + } + mysql_mutex_lock(&table->s->LOCK_rotation); + if (table->s->busy_rotation) + { + table->s->vers_wait_rotation(); + vers_hist_part(); + } + else + { + table->s->busy_rotation= true; + mysql_mutex_unlock(&table->s->LOCK_rotation); + // build freelist, scan min/max, assign hist_part + List_iterator it(partitions); + partition_element *el; + while ((el= it++)) + { + DBUG_ASSERT(el->type != partition_element::CONVENTIONAL); + if (el->type == partition_element::VERSIONING) + { + DBUG_ASSERT(!el->stat_trx_end); + el->stat_trx_end= new (&table->mem_root) + Stat_timestampf(table->s->vers_end_field()->field_name, table->s); + if (!is_create_table_ind && vers_scan_min_max(thd, el)) + return true; + } + if (el == vers_info->now_part || el == vers_info->hist_part) + continue; + if (!vers_info->hist_part && el->id == vers_info->hist_default) + { + vers_info->hist_part= el; + } + if (is_create_table_ind || ( + table->s->free_parts_init && + !vers_limit_exceed(el) && + !vers_interval_exceed(el))) + { + table->s->free_parts.push_back((void *) el->id, &table->s->mem_root); + } + } + table->s->hist_part_id= vers_info->hist_part->id; + if (!is_create_table_ind && (vers_limit_exceed() || vers_interval_exceed())) + vers_part_rotate(thd); + table->s->free_parts_init= false; + mysql_mutex_lock(&table->s->LOCK_rotation); + mysql_cond_broadcast(&table->s->COND_rotation); + table->s->busy_rotation= false; + } + mysql_mutex_unlock(&table->s->LOCK_rotation); + return false; +} + /* Check that the partition/subpartition is setup to use the correct @@ -1383,6 +1607,9 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, uint i, tot_partitions; bool result= TRUE, table_engine_set; char *same_name; + uint32 hist_parts= 0; + uint32 now_parts= 0; + const char* hist_default= NULL; DBUG_ENTER("partition_info::check_partition_info"); DBUG_ASSERT(default_engine_type != partition_hton); @@ -1424,7 +1651,8 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, } if (unlikely(is_sub_partitioned() && (!(part_type == RANGE_PARTITION || - part_type == LIST_PARTITION)))) + part_type == LIST_PARTITION || + part_type == VERSIONING_PARTITION)))) { /* Only RANGE and LIST partitioning can be subpartitioned */ my_error(ER_SUBPARTITION_ERROR, MYF(0)); @@ -1486,6 +1714,23 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, my_error(ER_SAME_NAME_PARTITION, MYF(0), same_name); goto end; } + + if (part_type == VERSIONING_PARTITION) + { + if (num_parts < 2) + { + my_error(ER_VERS_WRONG_PARAMS, MYF(0), "BY SYSTEM_TIME", "unexpected number of partitions (expected > 1)"); + goto end; + } + DBUG_ASSERT(vers_info); + if (!vers_info->now_part) + { + my_error(ER_VERS_WRONG_PARAMS, MYF(0), "BY SYSTEM_TIME", "no `AS OF NOW` partition defined"); + goto end; + } + DBUG_ASSERT(vers_info->initialized(false)); + DBUG_ASSERT(num_parts == partitions.elements); + } i= 0; { List_iterator part_it(partitions); @@ -1566,6 +1811,25 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, } } } + if (part_type == VERSIONING_PARTITION) + { + if (part_elem->type == partition_element::VERSIONING) + { + hist_parts++; + if (vers_info->hist_default == UINT32_MAX) + { + vers_info->hist_default= part_elem->id; + hist_default= part_elem->partition_name; + } + if (vers_info->hist_default == part_elem->id) + vers_info->hist_part= part_elem; + } + else + { + DBUG_ASSERT(part_elem->type == partition_element::AS_OF_NOW); + now_parts++; + } + } } while (++i < num_parts); if (!table_engine_set && num_parts_not_set != 0 && @@ -1603,6 +1867,31 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, check_list_constants(thd)))) goto end; } + + if (hist_parts > 1) + { + if (vers_info->limit == 0 && vers_info->interval == 0) + { + push_warning_printf(thd, + Sql_condition::WARN_LEVEL_WARN, + WARN_VERS_PARAMETERS, + ER_THD(thd, WARN_VERS_PARAMETERS), + "no rotation condition for multiple `VERSIONING` partitions."); + } + if (hist_default) + { + push_warning_printf(thd, + Sql_condition::WARN_LEVEL_WARN, + WARN_VERS_PARAMETERS, + "No `DEFAULT` for `VERSIONING` partitions. Setting `%s` as default.", + hist_default); + } + } + if (now_parts > 1) + { + my_error(ER_VERS_WRONG_PARAMS, MYF(0), "BY SYSTEM_TIME", "multiple `AS OF NOW` partitions"); + goto end; + } result= FALSE; end: DBUG_RETURN(result); diff --git a/sql/partition_info.h b/sql/partition_info.h index d4c180ddcdd..844956594ff 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -34,6 +34,46 @@ typedef int (*get_subpart_id_func)(partition_info *part_info, struct st_ddl_log_memory_entry; +struct Vers_part_info : public Sql_alloc +{ + Vers_part_info() : + interval(0), + limit(0), + now_part(NULL), + hist_part(NULL), + hist_default(UINT32_MAX) + { + } + Vers_part_info(Vers_part_info &src) : + interval(src.interval), + limit(src.limit), + now_part(NULL), + hist_part(NULL), + hist_default(src.hist_default) + { + } + bool initialized(bool fully= true) + { + if (now_part) + { + DBUG_ASSERT( + now_part->id != UINT32_MAX && + now_part->type == partition_element::AS_OF_NOW && + (fully ? (bool) hist_part : true) && + (!hist_part || ( + hist_part->id != UINT32_MAX && + hist_part->type == partition_element::VERSIONING))); + return true; + } + return false; + } + my_time_t interval; + ulonglong limit; + partition_element *now_part; + partition_element *hist_part; + uint32 hist_default; +}; + class partition_info : public Sql_alloc { public: @@ -142,6 +182,7 @@ public: LIST_PART_ENTRY *list_array; part_column_list_val *range_col_array; part_column_list_val *list_col_array; + Vers_part_info *vers_info; }; /******************************************** @@ -354,6 +395,74 @@ private: bool add_named_partition(const char *part_name, uint length); public: bool has_unique_name(partition_element *element); + + bool vers_init_info(THD *thd); + bool vers_set_interval(const INTERVAL &i); + bool vers_set_limit(ulonglong limit); + partition_element* vers_part_rotate(THD *thd); + bool vers_setup_1(THD *thd); + bool vers_setup_2(THD *thd, bool is_create_table_ind); + bool vers_scan_min_max(THD *thd, partition_element *part); + + partition_element *vers_hist_part() + { + DBUG_ASSERT(table && table->s); + DBUG_ASSERT(vers_info && vers_info->initialized()); + DBUG_ASSERT(table->s->hist_part_id != UINT32_MAX); + if (table->s->hist_part_id == vers_info->hist_part->id) + return vers_info->hist_part; + + List_iterator it(partitions); + partition_element *el; + while ((el= it++)) + { + DBUG_ASSERT(el->type != partition_element::CONVENTIONAL); + if (el->type == partition_element::VERSIONING && + el->id == table->s->hist_part_id) + { + vers_info->hist_part= el; + return vers_info->hist_part; + } + } + DBUG_ASSERT(0); + return NULL; + } + bool vers_limit_exceed(partition_element *part= NULL) + { + DBUG_ASSERT(vers_info); + if (!vers_info->limit) + return false; + if (!part) + { + DBUG_ASSERT(vers_info->initialized()); + part= vers_hist_part(); + } + // TODO: cache thread-shared part_recs and increment on INSERT + return table->file->part_recs_slow(part) >= vers_info->limit; + } + bool vers_interval_exceed(my_time_t max_time, partition_element *part= NULL) + { + DBUG_ASSERT(vers_info); + if (!vers_info->interval) + return false; + if (!part) + { + DBUG_ASSERT(vers_info->initialized()); + part= vers_hist_part(); + } + DBUG_ASSERT(part->stat_trx_end); + max_time-= part->stat_trx_end->min_time(); + return max_time > vers_info->interval; + } + bool vers_interval_exceed(partition_element *part) + { + DBUG_ASSERT(part->stat_trx_end); + return vers_interval_exceed(part->stat_trx_end->max_time(), part); + } + bool vers_interval_exceed() + { + return vers_interval_exceed(vers_hist_part()); + } }; uint32 get_next_partition_id_range(struct st_partition_iter* part_iter); diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index f37070d9394..c25b8b655cd 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -5716,9 +5716,9 @@ ER_TOO_MANY_PARTITIONS_ERROR ger "Es wurden zu vielen Partitionen (einschließlich Unterpartitionen) definiert" swe "För många partitioner (inkluderande subpartitioner) definierades" ER_SUBPARTITION_ERROR - eng "It is only possible to mix RANGE/LIST partitioning with HASH/KEY partitioning for subpartitioning" - ger "RANGE/LIST-Partitionierung kann bei Unterpartitionen nur zusammen mit HASH/KEY-Partitionierung verwendet werden" - swe "Det är endast möjligt att blanda RANGE/LIST partitionering med HASH/KEY partitionering för subpartitionering" + eng "It is only possible to mix RANGE/LIST/SYSTEM_TIME partitioning with HASH/KEY partitioning for subpartitioning" + ger "RANGE/LIST-Partitionierung kann bei Unterpartitionen nur zusammen mit HASH/KEY/SYSTEM_TIME-Partitionierung verwendet werden" + swe "Det är endast möjligt att blanda RANGE/LIST/SYSTEM_TIME partitionering med HASH/KEY partitionering för subpartitionering" ER_CANT_CREATE_HANDLER_FILE eng "Failed to create specific handler file" ger "Erzeugen einer spezifischen Handler-Datei fehlgeschlagen" @@ -7500,7 +7500,7 @@ ER_VERS_FIELD_WRONG_TYPE eng "%`s must be of type %`s for versioned table %`s" ER_VERS_WRONG_PARAMS - eng "Wrong parameters for versioned table %`s: %s" + eng "Wrong parameters for %`s: %s" ER_VERS_ENGINE_UNSUPPORTED eng "Engine does not support System Versioning for %`s" @@ -7510,3 +7510,15 @@ ER_VERS_RANGE_UNITS_MISMATCH ER_NON_VERSIONED_FIELD_IN_VERSIONED_QUERY eng "Attempt to read unversioned field %`s in historical query" + +ER_PARTITION_WRONG_TYPE + eng "Wrong partition type, expected type: %`s" + +WARN_VERS_PART_FULL + eng "Using full partition %`s, need more VERSIONING partitions!" + +WARN_VERS_PARAMETERS + eng "Maybe missing parameters: %s" + +WARN_VERS_PART_ROTATION + eng "Switching from partition %`s to %`s" diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 5af9b326eba..775d0c0d023 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -221,7 +221,8 @@ int TABLE::delete_row() else { store_record(this, record[1]); - vers_end_field()->set_time(); + Field *sys_trx_end= vers_end_field(); + sys_trx_end->set_time(); error= file->ha_update_row(record[1], record[0]); } return error; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 4e71e792a08..816cd374e67 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -87,7 +87,8 @@ const LEX_STRING partition_keywords[]= { { C_STRING_WITH_LEN("HASH") }, { C_STRING_WITH_LEN("RANGE") }, - { C_STRING_WITH_LEN("LIST") }, + { C_STRING_WITH_LEN("LIST") }, + { C_STRING_WITH_LEN("SYSTEM_TIME") }, { C_STRING_WITH_LEN("KEY") }, { C_STRING_WITH_LEN("MAXVALUE") }, { C_STRING_WITH_LEN("LINEAR ") }, @@ -108,6 +109,7 @@ static int get_partition_id_list_col(partition_info *, uint32 *, longlong *); static int get_partition_id_list(partition_info *, uint32 *, longlong *); static int get_partition_id_range_col(partition_info *, uint32 *, longlong *); static int get_partition_id_range(partition_info *, uint32 *, longlong *); +static int vers_get_partition_id(partition_info *, uint32 *, longlong *); static int get_part_id_charset_func_part(partition_info *, uint32 *, longlong *); static int get_part_id_charset_func_subpart(partition_info *, uint32 *); static int get_partition_id_hash_nosub(partition_info *, uint32 *, longlong *); @@ -1318,6 +1320,24 @@ static void set_up_partition_func_pointers(partition_info *part_info) part_info->get_subpartition_id= get_partition_id_hash_sub; } } + else if (part_info->part_type == VERSIONING_PARTITION) + { + part_info->get_part_partition_id= vers_get_partition_id; + if (part_info->list_of_subpart_fields) + { + if (part_info->linear_hash_ind) + part_info->get_subpartition_id= get_partition_id_linear_key_sub; + else + part_info->get_subpartition_id= get_partition_id_key_sub; + } + else + { + if (part_info->linear_hash_ind) + part_info->get_subpartition_id= get_partition_id_linear_hash_sub; + else + part_info->get_subpartition_id= get_partition_id_hash_sub; + } + } else /* LIST Partitioning */ { if (part_info->column_list) @@ -1358,6 +1378,10 @@ static void set_up_partition_func_pointers(partition_info *part_info) else part_info->get_partition_id= get_partition_id_list; } + else if (part_info->part_type == VERSIONING_PARTITION) + { + part_info->get_partition_id= vers_get_partition_id; + } else /* HASH partitioning */ { if (part_info->list_of_part_fields) @@ -1630,6 +1654,7 @@ bool fix_partition_func(THD *thd, TABLE *table, } } DBUG_ASSERT(part_info->part_type != NOT_A_PARTITION); + DBUG_ASSERT(part_info->part_type != VERSIONING_PARTITION || part_info->column_list); /* Partition is defined. We need to verify that partitioning function is correct. @@ -1662,6 +1687,9 @@ bool fix_partition_func(THD *thd, TABLE *table, const char *error_str; if (part_info->column_list) { + if (part_info->part_type == VERSIONING_PARTITION && + part_info->vers_setup_1(thd)) + goto end; List_iterator it(part_info->part_field_list); if (unlikely(handle_list_of_fields(thd, it, table, part_info, FALSE))) goto end; @@ -1685,6 +1713,10 @@ bool fix_partition_func(THD *thd, TABLE *table, if (unlikely(part_info->check_list_constants(thd))) goto end; } + else if (part_info->part_type == VERSIONING_PARTITION) + { + error_str= partition_keywords[PKW_SYSTEM_TIME].str; + } else { DBUG_ASSERT(0); @@ -2355,6 +2387,23 @@ static int add_partition_values(File fptr, partition_info *part_info, } while (++i < num_items); err+= add_end_parenthesis(fptr); } + else if (part_info->part_type == VERSIONING_PARTITION) + { + switch (p_elem->type) + { + case partition_element::AS_OF_NOW: + err+= add_string(fptr, " AS OF NOW"); + break; + case partition_element::VERSIONING: + err+= add_string(fptr, " VERSIONING"); + DBUG_ASSERT(part_info->vers_info); + if (part_info->vers_info->hist_default == p_elem->id) + err+= add_string(fptr, " DEFAULT"); + break; + default: + DBUG_ASSERT(0 && "wrong p_elem->type"); + } + } end: return err; } @@ -2497,13 +2546,32 @@ char *generate_partition_syntax(THD *thd, partition_info *part_info, else err+= add_part_key_word(fptr, partition_keywords[PKW_HASH].str); break; + case VERSIONING_PARTITION: + err+= add_part_key_word(fptr, partition_keywords[PKW_SYSTEM_TIME].str); + break; default: DBUG_ASSERT(0); /* We really shouldn't get here, no use in continuing from here */ my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR)); DBUG_RETURN(NULL); } - if (part_info->part_expr) + if (part_info->part_type == VERSIONING_PARTITION) + { + Vers_part_info *vers_info= part_info->vers_info; + DBUG_ASSERT(vers_info); + if (vers_info->interval) + { + err+= add_string(fptr, "INTERVAL "); + err+= add_int(fptr, vers_info->interval); + err+= add_string(fptr, " SECOND "); + } + if (vers_info->limit) + { + err+= add_string(fptr, "LIMIT "); + err+= add_int(fptr, vers_info->limit); + } + } + else if (part_info->part_expr) { err+= add_begin_parenthesis(fptr); err+= add_string_len(fptr, part_info->part_func_string, @@ -3350,6 +3418,73 @@ int get_partition_id_range_col(partition_info *part_info, } +int vers_get_partition_id(partition_info *part_info, + uint32 *part_id, + longlong *func_value) +{ + DBUG_ENTER("vers_get_partition_id"); + Field *sys_trx_end= part_info->part_field_array[0]; + DBUG_ASSERT(sys_trx_end); + DBUG_ASSERT(part_info->table); + Vers_part_info *vers_info= part_info->vers_info; + DBUG_ASSERT(vers_info && vers_info->initialized()); + DBUG_ASSERT(sys_trx_end->table == part_info->table && part_info->table->versioned()); + DBUG_ASSERT(part_info->table->vers_end_field() == sys_trx_end); + + // new rows have NULL in sys_trx_end + if (sys_trx_end->is_max() || sys_trx_end->is_null()) + { + *part_id= vers_info->now_part->id; + } + else // row is historical + { + partition_element *part= vers_info->hist_part; + THD *thd= current_thd; + TABLE *table= part_info->table; + + switch (thd->lex->sql_command) + { + case SQLCOM_DELETE: + case SQLCOM_DELETE_MULTI: + case SQLCOM_UPDATE: + case SQLCOM_UPDATE_MULTI: + case SQLCOM_ALTER_TABLE: + mysql_mutex_lock(&table->s->LOCK_rotation); + if (table->s->busy_rotation) + { + table->s->vers_wait_rotation(); + part_info->vers_hist_part(); + } + else + { + table->s->busy_rotation= true; + mysql_mutex_unlock(&table->s->LOCK_rotation); + if (part_info->vers_limit_exceed() || part_info->vers_interval_exceed(sys_trx_end->get_timestamp())) + { + part= part_info->vers_part_rotate(thd); + } + mysql_mutex_lock(&table->s->LOCK_rotation); + mysql_cond_broadcast(&table->s->COND_rotation); + table->s->busy_rotation= false; + } + mysql_mutex_unlock(&table->s->LOCK_rotation); + if (vers_info->interval) + { + DBUG_ASSERT(part->stat_trx_end); + part->stat_trx_end->update(sys_trx_end); + } + break; + default: + ; + } + *part_id= vers_info->hist_part->id; + } + + DBUG_PRINT("exit",("partition: %d", *part_id)); + DBUG_RETURN(0); +} + + int get_partition_id_range(partition_info *part_info, uint32 *part_id, longlong *func_value) @@ -4954,7 +5089,8 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, must know the number of new partitions in this case. */ if (thd->lex->no_write_to_binlog && - tab_part_info->part_type != HASH_PARTITION) + tab_part_info->part_type != HASH_PARTITION && + tab_part_info->part_type != VERSIONING_PARTITION) { my_error(ER_NO_BINLOG_ERROR, MYF(0)); goto err; @@ -5206,16 +5342,27 @@ that are reorganised. List_iterator part_it(tab_part_info->partitions); tab_part_info->is_auto_partitioned= FALSE; - if (!(tab_part_info->part_type == RANGE_PARTITION || - tab_part_info->part_type == LIST_PARTITION)) + if (tab_part_info->part_type == VERSIONING_PARTITION) { - my_error(ER_ONLY_ON_RANGE_LIST_PARTITION, MYF(0), "DROP"); - goto err; + if (num_parts_dropped >= tab_part_info->num_parts - 1) + { + my_error(ER_VERS_WRONG_PARAMS, MYF(0), "BY SYSTEM_TIME", "one `AS OF NOW` and at least one `VERSIONING` partition required"); + goto err; + } } - if (num_parts_dropped >= tab_part_info->num_parts) + else { - my_error(ER_DROP_LAST_PARTITION, MYF(0)); - goto err; + if (!(tab_part_info->part_type == RANGE_PARTITION || + tab_part_info->part_type == LIST_PARTITION)) + { + my_error(ER_ONLY_ON_RANGE_LIST_PARTITION, MYF(0), "DROP"); + goto err; + } + if (num_parts_dropped >= tab_part_info->num_parts) + { + my_error(ER_DROP_LAST_PARTITION, MYF(0)); + goto err; + } } do { @@ -5223,6 +5370,11 @@ that are reorganised. if (is_name_in_list(part_elem->partition_name, alter_info->partition_names)) { + if (part_elem->type == partition_element::AS_OF_NOW) + { + my_error(ER_VERS_WRONG_PARAMS, MYF(0), "BY SYSTEM_TIME", "`AS OF NOW` partition can not be dropped"); + goto err; + } /* Set state to indicate that the partition is to be dropped. */ diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 5a640ccb613..93836c82085 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -7030,6 +7030,11 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables, partition_keywords[PKW_HASH].length); table->field[7]->store(tmp_res.ptr(), tmp_res.length(), cs); break; + case VERSIONING_PARTITION: + tmp_res.length(0); + tmp_res.append(partition_keywords[PKW_SYSTEM_TIME].str, + partition_keywords[PKW_SYSTEM_TIME].length); + break; default: DBUG_ASSERT(0); my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR)); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index f91568e9fb1..f591566d91a 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1560,7 +1560,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token VARIANCE_SYM %token VARYING /* SQL-2003-R */ %token VAR_SAMP_SYM -%token VERSIONING /* 32N2439 */ +%token VERSIONING_SYM /* 32N2439 */ %token VIA_SYM %token VIEW_SYM /* SQL-2003-N */ %token VIRTUAL_SYM @@ -4910,6 +4910,10 @@ part_type_def: { Lex->part_info->part_type= LIST_PARTITION; } | LIST_SYM part_column_list { Lex->part_info->part_type= LIST_PARTITION; } + | SYSTEM_TIME_SYM + { if (Lex->part_info->vers_init_info(thd)) MYSQL_YYABORT; } + opt_versioning_interval + opt_versioning_limit ; opt_linear: @@ -5117,6 +5121,7 @@ part_definition: MYSQL_YYABORT; } p_elem->part_state= PART_NORMAL; + p_elem->id= part_info->partitions.elements - 1; part_info->curr_part_elem= p_elem; part_info->current_partition= p_elem; part_info->use_default_partitions= FALSE; @@ -5185,6 +5190,42 @@ opt_part_values: part_info->part_type= LIST_PARTITION; } part_values_in {} + | AS OF_SYM NOW_SYM + { + LEX *lex= Lex; + partition_info *part_info= lex->part_info; + if (! lex->is_partition_management()) + { + if (part_info->part_type != VERSIONING_PARTITION) + my_yyabort_error((ER_PARTITION_WRONG_TYPE, MYF(0), + "BY SYSTEM_TIME")); + } + else + { + part_info->vers_init_info(thd); + } + partition_element *elem= part_info->curr_part_elem; + elem->type= partition_element::AS_OF_NOW; + DBUG_ASSERT(part_info->vers_info); + part_info->vers_info->now_part= elem; + } + | VERSIONING_SYM + { + LEX *lex= Lex; + partition_info *part_info= lex->part_info; + if (! lex->is_partition_management()) + { + if (part_info->part_type != VERSIONING_PARTITION) + my_yyabort_error((ER_PARTITION_WRONG_TYPE, MYF(0), + "BY SYSTEM_TIME")); + } + else + { + part_info->vers_init_info(thd); + } + part_info->curr_part_elem->type= partition_element::VERSIONING; + } + opt_default_hist_part | DEFAULT { LEX *lex= Lex; @@ -5430,6 +5471,7 @@ sub_part_definition: mem_alloc_error(sizeof(partition_element)); MYSQL_YYABORT; } + sub_p_elem->id= curr_part->subpartitions.elements - 1; part_info->curr_part_elem= sub_p_elem; part_info->use_default_subpartitions= FALSE; part_info->use_default_num_subpartitions= FALSE; @@ -5486,6 +5528,45 @@ opt_part_option: { Lex->part_info->curr_part_elem->part_comment= $3.str; } ; +opt_versioning_interval: + /* empty */ {} + | INTERVAL_SYM expr interval + { + partition_info *part_info= Lex->part_info; + DBUG_ASSERT(part_info->part_type == VERSIONING_PARTITION); + INTERVAL interval; + if (get_interval_value($2, $3, &interval)) + my_yyabort_error((ER_VERS_WRONG_PARAMS, MYF(0), "BY SYSTEM_TIME", "wrong INTERVAL value")); + if (part_info->vers_set_interval(interval)) + MYSQL_YYABORT; + } + ; + +opt_versioning_limit: + /* empty */ {} + | LIMIT ulonglong_num + { + partition_info *part_info= Lex->part_info; + DBUG_ASSERT(part_info->part_type == VERSIONING_PARTITION); + if (part_info->vers_set_limit($2)) + MYSQL_YYABORT; + } + ; + +opt_default_hist_part: + /* empty */ {} + | DEFAULT + { + partition_info *part_info= Lex->part_info; + DBUG_ASSERT(part_info && part_info->vers_info && part_info->curr_part_elem); + if (part_info->vers_info->hist_part) + my_yyabort_error((ER_VERS_WRONG_PARAMS, MYF(0), + "BY SYSTEM_TIME", "multiple `DEFAULT` partitions")); + part_info->vers_info->hist_part= part_info->curr_part_elem; + part_info->vers_info->hist_default= part_info->curr_part_elem->id; + } + ; + /* End of partition parser part */ @@ -5853,7 +5934,7 @@ create_table_option: Lex->create_info.used_fields|= HA_CREATE_USED_SEQUENCE; Lex->create_info.sequence= $3; } - | WITH_SYSTEM_SYM VERSIONING + | WITH_SYSTEM_SYM VERSIONING_SYM { const char *table_name= Lex->create_last_non_select_table->table_name; @@ -5867,7 +5948,7 @@ create_table_option: info.declared_with_system_versioning= true; Lex->create_info.options|= HA_VERSIONED_TABLE; } - | WITHOUT SYSTEM VERSIONING + | WITHOUT SYSTEM VERSIONING_SYM { const char *table_name= Lex->create_last_non_select_table->table_name; @@ -6086,10 +6167,9 @@ period_for_system_time: Vers_parse_info &info= Lex->vers_get_info(); if (!my_strcasecmp(system_charset_info, $4->c_ptr(), $6->c_ptr())) { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), + my_yyabort_error((ER_VERS_WRONG_PARAMS, MYF(0), Lex->create_last_non_select_table->table_name, - "'PERIOD FOR SYSTEM_TIME' columns must be different"); - MYSQL_YYABORT; + "'PERIOD FOR SYSTEM_TIME' columns must be different")); } info.set_period_for_system_time($4, $6); } @@ -6221,8 +6301,7 @@ field_def: } if (*p) { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, err); - MYSQL_YYABORT; + my_yyabort_error((ER_VERS_WRONG_PARAMS, MYF(0), table_name, err)); } *p= field_name; } @@ -6698,7 +6777,7 @@ serial_attribute: new (thd->mem_root) engine_option_value($1, &Lex->last_field->option_list, &Lex->option_list_last); } - | WITH_SYSTEM_SYM VERSIONING + | WITH_SYSTEM_SYM VERSIONING_SYM { if (Lex->last_field->versioning != Column_definition::VERSIONING_NOT_SET) @@ -6711,7 +6790,7 @@ serial_attribute: Lex->create_info.vers_info.has_versioned_fields= true; Lex->create_info.options|= HA_VERSIONED_TABLE; } - | WITHOUT SYSTEM VERSIONING + | WITHOUT SYSTEM VERSIONING_SYM { if (Lex->last_field->versioning != Column_definition::VERSIONING_NOT_SET) diff --git a/sql/table.cc b/sql/table.cc index ad44f896621..ef8b3104165 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -426,6 +426,9 @@ void TABLE_SHARE::destroy() DBUG_ENTER("TABLE_SHARE::destroy"); DBUG_PRINT("info", ("db: %s table: %s", db.str, table_name.str)); + if (versioned) + vers_destroy(); + if (ha_share) { delete ha_share; @@ -2546,7 +2549,9 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, /* Set system versioning information. */ if (system_period == NULL) { - share->disable_system_versioning(); + versioned= false; + row_start_field = 0; + row_end_field = 0; } else { @@ -2555,9 +2560,11 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, uint16 row_end= uint2korr(system_period + sizeof(uint16)); if (row_start >= share->fields || row_end >= share->fields) goto err; - DBUG_PRINT("info", ("Columns with system versioning: [%d, %d]", row_start, - row_end)); - share->enable_system_versioning(row_start, row_end); + DBUG_PRINT("info", ("Columns with system versioning: [%d, %d]", row_start, row_end)); + versioned= true; + vers_init(); + row_start_field = row_start; + row_end_field = row_end; vers_start_field()->flags|= VERS_SYS_START_FLAG; vers_end_field()->flags|= VERS_SYS_END_FLAG; } // if (system_period == NULL) @@ -3403,6 +3410,17 @@ partititon_err: if (outparam->no_replicate || !binlog_filter->db_ok(outparam->s->db.str)) outparam->s->cached_row_logging_check= 0; // No row based replication +#ifdef WITH_PARTITION_STORAGE_ENGINE + if (outparam->part_info && + outparam->part_info->part_type == VERSIONING_PARTITION && + outparam->part_info->vers_setup_2(thd, is_create_table)) + { + error= OPEN_FRM_OPEN_ERROR; + error_reported= true; + goto err; + } +#endif + /* Increment the opened_tables counter, only when open flags set. */ if (db_stat) thd->status_var.opened_tables++; diff --git a/sql/table.h b/sql/table.h index b93bb3df5e3..fc7e639f162 100644 --- a/sql/table.h +++ b/sql/table.h @@ -561,6 +561,9 @@ struct TABLE_STATISTICS_CB bool histograms_are_read; }; +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif /** This structure is shared between different table objects. There is one @@ -748,19 +751,27 @@ struct TABLE_SHARE bool versioned; uint16 row_start_field; uint16 row_end_field; - - void enable_system_versioning(uint16 row_start, uint row_end) - { - versioned = true; - row_start_field = row_start; - row_end_field = row_end; + uint32 hist_part_id; + List free_parts; + bool free_parts_init; + bool busy_rotation; + mysql_mutex_t LOCK_rotation; + mysql_cond_t COND_rotation; + + void vers_init() + { + hist_part_id= UINT32_MAX; + busy_rotation= false; + free_parts.empty(); + free_parts_init= true; + mysql_mutex_init(key_TABLE_SHARE_LOCK_rotation, &LOCK_rotation, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_TABLE_SHARE_COND_rotation, &COND_rotation, NULL); } - void disable_system_versioning() + void vers_destroy() { - versioned = false; - row_start_field = 0; - row_end_field = 0; + mysql_mutex_destroy(&LOCK_rotation); + mysql_cond_destroy(&COND_rotation); } Field *vers_start_field() @@ -773,6 +784,18 @@ struct TABLE_SHARE return field[row_end_field]; } + void vers_part_rotate() + { + DBUG_ASSERT(!free_parts.is_empty()); + hist_part_id= (ulong)(void *)(free_parts.pop()); + } + + void vers_wait_rotation() + { + while (busy_rotation) + mysql_cond_wait(&COND_rotation, &LOCK_rotation); + } + /** Cache the checked structure of this table. @@ -1495,8 +1518,8 @@ public: /* Versioned by SQL layer */ bool versioned_by_sql() const { - DBUG_ASSERT(s->db_type()); - return s->versioned && !s->db_type()->versioned(); + DBUG_ASSERT(file); + return s->versioned && !file->versioned(); } Field *vers_start_field() const diff --git a/storage/tokudb/mysql-test/tokudb_parts/r/partition_syntax_tokudb.result b/storage/tokudb/mysql-test/tokudb_parts/r/partition_syntax_tokudb.result index 1b5d2870cda..5961197766b 100644 --- a/storage/tokudb/mysql-test/tokudb_parts/r/partition_syntax_tokudb.result +++ b/storage/tokudb/mysql-test/tokudb_parts/r/partition_syntax_tokudb.result @@ -510,7 +510,7 @@ f_charbig VARCHAR(1000) ) PARTITION BY RANGE(f_int1) ( PARTITION part1 VALUES LESS THAN (1000) (SUBPARTITION subpart11)); -ERROR HY000: It is only possible to mix RANGE/LIST partitioning with HASH/KEY partitioning for subpartitioning +ERROR HY000: It is only possible to mix RANGE/LIST/SYSTEM_TIME partitioning with HASH/KEY partitioning for subpartitioning #------------------------------------------------------------------------ # 2.2 Every partition must have the same number of subpartitions. # This is a limitation of MySQL 5.1, which could be removed in -- cgit v1.2.1 From 41d9840850746aa250fb63d9c83c44e1a9042941 Mon Sep 17 00:00:00 2001 From: kevg Date: Thu, 15 Dec 2016 13:04:45 +0300 Subject: SQL: remove unneded return value --- sql/field.cc | 7 +++---- sql/field.h | 8 ++++---- sql/table.cc | 3 +-- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index a83cbb20eff..3c34d973bf5 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4356,12 +4356,11 @@ void Field_longlong::sql_type(String &res) const add_zerofill_and_unsigned(res); } -bool Field_longlong::set_max() +void Field_longlong::set_max() { ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; set_notnull(); int8store(ptr, unsigned_flag ? ULONGLONG_MAX : LONGLONG_MAX); - return FALSE; } bool Field_longlong::is_max() @@ -5444,7 +5443,7 @@ void Field_timestampf::store_TIME(my_time_t timestamp, ulong sec_part) my_timestamp_to_binary(&tm, ptr, dec); } -bool Field_timestampf::set_max() +void Field_timestampf::set_max() { DBUG_ENTER("Field_timestampf::set_max"); ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; @@ -5453,7 +5452,7 @@ bool Field_timestampf::set_max() mi_int4store(ptr, TIMESTAMP_MAX_VALUE); memset(ptr + 4, 0x0, value_length() - 4); - DBUG_RETURN(FALSE); + DBUG_VOID_RETURN; } bool Field_timestampf::is_max() diff --git a/sql/field.h b/sql/field.h index a6b1cace962..e955323b917 100644 --- a/sql/field.h +++ b/sql/field.h @@ -677,8 +677,8 @@ public: /** Used by System Versioning. */ - virtual bool set_max() - { DBUG_ASSERT(0); return false; } + virtual void set_max() + { DBUG_ASSERT(0); } virtual bool is_max() { DBUG_ASSERT(0); return false; } @@ -2129,7 +2129,7 @@ public: return unpack_int64(to, from, from_end); } - bool set_max(); + void set_max(); bool is_max(); }; @@ -2540,7 +2540,7 @@ public: { return memcmp(a_ptr, b_ptr, pack_length()); } - bool set_max(); + void set_max(); bool is_max(); void store_TIME(my_time_t timestamp, ulong sec_part); my_time_t get_timestamp(const uchar *pos= NULL, ulong *sec_part= NULL) const; diff --git a/sql/table.cc b/sql/table.cc index ef8b3104165..4b7d5ef0d6f 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -7602,8 +7602,7 @@ void TABLE::vers_update_fields() if (vers_start_field()->set_time()) DBUG_ASSERT(0); - if (vers_end_field()->set_max()) - DBUG_ASSERT(0); + vers_end_field()->set_max(); DBUG_VOID_RETURN; } -- cgit v1.2.1 From ef10ef98ab6e44737474a93daca91c22ae25fefa Mon Sep 17 00:00:00 2001 From: kevg Date: Fri, 16 Dec 2016 14:11:23 +0300 Subject: SQL: UPDATE on row-based replication [closes: #94] --- mysql-test/suite/versioning/r/rpl_row.result | 41 +++++++++++++++++++++++++++ mysql-test/suite/versioning/r/rpl_stmt.result | 41 +++++++++++++++++++++++++++ mysql-test/suite/versioning/t/rpl_row.test | 7 +++++ mysql-test/suite/versioning/t/rpl_stmt.test | 7 +++++ mysql-test/suite/versioning/t/rpl_test.inc | 33 +++++++++++++++++++++ sql/ha_sequence.cc | 6 ++-- sql/handler.cc | 32 ++++++++++----------- 7 files changed, 148 insertions(+), 19 deletions(-) create mode 100644 mysql-test/suite/versioning/r/rpl_row.result create mode 100644 mysql-test/suite/versioning/r/rpl_stmt.result create mode 100644 mysql-test/suite/versioning/t/rpl_row.test create mode 100644 mysql-test/suite/versioning/t/rpl_stmt.test create mode 100644 mysql-test/suite/versioning/t/rpl_test.inc diff --git a/mysql-test/suite/versioning/r/rpl_row.result b/mysql-test/suite/versioning/r/rpl_row.result new file mode 100644 index 00000000000..b2d1adb7278 --- /dev/null +++ b/mysql-test/suite/versioning/r/rpl_row.result @@ -0,0 +1,41 @@ +include/master-slave.inc +[connection master] +connection slave; +connection master; +CREATE TABLE t1 (x int) with system versioning ENGINE = innodb; +insert into t1 values (1); +SELECT * FROM t1; +x +1 +delete from t1; +select * from t1; +x +select * from t1 for system_time all; +x +1 +connection slave; +select * from t1; +x +select * from t1 for system_time all; +x +1 +connection master; +insert into t1 values (2); +connection slave; +select * from t1; +x +2 +connection master; +update t1 set x = 3; +connection slave; +select * from t1; +x +3 +select * from t1 for system_time all; +x +1 +3 +2 +connection master; +drop table t1; +include/rpl_end.inc diff --git a/mysql-test/suite/versioning/r/rpl_stmt.result b/mysql-test/suite/versioning/r/rpl_stmt.result new file mode 100644 index 00000000000..b2d1adb7278 --- /dev/null +++ b/mysql-test/suite/versioning/r/rpl_stmt.result @@ -0,0 +1,41 @@ +include/master-slave.inc +[connection master] +connection slave; +connection master; +CREATE TABLE t1 (x int) with system versioning ENGINE = innodb; +insert into t1 values (1); +SELECT * FROM t1; +x +1 +delete from t1; +select * from t1; +x +select * from t1 for system_time all; +x +1 +connection slave; +select * from t1; +x +select * from t1 for system_time all; +x +1 +connection master; +insert into t1 values (2); +connection slave; +select * from t1; +x +2 +connection master; +update t1 set x = 3; +connection slave; +select * from t1; +x +3 +select * from t1 for system_time all; +x +1 +3 +2 +connection master; +drop table t1; +include/rpl_end.inc diff --git a/mysql-test/suite/versioning/t/rpl_row.test b/mysql-test/suite/versioning/t/rpl_row.test new file mode 100644 index 00000000000..cf04c52dd16 --- /dev/null +++ b/mysql-test/suite/versioning/t/rpl_row.test @@ -0,0 +1,7 @@ +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc +-- source include/have_innodb.inc + +-- source rpl_test.inc + +-- source include/rpl_end.inc diff --git a/mysql-test/suite/versioning/t/rpl_stmt.test b/mysql-test/suite/versioning/t/rpl_stmt.test new file mode 100644 index 00000000000..bc4e76cdf5d --- /dev/null +++ b/mysql-test/suite/versioning/t/rpl_stmt.test @@ -0,0 +1,7 @@ +-- source include/have_binlog_format_statement.inc +-- source include/master-slave.inc +-- source include/have_innodb.inc + +-- source rpl_test.inc + +-- source include/rpl_end.inc diff --git a/mysql-test/suite/versioning/t/rpl_test.inc b/mysql-test/suite/versioning/t/rpl_test.inc new file mode 100644 index 00000000000..abd156faa8c --- /dev/null +++ b/mysql-test/suite/versioning/t/rpl_test.inc @@ -0,0 +1,33 @@ +#BUG#12662190 - COM_COMMIT IS NOT INCREMENTED FROM THE BINARY LOGS ON SLAVE, COM_BEGIN IS +#Testing command counters -BEFORE. +#Storing the before counts of Slave +connection slave; +let $slave_com_commit_before= query_get_value(SHOW GLOBAL STATUS LIKE 'com_commit', Value, 1); +let $slave_com_insert_before= query_get_value(SHOW GLOBAL STATUS LIKE 'com_insert', Value, 1); +let $slave_com_delete_before= query_get_value(SHOW GLOBAL STATUS LIKE 'com_delete', Value, 1); +let $slave_com_update_before= query_get_value(SHOW GLOBAL STATUS LIKE 'com_update', Value, 1); + +connection master; +CREATE TABLE t1 (x int) with system versioning ENGINE = innodb; +insert into t1 values (1); +SELECT * FROM t1; +delete from t1; +select * from t1; +select * from t1 for system_time all; +sync_slave_with_master; +select * from t1; +select * from t1 for system_time all; + +connection master; +insert into t1 values (2); +sync_slave_with_master; +select * from t1; + +connection master; +update t1 set x = 3; +sync_slave_with_master; +select * from t1; +select * from t1 for system_time all; + +connection master; +drop table t1; diff --git a/sql/ha_sequence.cc b/sql/ha_sequence.cc index f3c4d8961a8..04df348ca6f 100644 --- a/sql/ha_sequence.cc +++ b/sql/ha_sequence.cc @@ -220,7 +220,8 @@ int ha_sequence::write_row(uchar *buf) sequence->copy(&tmp_seq); rows_changed++; /* We have to do the logging while we hold the sequence mutex */ - error= binlog_log_row(table, 0, buf, log_func); + if (table->file->check_table_binlog_row_based(1)) + error= binlog_log_row(table, 0, buf, log_func); row_already_logged= 1; } @@ -254,7 +255,8 @@ int ha_sequence::update_row(const uchar *old_data, uchar *new_data) sequence->copy(&tmp_seq); rows_changed++; /* We have to do the logging while we hold the sequence mutex */ - error= binlog_log_row(table, old_data, new_data, + if (table->file->check_table_binlog_row_based(1)) + error= binlog_log_row(table, old_data, new_data, Update_rows_log_event::binlog_row_logging_function); row_already_logged= 1; } diff --git a/sql/handler.cc b/sql/handler.cc index 62c628a01dc..b90ee5f6425 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -5795,10 +5795,10 @@ static int write_locked_table_maps(THD *thd) static int check_wsrep_max_ws_rows(); -static int binlog_log_row_internal(TABLE* table, - const uchar *before_record, - const uchar *after_record, - Log_func *log_func) +int binlog_log_row(TABLE* table, + const uchar *before_record, + const uchar *after_record, + Log_func *log_func) { bool error= 0; THD *const thd= table->in_use; @@ -5833,16 +5833,6 @@ static int binlog_log_row_internal(TABLE* table, return error ? HA_ERR_RBR_LOGGING_FAILED : 0; } -int binlog_log_row(TABLE* table, - const uchar *before_record, - const uchar *after_record, - Log_func *log_func) -{ - if (!table->file->check_table_binlog_row_based(1)) - return 0; - return binlog_log_row_internal(table, before_record, after_record, log_func); -} - int handler::ha_external_lock(THD *thd, int lock_type) { @@ -5991,7 +5981,8 @@ int handler::ha_write_row(uchar *buf) if (likely(!error) && !row_already_logged) { rows_changed++; - error= binlog_log_row(table, 0, buf, log_func); + if (table->file->check_table_binlog_row_based(1)) + error= binlog_log_row(table, 0, buf, log_func); } DEBUG_SYNC_C("ha_write_row_end"); DBUG_RETURN(error); @@ -6012,6 +6003,9 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data) DBUG_ASSERT(new_data == table->record[0]); DBUG_ASSERT(old_data == table->record[1]); + // InnoDB changes sys_trx_end to curr_trx_id and we need to restore MAX_TRX + if (table->file->check_table_binlog_row_based(1)) + memcpy(table->record[2], table->record[1], table->s->reclength); MYSQL_UPDATE_ROW_START(table_share->db.str, table_share->table_name.str); mark_trx_read_write(); increment_statistics(&SSV::ha_update_count); @@ -6023,7 +6017,10 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data) if (likely(!error) && !row_already_logged) { rows_changed++; - error= binlog_log_row(table, old_data, new_data, log_func); + if (table->file->check_table_binlog_row_based(1)) { + memcpy(table->record[1], table->record[2], table->s->reclength); + error= binlog_log_row(table, old_data, new_data, log_func); + } } return error; } @@ -6072,7 +6069,8 @@ int handler::ha_delete_row(const uchar *buf) if (likely(!error)) { rows_changed++; - error= binlog_log_row(table, buf, 0, log_func); + if (table->file->check_table_binlog_row_based(1)) + error= binlog_log_row(table, buf, 0, log_func); } return error; } -- cgit v1.2.1 From e45b85eb3e5bb905ee6f45dfb037fba1aa47266d Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Sun, 18 Dec 2016 17:06:43 +0000 Subject: SQL: replication from unversioned to versioned [fixes #94] --- mysql-test/suite/versioning/r/rpl_row.result | 72 +++++++++++++++++++++++++++ mysql-test/suite/versioning/r/rpl_stmt.result | 72 +++++++++++++++++++++++++++ mysql-test/suite/versioning/t/rpl_test.inc | 57 +++++++++++++++++++++ sql/handler.cc | 10 ++-- sql/log_event.cc | 29 +++++++++-- 5 files changed, 232 insertions(+), 8 deletions(-) diff --git a/mysql-test/suite/versioning/r/rpl_row.result b/mysql-test/suite/versioning/r/rpl_row.result index b2d1adb7278..e193dc90ee0 100644 --- a/mysql-test/suite/versioning/r/rpl_row.result +++ b/mysql-test/suite/versioning/r/rpl_row.result @@ -37,5 +37,77 @@ x 3 2 connection master; +create or replace table t1 (x int primary key) engine = innodb; +connection slave; +alter table t1 with system versioning; +connection master; +insert into t1 values (1); +update t1 set x= 2 where x = 1; +connection slave; +select * from t1; +x +2 +select * from t1 for system_time all; +x +1 +2 +connection master; +delete from t1; +connection slave; +select * from t1; +x +select * from t1 for system_time all; +x +1 +2 +connection master; +create or replace table t1 (x int) engine = innodb; +connection slave; +alter table t1 with system versioning; +connection master; +insert into t1 values (1); +update t1 set x= 2 where x = 1; +connection slave; +select * from t1; +x +2 +select * from t1 for system_time all; +x +2 +1 +connection master; +delete from t1; +connection slave; +select * from t1; +x +select * from t1 for system_time all; +x +2 +1 +connection master; +create or replace table t1 (x int primary key) with system versioning engine = innodb; +connection slave; +alter table t1 without system versioning; +connection master; +insert into t1 values (1); +update t1 set x= 2 where x = 1; +select * from t1 for system_time all; +x +1 +2 +connection slave; +select * from t1; +x +2 +connection master; +delete from t1; +select * from t1 for system_time all; +x +1 +2 +connection slave; +select * from t1; +x +connection master; drop table t1; include/rpl_end.inc diff --git a/mysql-test/suite/versioning/r/rpl_stmt.result b/mysql-test/suite/versioning/r/rpl_stmt.result index b2d1adb7278..e193dc90ee0 100644 --- a/mysql-test/suite/versioning/r/rpl_stmt.result +++ b/mysql-test/suite/versioning/r/rpl_stmt.result @@ -37,5 +37,77 @@ x 3 2 connection master; +create or replace table t1 (x int primary key) engine = innodb; +connection slave; +alter table t1 with system versioning; +connection master; +insert into t1 values (1); +update t1 set x= 2 where x = 1; +connection slave; +select * from t1; +x +2 +select * from t1 for system_time all; +x +1 +2 +connection master; +delete from t1; +connection slave; +select * from t1; +x +select * from t1 for system_time all; +x +1 +2 +connection master; +create or replace table t1 (x int) engine = innodb; +connection slave; +alter table t1 with system versioning; +connection master; +insert into t1 values (1); +update t1 set x= 2 where x = 1; +connection slave; +select * from t1; +x +2 +select * from t1 for system_time all; +x +2 +1 +connection master; +delete from t1; +connection slave; +select * from t1; +x +select * from t1 for system_time all; +x +2 +1 +connection master; +create or replace table t1 (x int primary key) with system versioning engine = innodb; +connection slave; +alter table t1 without system versioning; +connection master; +insert into t1 values (1); +update t1 set x= 2 where x = 1; +select * from t1 for system_time all; +x +1 +2 +connection slave; +select * from t1; +x +2 +connection master; +delete from t1; +select * from t1 for system_time all; +x +1 +2 +connection slave; +select * from t1; +x +connection master; drop table t1; include/rpl_end.inc diff --git a/mysql-test/suite/versioning/t/rpl_test.inc b/mysql-test/suite/versioning/t/rpl_test.inc index abd156faa8c..bba67efc19b 100644 --- a/mysql-test/suite/versioning/t/rpl_test.inc +++ b/mysql-test/suite/versioning/t/rpl_test.inc @@ -29,5 +29,62 @@ sync_slave_with_master; select * from t1; select * from t1 for system_time all; +# check unversioned -> versioned replication +connection master; +create or replace table t1 (x int primary key) engine = innodb; +sync_slave_with_master; +alter table t1 with system versioning; + +connection master; +insert into t1 values (1); +update t1 set x= 2 where x = 1; +sync_slave_with_master; +select * from t1; +select * from t1 for system_time all; + +connection master; +delete from t1; +sync_slave_with_master; +select * from t1; +select * from t1 for system_time all; + +# same thing (UPDATE, DELETE), but without PK +connection master; +create or replace table t1 (x int) engine = innodb; +sync_slave_with_master; +alter table t1 with system versioning; + +connection master; +insert into t1 values (1); +update t1 set x= 2 where x = 1; +sync_slave_with_master; +select * from t1; +select * from t1 for system_time all; + +connection master; +delete from t1; +sync_slave_with_master; +select * from t1; +select * from t1 for system_time all; + +# same thing, but reverse: versioned -> unversioned +connection master; +create or replace table t1 (x int primary key) with system versioning engine = innodb; +sync_slave_with_master; +alter table t1 without system versioning; + +connection master; +insert into t1 values (1); +update t1 set x= 2 where x = 1; +select * from t1 for system_time all; +sync_slave_with_master; +select * from t1; + +connection master; +delete from t1; +select * from t1 for system_time all; +sync_slave_with_master; +select * from t1; + connection master; drop table t1; diff --git a/sql/handler.cc b/sql/handler.cc index b90ee5f6425..0712d3e5798 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6003,8 +6003,8 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data) DBUG_ASSERT(new_data == table->record[0]); DBUG_ASSERT(old_data == table->record[1]); - // InnoDB changes sys_trx_end to curr_trx_id and we need to restore MAX_TRX - if (table->file->check_table_binlog_row_based(1)) + // it is important to keep 'old_data' intact for versioning to work correctly on slave side + if (table->file->check_table_binlog_row_based(1) && table->versioned()) memcpy(table->record[2], table->record[1], table->s->reclength); MYSQL_UPDATE_ROW_START(table_share->db.str, table_share->table_name.str); mark_trx_read_write(); @@ -6017,8 +6017,10 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data) if (likely(!error) && !row_already_logged) { rows_changed++; - if (table->file->check_table_binlog_row_based(1)) { - memcpy(table->record[1], table->record[2], table->s->reclength); + if (table->file->check_table_binlog_row_based(1)) + { + if (table->versioned()) + memcpy(table->record[1], table->record[2], table->s->reclength); error= binlog_log_row(table, old_data, new_data, log_func); } } diff --git a/sql/log_event.cc b/sql/log_event.cc index c7cbff9c615..0e48791fd5c 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -12766,7 +12766,7 @@ uint8 Write_rows_log_event::get_trg_event_map() Returns TRUE if different. */ -static bool record_compare(TABLE *table) +static bool record_compare(TABLE *table, bool skip_sys_start) { bool result= FALSE; /** @@ -12799,7 +12799,10 @@ static bool record_compare(TABLE *table) /* Compare fields */ for (Field **ptr=table->field ; *ptr ; ptr++) { - + if (skip_sys_start && *ptr == table->vers_start_field()) + { + continue; + } /** We only compare field contents that are not null. NULL fields (i.e., their null bits) were compared @@ -12994,6 +12997,24 @@ int Rows_log_event::find_row(rpl_group_info *rgi) prepare_record(table, m_width, FALSE); error= unpack_current_row(rgi); + bool skip_sys_start= false; + + if (table->versioned()) + { + Field *sys_trx_end= table->vers_end_field(); + DBUG_ASSERT(table->read_set); + bitmap_set_bit(table->read_set, sys_trx_end->field_index); + // master table is unversioned + if (sys_trx_end->val_int() == 0) + { + DBUG_ASSERT(table->write_set); + bitmap_set_bit(table->write_set, sys_trx_end->field_index); + sys_trx_end->set_max(); + table->vers_start_field()->set_notnull(); + skip_sys_start= true; + } + } + DBUG_PRINT("info",("looking for the following record")); DBUG_DUMP("record[0]", table->record[0], table->s->reclength); @@ -13169,7 +13190,7 @@ int Rows_log_event::find_row(rpl_group_info *rgi) /* We use this to test that the correct key is used in test cases. */ DBUG_EXECUTE_IF("slave_crash_if_index_scan", abort();); - while (record_compare(table)) + while (record_compare(table, skip_sys_start)) { while ((error= table->file->ha_index_next(table->record[0]))) { @@ -13233,7 +13254,7 @@ int Rows_log_event::find_row(rpl_group_info *rgi) goto end; } } - while (record_compare(table)); + while (record_compare(table, skip_sys_start)); /* Note: above record_compare will take into accout all record fields -- cgit v1.2.1 From 2157c6bfbc687793f64f6852202f9cc040eda581 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 19 Dec 2016 11:48:12 +0000 Subject: IB: misc cleanup --- storage/innobase/trx/trx0trx.cc | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 7298fc62b4c..8192c816c4c 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -1212,33 +1212,6 @@ trx_t::assign_temp_rseg() return(rseg); } -/** Functor to create trx_ids array. */ -struct copy_trx_ids -{ - copy_trx_ids(trx_id_t* _array, ulint& _array_size) - : array(_array), array_size(_array_size) - { - array_size = 0; - } - - void operator()(trx_t* trx) - { - ut_ad(mutex_own(&trx_sys->mutex)); - ut_ad(trx->in_rw_trx_list); - - /* trx->state cannot change from or to NOT_STARTED - while we are holding the trx_sys->mutex. It may change - from ACTIVE to PREPARED or COMMITTED. */ - - if (!trx_state_eq(trx, TRX_STATE_COMMITTED_IN_MEMORY)) { - array[array_size++] = trx->id; - } - } - - trx_id_t* array; - ulint& array_size; -}; - /****************************************************************//** Starts a transaction. */ static -- cgit v1.2.1 From 412dd1e1f3a890a771b64283b7f34bc65a8a791f Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 20 Dec 2016 18:52:45 +0000 Subject: SQL: FOR SYSTEM_TIME support in VIEW expression [fixes #99] --- mysql-test/suite/versioning/r/view.result | 25 ++++++++++++++++++ mysql-test/suite/versioning/t/view.test | 25 ++++++++++++++++++ sql/sql_select.cc | 43 +++++-------------------------- sql/table.h | 6 ----- 4 files changed, 56 insertions(+), 43 deletions(-) create mode 100644 mysql-test/suite/versioning/r/view.result create mode 100644 mysql-test/suite/versioning/t/view.test diff --git a/mysql-test/suite/versioning/r/view.result b/mysql-test/suite/versioning/r/view.result new file mode 100644 index 00000000000..b9538698ec1 --- /dev/null +++ b/mysql-test/suite/versioning/r/view.result @@ -0,0 +1,25 @@ +create table t1 (x int) with system versioning engine innodb; +insert into t1 values (1); +select now(6) into @t1; +update t1 set x= 2; +select now(6) into @t2; +delete from t1; +set @vt1= concat("create view vt1 as select * from t1 for system_time as of timestamp '", @t1, "'"); +prepare stmt from @vt1; +execute stmt; +drop prepare stmt; +set @vt2= concat("create view vt2 as select * from t1 for system_time as of timestamp '", @t2, "'"); +prepare stmt from @vt2; +execute stmt; +drop prepare stmt; +select * from vt1; +x +1 +select * from vt2; +x +2 +select * from t1; +x +drop view vt1; +drop view vt2; +drop table t1; diff --git a/mysql-test/suite/versioning/t/view.test b/mysql-test/suite/versioning/t/view.test new file mode 100644 index 00000000000..6c04255bad1 --- /dev/null +++ b/mysql-test/suite/versioning/t/view.test @@ -0,0 +1,25 @@ +-- source include/have_innodb.inc + +create table t1 (x int) with system versioning engine innodb; +insert into t1 values (1); + +select now(6) into @t1; +update t1 set x= 2; + +select now(6) into @t2; +delete from t1; + +set @vt1= concat("create view vt1 as select * from t1 for system_time as of timestamp '", @t1, "'"); +prepare stmt from @vt1; execute stmt; drop prepare stmt; + +set @vt2= concat("create view vt2 as select * from t1 for system_time as of timestamp '", @t2, "'"); +prepare stmt from @vt2; execute stmt; drop prepare stmt; + +select * from vt1; +select * from vt2; +select * from t1; + +drop view vt1; +drop view vt2; +drop table t1; + diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1aef44397b2..f72456a9414 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -899,8 +899,6 @@ vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LEX *s *dst_cond= cond1; else thd->change_item_tree(dst_cond, cond1); - - table->vers_moved_to_where= true; } } // if (... table->table->versioned()) } // for (table= tables; ...) @@ -25036,39 +25034,6 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result) DBUG_RETURN(res || thd->is_error()); } -void TABLE_LIST::print_system_versioning(THD *thd, table_map eliminated_tables, - String *str, enum_query_type query_type) -{ - if (vers_moved_to_where) - return; - - DBUG_ASSERT(select_lex); - // system versioning - if (select_lex->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED) - { - switch (select_lex->vers_conditions.type) - { - case FOR_SYSTEM_TIME_AS_OF: - str->append(STRING_WITH_LEN(" for system_time as of ")); - select_lex->vers_conditions.start->print(str, query_type); - break; - case FOR_SYSTEM_TIME_FROM_TO: - str->append(STRING_WITH_LEN(" for system_time from timestamp ")); - select_lex->vers_conditions.start->print(str, query_type); - str->append(STRING_WITH_LEN(" to ")); - select_lex->vers_conditions.end->print(str, query_type); - break; - case FOR_SYSTEM_TIME_BETWEEN: - str->append(STRING_WITH_LEN(" for system_time between timestamp ")); - select_lex->vers_conditions.start->print(str, query_type); - str->append(STRING_WITH_LEN(" and ")); - select_lex->vers_conditions.end->print(str, query_type); - break; - default: - DBUG_ASSERT(0); - } - } -} static void print_table_array(THD *thd, table_map eliminated_tables, @@ -25404,8 +25369,6 @@ void TABLE_LIST::print(THD *thd, table_map eliminated_tables, String *str, append_identifier(thd, str, t_alias, strlen(t_alias)); } - print_system_versioning(thd, eliminated_tables, str, query_type); - if (index_hints) { List_iterator it(*index_hints); @@ -25565,6 +25528,12 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type) str->append(having_value != Item::COND_FALSE ? "1" : "0"); } + if (vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED) + { + // versioning conditions must be already unwrapped to WHERE clause + str->append(STRING_WITH_LEN(" for system_time all ")); + } + if (order_list.elements) { str->append(STRING_WITH_LEN(" order by ")); diff --git a/sql/table.h b/sql/table.h index fc7e639f162..dbcbee290f8 100644 --- a/sql/table.h +++ b/sql/table.h @@ -2334,9 +2334,6 @@ struct TABLE_LIST TABLE_LIST *first_leaf_for_name_resolution(); TABLE_LIST *last_leaf_for_name_resolution(); - /* System Versioning */ - bool vers_moved_to_where; - /** @brief Find the bottom in the chain of embedded table VIEWs. @@ -2535,9 +2532,6 @@ struct TABLE_LIST void check_pushable_cond_for_table(Item *cond); Item *build_pushable_cond_for_table(THD *thd, Item *cond); - void print_system_versioning(THD *thd, table_map eliminated_tables, - String *str, enum_query_type query_type); - private: bool prep_check_option(THD *thd, uint8 check_opt_type); bool prep_where(THD *thd, Item **conds, bool no_where_clause); -- cgit v1.2.1 From 46badf17c4fa8ffe1a13bf147ba492dcc984a57b Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 21 Dec 2016 05:57:00 +0000 Subject: IB: FK cascade delete when parent versioned [fixes #101] --- mysql-test/suite/versioning/r/foreign.result | 26 ++++++++++++++++++++++--- mysql-test/suite/versioning/t/foreign.test | 29 +++++++++++++++++++++++++--- storage/innobase/row/row0ins.cc | 23 +++++++++++++--------- 3 files changed, 63 insertions(+), 15 deletions(-) diff --git a/mysql-test/suite/versioning/r/foreign.result b/mysql-test/suite/versioning/r/foreign.result index b9c49778c5e..ee9e726a29a 100644 --- a/mysql-test/suite/versioning/r/foreign.result +++ b/mysql-test/suite/versioning/r/foreign.result @@ -52,21 +52,41 @@ insert into child values(1); delete from parent where id = 1; select * from child; parent_id -select * from child for system_time from timestamp '1-1-1' to timestamp now(6); +select * from child for system_time all; parent_id 1 insert into parent values(1); insert into child values(1); -update parent set id=id+1; +update parent set id = id + 1; select * from child; parent_id 2 -select * from child for system_time from timestamp '1-1-1' to timestamp now(6); +select * from child for system_time all; parent_id 1 2 drop table child; drop table parent; +create or replace table parent ( +id int primary key +) with system versioning +engine innodb; +create or replace table child ( +x int, +parent_id int not null, +constraint `parent-fk` + foreign key (parent_id) references parent (id) +on delete cascade +on update restrict +) +engine innodb; +insert into parent (id) values (1); +insert into child (x, parent_id) values (1, 1); +delete from parent; +select * from child; +x parent_id +drop table child; +drop table parent; create table parent( id int unique key ) engine innodb; diff --git a/mysql-test/suite/versioning/t/foreign.test b/mysql-test/suite/versioning/t/foreign.test index 3f1a14e58aa..2a1bca3af60 100644 --- a/mysql-test/suite/versioning/t/foreign.test +++ b/mysql-test/suite/versioning/t/foreign.test @@ -76,13 +76,36 @@ insert into child values(1); delete from parent where id = 1; select * from child; -select * from child for system_time from timestamp '1-1-1' to timestamp now(6); +select * from child for system_time all; insert into parent values(1); insert into child values(1); -update parent set id=id+1; +update parent set id = id + 1; +select * from child; +select * from child for system_time all; + +drop table child; +drop table parent; + +create or replace table parent ( + id int primary key +) with system versioning +engine innodb; + +create or replace table child ( + x int, + parent_id int not null, + constraint `parent-fk` + foreign key (parent_id) references parent (id) + on delete cascade + on update restrict +) +engine innodb; + +insert into parent (id) values (1); +insert into child (x, parent_id) values (1, 1); +delete from parent; select * from child; -select * from child for system_time from timestamp '1-1-1' to timestamp now(6); drop table child; drop table parent; diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 40d3eccdc34..f3fc7422ffe 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -430,7 +430,8 @@ row_ins_cascade_ancestor_updates_table( upd_node = static_cast(parent); - if (upd_node->table == table && upd_node->is_delete == FALSE) { + if (upd_node->table == table && upd_node->is_delete == FALSE + && !upd_node->vers_delete) { return(TRUE); } @@ -977,6 +978,8 @@ row_ins_foreign_fill_virtual( innobase_init_vc_templ(index->table); } + bool is_delete = node->is_delete || node->vers_delete; + for (ulint i = 0; i < n_v_fld; i++) { dict_v_col_t* col = dict_table_get_nth_v_col( @@ -1008,14 +1011,14 @@ row_ins_foreign_fill_virtual( upd_field_set_v_field_no(upd_field, i, index); - if (node->is_delete + if (is_delete ? (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) : (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL)) { dfield_set_null(&upd_field->new_val); } - if (!node->is_delete + if (!is_delete && (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE)) { dfield_t* new_vfield = innobase_get_computed_value( @@ -1108,7 +1111,9 @@ row_ins_foreign_check_on_constraint( node = static_cast(thr->run_node); - if (node->is_delete && 0 == (foreign->type + bool is_delete = node->is_delete || node->vers_delete; + + if (is_delete && 0 == (foreign->type & (DICT_FOREIGN_ON_DELETE_CASCADE | DICT_FOREIGN_ON_DELETE_SET_NULL))) { @@ -1119,7 +1124,7 @@ row_ins_foreign_check_on_constraint( DBUG_RETURN(DB_ROW_IS_REFERENCED); } - if (!node->is_delete && 0 == (foreign->type + if (!is_delete && 0 == (foreign->type & (DICT_FOREIGN_ON_UPDATE_CASCADE | DICT_FOREIGN_ON_UPDATE_SET_NULL))) { @@ -1148,7 +1153,7 @@ row_ins_foreign_check_on_constraint( cascade->foreign = foreign; - if (node->is_delete + if (is_delete && (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE)) { cascade->is_delete = TRUE; } else { @@ -1285,7 +1290,7 @@ row_ins_foreign_check_on_constraint( clust_index, tmp_heap); } - if (node->is_delete + if (is_delete ? (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) : (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL)) { @@ -1365,7 +1370,7 @@ row_ins_foreign_check_on_constraint( } } - if (!node->is_delete + if (!is_delete && (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE)) { /* Build the appropriate update vector which sets changing @@ -1690,7 +1695,7 @@ row_ins_check_foreign_constraint( if (que_node_get_type(thr->run_node) == QUE_NODE_UPDATE) { upd_node = static_cast(thr->run_node); - if (!(upd_node->is_delete) && upd_node->foreign == foreign) { + if (!(upd_node->is_delete) && !(upd_node->vers_delete) && upd_node->foreign == foreign) { /* If a cascaded update is done as defined by a foreign key constraint, do not check that constraint for the child row. In ON UPDATE CASCADE -- cgit v1.2.1 From 27d9e762a9dfe24c9afe167d3f3acfc6d8e43fd2 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 21 Dec 2016 08:17:44 +0000 Subject: SQL: prohibit write-locking of historic rows [fixes #102] --- mysql-test/suite/versioning/r/select.result | 4 ++++ mysql-test/suite/versioning/t/select.test | 5 +++++ sql/sql_select.cc | 34 +++++++++++++++++++++++------ 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index 696f339e355..dad8b394079 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -402,6 +402,10 @@ create or replace table t1 (x int); insert into t1 values (1); select * from t1 for system_time all; ERROR HY000: System Versioning required: `FOR SYSTEM_TIME` query +create or replace table t1 (x int) with system versioning; +insert into t1 values (1); +select * from t1 for system_time all for update; +ERROR HY000: Wrong parameters for `FOR SYSTEM_TIME query`: write-locking of historic rows drop table t1; call verify_vtq; No A B C D diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index 566c6ad4a50..d47b09e2205 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -126,6 +126,11 @@ insert into t1 values (1); --error ER_VERSIONING_REQUIRED select * from t1 for system_time all; +create or replace table t1 (x int) with system versioning; +insert into t1 values (1); +--error ER_VERS_WRONG_PARAMS +select * from t1 for system_time all for update; + drop table t1; call verify_vtq; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index f72456a9414..b36ccc4e8d6 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -690,9 +690,11 @@ vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LEX *s versioned_tables++; } + vers_range_type_t query_type= slex->vers_conditions.type; + if (versioned_tables == 0) { - if (slex->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED) + if (query_type != FOR_SYSTEM_TIME_UNSPECIFIED) { my_error(ER_VERSIONING_REQUIRED, MYF(0), "`FOR SYSTEM_TIME` query"); DBUG_RETURN(-1); @@ -700,9 +702,27 @@ vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LEX *s DBUG_RETURN(0); } - if (slex->vers_conditions.type == FOR_SYSTEM_TIME_ALL) + if (query_type != FOR_SYSTEM_TIME_UNSPECIFIED) { - DBUG_RETURN(0); + switch (slex->lock_type) + { + case TL_WRITE_ALLOW_WRITE: + case TL_WRITE_CONCURRENT_INSERT: + case TL_WRITE_DELAYED: + case TL_WRITE_DEFAULT: + case TL_WRITE_LOW_PRIORITY: + case TL_WRITE: + case TL_WRITE_ONLY: + my_error(ER_VERS_WRONG_PARAMS, MYF(0), "FOR SYSTEM_TIME query", "write-locking of historic rows"); + DBUG_RETURN(-1); + default: + break; + } + + if (query_type == FOR_SYSTEM_TIME_ALL) + { + DBUG_RETURN(0); + } } /* For prepared statements we create items on statement arena, @@ -784,7 +804,7 @@ vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LEX *s } } else if (vers_simple_select && slex->vers_conditions.unit == UNIT_TIMESTAMP - && slex->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED) + && query_type != FOR_SYSTEM_TIME_UNSPECIFIED) { DBUG_ASSERT(table->table->s && table->table->s->db_plugin); handlerton *hton= plugin_hton(table->table->s->db_plugin); @@ -805,7 +825,7 @@ vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LEX *s Item *cond1= 0, *cond2= 0, *curr= 0; if (table->table->versioned_by_sql() || vers_simple_select) { - switch (slex->vers_conditions.type) + switch (query_type) { case FOR_SYSTEM_TIME_UNSPECIFIED: if (table->table->versioned_by_sql()) @@ -851,7 +871,7 @@ vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LEX *s Item *trx_id0, *trx_id1; - switch (slex->vers_conditions.type) + switch (query_type) { case FOR_SYSTEM_TIME_UNSPECIFIED: curr= newx Item_int(thd, ULONGLONG_MAX); @@ -877,7 +897,7 @@ vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LEX *s trx_id1= slex->vers_conditions.end; } - cond1= slex->vers_conditions.type == FOR_SYSTEM_TIME_FROM_TO ? + cond1= query_type == FOR_SYSTEM_TIME_FROM_TO ? newx Item_func_vtq_trx_sees(thd, trx_id1, row_start) : newx Item_func_vtq_trx_sees_eq(thd, trx_id1, row_start); cond2= newx Item_func_vtq_trx_sees_eq(thd, row_end, trx_id0); -- cgit v1.2.1 From ea60760e476ae3e5d1dc44d1976fba68e86f679f Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Thu, 22 Dec 2016 07:34:33 +0000 Subject: SQL: missed FOR SYSTEM_TIME ALL for FOR_SYSTEM_TIME_UNSPECIFIED [fixes #105] --- mysql-test/suite/versioning/r/view.result | 4 ++++ mysql-test/suite/versioning/t/view.test | 3 +++ sql/sql_select.cc | 7 +++++-- sql/table.h | 4 ++++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/versioning/r/view.result b/mysql-test/suite/versioning/r/view.result index b9538698ec1..eeec506f933 100644 --- a/mysql-test/suite/versioning/r/view.result +++ b/mysql-test/suite/versioning/r/view.result @@ -20,6 +20,10 @@ x 2 select * from t1; x +create or replace view vt1 as select * from t1; +show create view vt1; +View Create View character_set_client collation_connection +vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`x` AS `x` from `t1` where `t1`.`sys_trx_end` = 18446744073709551615 for system_time all latin1 latin1_swedish_ci drop view vt1; drop view vt2; drop table t1; diff --git a/mysql-test/suite/versioning/t/view.test b/mysql-test/suite/versioning/t/view.test index 6c04255bad1..445dcc1f633 100644 --- a/mysql-test/suite/versioning/t/view.test +++ b/mysql-test/suite/versioning/t/view.test @@ -19,6 +19,9 @@ select * from vt1; select * from vt2; select * from t1; +create or replace view vt1 as select * from t1; +show create view vt1; + drop view vt1; drop view vt2; drop table t1; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b36ccc4e8d6..4dc67267b74 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -721,6 +721,7 @@ vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LEX *s if (query_type == FOR_SYSTEM_TIME_ALL) { + slex->vers_conditions.unwrapped= true; DBUG_RETURN(0); } } @@ -928,6 +929,8 @@ vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LEX *s thd->restore_active_arena(arena, &backup); } + slex->vers_conditions.unwrapped= true; + DBUG_RETURN(0); #undef newx } @@ -25548,9 +25551,9 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type) str->append(having_value != Item::COND_FALSE ? "1" : "0"); } - if (vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED) + if (vers_conditions.unwrapped) { - // versioning conditions must be already unwrapped to WHERE clause + // versioning conditions are already unwrapped to WHERE clause str->append(STRING_WITH_LEN(" for system_time all ")); } diff --git a/sql/table.h b/sql/table.h index dbcbee290f8..552e51284a6 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1857,11 +1857,14 @@ struct vers_select_conds_t vers_range_unit_t unit; Item *start, *end; + bool unwrapped; + void empty() { type= FOR_SYSTEM_TIME_UNSPECIFIED; unit= UNIT_TIMESTAMP; start= end= NULL; + unwrapped= false; } void init( @@ -1874,6 +1877,7 @@ struct vers_select_conds_t unit= u; start= s; end= e; + unwrapped= false; } }; -- cgit v1.2.1 From 4383e16cbe1010c5fbcd61e0b411703a84649ddf Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Sun, 25 Dec 2016 08:25:17 +0000 Subject: IB: skip check_ref on historical record [fixes #101] --- mysql-test/suite/versioning/r/foreign.result | 27 +++++++++++++++++++++++++-- mysql-test/suite/versioning/t/foreign.test | 28 ++++++++++++++++++++++++++-- storage/innobase/row/row0ins.cc | 16 ++++++++++++++-- 3 files changed, 65 insertions(+), 6 deletions(-) diff --git a/mysql-test/suite/versioning/r/foreign.result b/mysql-test/suite/versioning/r/foreign.result index ee9e726a29a..3903bee2f00 100644 --- a/mysql-test/suite/versioning/r/foreign.result +++ b/mysql-test/suite/versioning/r/foreign.result @@ -80,13 +80,36 @@ on delete cascade on update restrict ) engine innodb; -insert into parent (id) values (1); -insert into child (x, parent_id) values (1, 1); +insert into parent (id) values (2); +insert into child (x, parent_id) values (2, 2); delete from parent; select * from child; x parent_id drop table child; drop table parent; +create or replace table parent ( +id int primary key +) +engine innodb; +create or replace table child ( +id int primary key, +parent_id int not null, +constraint `parent-fk` + foreign key (parent_id) references parent (id) +on delete cascade +on update restrict +) with system versioning +engine innodb; +insert into parent (id) values (3); +insert into child (id, parent_id) values (3, 3); +delete from parent; +select * from child; +id parent_id +select * from child for system_time all; +id parent_id +3 3 +drop table child; +drop table parent; create table parent( id int unique key ) engine innodb; diff --git a/mysql-test/suite/versioning/t/foreign.test b/mysql-test/suite/versioning/t/foreign.test index 2a1bca3af60..ec23abac460 100644 --- a/mysql-test/suite/versioning/t/foreign.test +++ b/mysql-test/suite/versioning/t/foreign.test @@ -102,14 +102,38 @@ create or replace table child ( ) engine innodb; -insert into parent (id) values (1); -insert into child (x, parent_id) values (1, 1); +insert into parent (id) values (2); +insert into child (x, parent_id) values (2, 2); delete from parent; select * from child; drop table child; drop table parent; +create or replace table parent ( + id int primary key +) +engine innodb; + +create or replace table child ( + id int primary key, + parent_id int not null, + constraint `parent-fk` + foreign key (parent_id) references parent (id) + on delete cascade + on update restrict +) with system versioning +engine innodb; + +insert into parent (id) values (3); +insert into child (id, parent_id) values (3, 3); +delete from parent; +select * from child; +select * from child for system_time all; + +drop table child; +drop table parent; + ################# # Test SET NULL # ################# diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index f3fc7422ffe..c107ae6e01b 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -1686,10 +1686,22 @@ row_ins_check_foreign_constraint( /* If any of the foreign key fields in entry is SQL NULL, we suppress the foreign key check: this is compatible with Oracle, for example */ - for (ulint i = 0; i < foreign->n_fields; i++) { - if (dfield_is_null(dtuple_get_nth_field(entry, i))) { + for (ulint i = 0; i < entry->n_fields; i++) { + dfield_t* field = dtuple_get_nth_field(entry, i); + if (i < foreign->n_fields && dfield_is_null(field)) { goto exit_func; } + /* System Versioning: if sys_trx_end != Inf, we + suppress the foreign key check */ + if (DICT_TF2_FLAG_IS_SET(table, DICT_TF2_VERSIONED) && + dfield_get_type(field)->prtype & DATA_VERS_ROW_END) + { + byte* data = static_cast(dfield_get_data(field)); + ut_ad(data); + trx_id_t end_trx_id = mach_read_from_8(data); + if (end_trx_id != TRX_ID_MAX) + goto exit_func; + } } if (que_node_get_type(thr->run_node) == QUE_NODE_UPDATE) { -- cgit v1.2.1 From abb2f9488d3e1ca4e4dacc8a315ae6ed6f13fd68 Mon Sep 17 00:00:00 2001 From: kevg Date: Mon, 26 Dec 2016 18:46:02 +0300 Subject: IB: skip sys_trx_start when comparing master and slave rows [closes #107] --- mysql-test/suite/versioning/r/rpl_row.result | 13 +++++++++++++ mysql-test/suite/versioning/r/rpl_stmt.result | 13 +++++++++++++ mysql-test/suite/versioning/t/rpl_test.inc | 11 +++++++++++ sql/log_event.cc | 10 ++++------ sql/table.h | 6 ++++++ 5 files changed, 47 insertions(+), 6 deletions(-) diff --git a/mysql-test/suite/versioning/r/rpl_row.result b/mysql-test/suite/versioning/r/rpl_row.result index e193dc90ee0..6d41ed6ff7b 100644 --- a/mysql-test/suite/versioning/r/rpl_row.result +++ b/mysql-test/suite/versioning/r/rpl_row.result @@ -109,5 +109,18 @@ connection slave; select * from t1; x connection master; +create or replace table t1 (a int) with system versioning engine = innodb; +insert into t1 values (1); +update t1 set a=2; +select * from t1 for system_time all; +a +2 +1 +connection slave; +select * from t1 for system_time all; +a +2 +1 +connection master; drop table t1; include/rpl_end.inc diff --git a/mysql-test/suite/versioning/r/rpl_stmt.result b/mysql-test/suite/versioning/r/rpl_stmt.result index e193dc90ee0..6d41ed6ff7b 100644 --- a/mysql-test/suite/versioning/r/rpl_stmt.result +++ b/mysql-test/suite/versioning/r/rpl_stmt.result @@ -109,5 +109,18 @@ connection slave; select * from t1; x connection master; +create or replace table t1 (a int) with system versioning engine = innodb; +insert into t1 values (1); +update t1 set a=2; +select * from t1 for system_time all; +a +2 +1 +connection slave; +select * from t1 for system_time all; +a +2 +1 +connection master; drop table t1; include/rpl_end.inc diff --git a/mysql-test/suite/versioning/t/rpl_test.inc b/mysql-test/suite/versioning/t/rpl_test.inc index bba67efc19b..74ed3bfd15b 100644 --- a/mysql-test/suite/versioning/t/rpl_test.inc +++ b/mysql-test/suite/versioning/t/rpl_test.inc @@ -86,5 +86,16 @@ select * from t1 for system_time all; sync_slave_with_master; select * from t1; +# at this point in this particular test master and slave have different curr_trx_id +# and the same rows have different sys_trx_start +# slave should ignore sys_trx_start while searching for a record to update in a InnoDB table +connection master; +create or replace table t1 (a int) with system versioning engine = innodb; +insert into t1 values (1); +update t1 set a=2; +select * from t1 for system_time all; +sync_slave_with_master; +select * from t1 for system_time all; + connection master; drop table t1; diff --git a/sql/log_event.cc b/sql/log_event.cc index 0e48791fd5c..4a48ebce077 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -12766,7 +12766,7 @@ uint8 Write_rows_log_event::get_trg_event_map() Returns TRUE if different. */ -static bool record_compare(TABLE *table, bool skip_sys_start) +static bool record_compare(TABLE *table) { bool result= FALSE; /** @@ -12799,7 +12799,7 @@ static bool record_compare(TABLE *table, bool skip_sys_start) /* Compare fields */ for (Field **ptr=table->field ; *ptr ; ptr++) { - if (skip_sys_start && *ptr == table->vers_start_field()) + if (table->versioned_by_engine() && *ptr == table->vers_start_field()) { continue; } @@ -12997,7 +12997,6 @@ int Rows_log_event::find_row(rpl_group_info *rgi) prepare_record(table, m_width, FALSE); error= unpack_current_row(rgi); - bool skip_sys_start= false; if (table->versioned()) { @@ -13011,7 +13010,6 @@ int Rows_log_event::find_row(rpl_group_info *rgi) bitmap_set_bit(table->write_set, sys_trx_end->field_index); sys_trx_end->set_max(); table->vers_start_field()->set_notnull(); - skip_sys_start= true; } } @@ -13190,7 +13188,7 @@ int Rows_log_event::find_row(rpl_group_info *rgi) /* We use this to test that the correct key is used in test cases. */ DBUG_EXECUTE_IF("slave_crash_if_index_scan", abort();); - while (record_compare(table, skip_sys_start)) + while (record_compare(table)) { while ((error= table->file->ha_index_next(table->record[0]))) { @@ -13254,7 +13252,7 @@ int Rows_log_event::find_row(rpl_group_info *rgi) goto end; } } - while (record_compare(table, skip_sys_start)); + while (record_compare(table)); /* Note: above record_compare will take into accout all record fields diff --git a/sql/table.h b/sql/table.h index 552e51284a6..da91162523a 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1522,6 +1522,12 @@ public: return s->versioned && !file->versioned(); } + bool versioned_by_engine() const + { + DBUG_ASSERT(file); + return s->versioned && file->versioned(); + } + Field *vers_start_field() const { DBUG_ASSERT(s->versioned); -- cgit v1.2.1 From 4c37011582b4581bb122293ba30a6956b573483c Mon Sep 17 00:00:00 2001 From: kevg Date: Tue, 17 Jan 2017 13:47:08 +0300 Subject: Tests: disabled failing (in 10.2) tests --- mysql-test/suite/encryption/disabled.def | 2 ++ mysql-test/suite/handler/disabled.def | 3 +++ storage/tokudb/mysql-test/tokudb/disabled.def | 3 +++ storage/tokudb/mysql-test/tokudb_parts/disabled.def | 12 ++++++++++++ 4 files changed, 20 insertions(+) diff --git a/mysql-test/suite/encryption/disabled.def b/mysql-test/suite/encryption/disabled.def index 8c263c6a458..952057751c8 100644 --- a/mysql-test/suite/encryption/disabled.def +++ b/mysql-test/suite/encryption/disabled.def @@ -13,3 +13,5 @@ innodb_scrub : MDEV-8139 scrubbing does not work reliably innodb_scrub_background : MDEV-8139 scrubbing does not work reliably innodb_encryption-page-compression : MDEV-11420 +innodb_lotoftables : versioning branch + diff --git a/mysql-test/suite/handler/disabled.def b/mysql-test/suite/handler/disabled.def index 888298bbb09..1f648e74b06 100644 --- a/mysql-test/suite/handler/disabled.def +++ b/mysql-test/suite/handler/disabled.def @@ -9,3 +9,6 @@ # Do not use any TAB characters for whitespace. # ############################################################################## + +wl6501_1: versioning branch +wl6501_crash_3: versioning branch diff --git a/storage/tokudb/mysql-test/tokudb/disabled.def b/storage/tokudb/mysql-test/tokudb/disabled.def index ddefceb432e..1f5ed441254 100644 --- a/storage/tokudb/mysql-test/tokudb/disabled.def +++ b/storage/tokudb/mysql-test/tokudb/disabled.def @@ -29,3 +29,6 @@ cluster_key_part: engine options on partitioned tables i_s_tokudb_lock_waits_released: unstable, race conditions i_s_tokudb_locks_released: unstable, race conditions row_format: n/a + +rows-32m-rand-insert: versioning branch +rows-32m-seq-insert: versioning branch \ No newline at end of file diff --git a/storage/tokudb/mysql-test/tokudb_parts/disabled.def b/storage/tokudb/mysql-test/tokudb_parts/disabled.def index 3252a463176..41fe1df15c0 100644 --- a/storage/tokudb/mysql-test/tokudb_parts/disabled.def +++ b/storage/tokudb/mysql-test/tokudb_parts/disabled.def @@ -7,3 +7,15 @@ partition_max_sub_parts_key_list_tokudb: 5.6 test not merged yet partition_max_sub_parts_key_range_tokudb: 5.6 test not merged yet partition_max_sub_parts_list_tokudb: 5.6 test not merged yet partition_max_sub_parts_range_tokudb: 5.6 test not merged yet + +partition_alter1_1_2_tokudb: versioning branch +partition_alter1_1_tokudb: versioning branch +partition_alter1_2_tokudb: versioning branch +partition_alter2_1_1_tokudb: versioning branch +partition_alter2_1_2_tokudb: versioning branch +partition_alter2_2_1_tokudb: versioning branch +partition_alter2_2_2_tokudb: versioning branch +partition_alter4_tokudb: versioning branch +partition_basic_tokudb: versioning branch +partition_debug_tokudb: versioning branch +part_supported_sql_func_tokudb: versioning branch \ No newline at end of file -- cgit v1.2.1 From c9e4ac4b7221ab58097ce16e91eb1b885f2a3485 Mon Sep 17 00:00:00 2001 From: kevg Date: Fri, 23 Dec 2016 17:05:57 +0300 Subject: 0.6: truncate history feature [closes #96] --- .../suite/versioning/r/truncate_history.result | 115 +++++++++++++++++++++ .../suite/versioning/r/truncate_innodb_rpl.result | 7 ++ .../suite/versioning/t/truncate_history.test | 94 +++++++++++++++++ .../suite/versioning/t/truncate_innodb_rpl.test | 10 ++ sql/handler.cc | 2 +- sql/handler.h | 2 +- sql/share/errmsg-utf8.txt | 3 + sql/sql_delete.cc | 58 ++++++++--- sql/sql_select.cc | 4 +- sql/sql_select.h | 3 + sql/sql_truncate.cc | 9 +- sql/sql_yacc.yy | 3 +- storage/innobase/handler/ha_innodb.cc | 6 +- storage/innobase/include/row0mysql.h | 3 +- storage/innobase/row/row0mysql.cc | 11 +- 15 files changed, 301 insertions(+), 29 deletions(-) create mode 100644 mysql-test/suite/versioning/r/truncate_history.result create mode 100644 mysql-test/suite/versioning/r/truncate_innodb_rpl.result create mode 100644 mysql-test/suite/versioning/t/truncate_history.test create mode 100644 mysql-test/suite/versioning/t/truncate_innodb_rpl.test diff --git a/mysql-test/suite/versioning/r/truncate_history.result b/mysql-test/suite/versioning/r/truncate_history.result new file mode 100644 index 00000000000..d71354bcc36 --- /dev/null +++ b/mysql-test/suite/versioning/r/truncate_history.result @@ -0,0 +1,115 @@ +create table t (a int); +truncate t for system_time all; +ERROR HY000: System Versioning required: `FOR SYSTEM_TIME` query +create procedure truncate_history_of_t() +begin +prepare stmt from 'truncate t for system_time timestamp between \'1-1-1\' and now(6)'; +execute stmt; +drop prepare stmt; +end~~ +create or replace table t (a int) with system versioning; +insert into t values (1); +update t set a=2; +select * from t for system_time all; +a +2 +1 +set @test = 'correct'; +create trigger trg_before before delete on t for each row set @test = 'incorrect'; +create trigger trg_after after delete on t for each row set @test = 'incorrect'; +truncate t for system_time all; +select * from t for system_time all; +a +2 +select @test from t; +@test +correct +drop trigger trg_before; +drop trigger trg_after; +update t set a=3; +update t set a=4; +truncate t for system_time as of timestamp now(6); +select * from t for system_time all; +a +4 +2 +3 +truncate t for system_time timestamp between '1-1-1' and now(6); +select * from t for system_time all; +a +4 +update t set a=5; +truncate t for system_time timestamp from '1-1-1' to now(6); +select * from t for system_time all; +a +5 +update t set a=6; +call truncate_history_of_t(); +select * from t for system_time all; +a +6 +set @ts1 = now(6); +update t set a=7; +set @ts2 = now(6); +update t set a=8; +truncate t for system_time timestamp from '1-1-1' to @ts1; +select * from t for system_time all; +a +8 +7 +update t set a=9; +truncate t for system_time timestamp between '1-1-1' and @ts2; +select * from t for system_time all; +a +9 +8 +create or replace table t (a int) with system versioning engine=innodb; +insert into t values (1); +update t set a=2; +select * from t for system_time all; +a +2 +1 +truncate t for system_time all; +select * from t for system_time all; +a +2 +update t set a=3; +update t set a=4; +truncate t for system_time as of timestamp now(6); +select * from t for system_time all; +a +4 +2 +3 +truncate t for system_time timestamp between '1-1-1' and now(6); +select * from t for system_time all; +a +4 +update t set a=5; +truncate t for system_time timestamp from '1-1-1' to now(6); +select * from t for system_time all; +a +5 +update t set a=6; +call truncate_history_of_t(); +select * from t for system_time all; +a +6 +set @ts1 = now(6); +update t set a=7; +set @ts2 = now(6); +update t set a=8; +truncate t for system_time timestamp from '1-1-1' to @ts1; +select * from t for system_time all; +a +8 +7 +update t set a=9; +truncate t for system_time timestamp between '1-1-1' and @ts2; +select * from t for system_time all; +a +9 +8 +drop table t; +drop procedure truncate_history_of_t; diff --git a/mysql-test/suite/versioning/r/truncate_innodb_rpl.result b/mysql-test/suite/versioning/r/truncate_innodb_rpl.result new file mode 100644 index 00000000000..1aa29d7b95f --- /dev/null +++ b/mysql-test/suite/versioning/r/truncate_innodb_rpl.result @@ -0,0 +1,7 @@ +include/master-slave.inc +[connection master] +create table t (a int) with system versioning engine=innodb; +truncate t for system_time all; +ERROR HY000: `TRUNCATE FOR SYSTEM_TIME with row-based replication` is not allowed for versioned table +drop table t; +include/rpl_end.inc diff --git a/mysql-test/suite/versioning/t/truncate_history.test b/mysql-test/suite/versioning/t/truncate_history.test new file mode 100644 index 00000000000..42f60f51d46 --- /dev/null +++ b/mysql-test/suite/versioning/t/truncate_history.test @@ -0,0 +1,94 @@ +-- source include/have_innodb.inc + +create table t (a int); +--error ER_VERSIONING_REQUIRED +truncate t for system_time all; + +delimiter ~~; +create procedure truncate_history_of_t() +begin + prepare stmt from 'truncate t for system_time timestamp between \'1-1-1\' and now(6)'; + execute stmt; + drop prepare stmt; +end~~ +delimiter ;~~ + +create or replace table t (a int) with system versioning; +insert into t values (1); +update t set a=2; +select * from t for system_time all; + +set @test = 'correct'; +create trigger trg_before before delete on t for each row set @test = 'incorrect'; +create trigger trg_after after delete on t for each row set @test = 'incorrect'; + +truncate t for system_time all; +select * from t for system_time all; + +select @test from t; +drop trigger trg_before; +drop trigger trg_after; + +update t set a=3; +update t set a=4; +truncate t for system_time as of timestamp now(6); +select * from t for system_time all; + +truncate t for system_time timestamp between '1-1-1' and now(6); +select * from t for system_time all; + +update t set a=5; +truncate t for system_time timestamp from '1-1-1' to now(6); +select * from t for system_time all; + +update t set a=6; +call truncate_history_of_t(); +select * from t for system_time all; + +set @ts1 = now(6); +update t set a=7; +set @ts2 = now(6); +update t set a=8; +truncate t for system_time timestamp from '1-1-1' to @ts1; +select * from t for system_time all; +update t set a=9; +truncate t for system_time timestamp between '1-1-1' and @ts2; +select * from t for system_time all; + + +create or replace table t (a int) with system versioning engine=innodb; +insert into t values (1); +update t set a=2; +select * from t for system_time all; + +truncate t for system_time all; +select * from t for system_time all; + +update t set a=3; +update t set a=4; +truncate t for system_time as of timestamp now(6); +select * from t for system_time all; + +truncate t for system_time timestamp between '1-1-1' and now(6); +select * from t for system_time all; + +update t set a=5; +truncate t for system_time timestamp from '1-1-1' to now(6); +select * from t for system_time all; + +update t set a=6; +call truncate_history_of_t(); +select * from t for system_time all; + +set @ts1 = now(6); +update t set a=7; +set @ts2 = now(6); +update t set a=8; +truncate t for system_time timestamp from '1-1-1' to @ts1; +select * from t for system_time all; +update t set a=9; +truncate t for system_time timestamp between '1-1-1' and @ts2; +select * from t for system_time all; + +drop table t; +drop procedure truncate_history_of_t; diff --git a/mysql-test/suite/versioning/t/truncate_innodb_rpl.test b/mysql-test/suite/versioning/t/truncate_innodb_rpl.test new file mode 100644 index 00000000000..57fad82f3ba --- /dev/null +++ b/mysql-test/suite/versioning/t/truncate_innodb_rpl.test @@ -0,0 +1,10 @@ +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc +-- source include/have_innodb.inc + +create table t (a int) with system versioning engine=innodb; +--error ER_VERS_NOT_ALLOWED +truncate t for system_time all; +drop table t; + +-- source include/rpl_end.inc diff --git a/sql/handler.cc b/sql/handler.cc index 0712d3e5798..98f558f50cc 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -5659,7 +5659,7 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat) 1 Row needs to be logged */ -inline bool handler::check_table_binlog_row_based(bool binlog_row) +bool handler::check_table_binlog_row_based(bool binlog_row) { if (unlikely((table->in_use->variables.sql_log_bin_off))) return 0; /* Called by partitioning engine */ diff --git a/sql/handler.h b/sql/handler.h index 5bcacf1f50b..56ee1addd6d 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -4079,7 +4079,7 @@ protected: virtual int delete_table(const char *name); public: - inline bool check_table_binlog_row_based(bool binlog_row); + bool check_table_binlog_row_based(bool binlog_row); private: /* Cache result to avoid extra calls */ inline void mark_trx_read_write() diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index c25b8b655cd..daca9b4ce52 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7522,3 +7522,6 @@ WARN_VERS_PARAMETERS WARN_VERS_PART_ROTATION eng "Switching from partition %`s to %`s" + +ER_VERS_NOT_ALLOWED + eng "%`s is not allowed for versioned table" diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 775d0c0d023..5d62b54b297 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -215,19 +215,13 @@ void Update_plan::save_explain_data_intern(MEM_ROOT *mem_root, inline int TABLE::delete_row() { - int error; - if (!versioned_by_sql()) - error= file->ha_delete_row(record[0]); - else - { - store_record(this, record[1]); - Field *sys_trx_end= vers_end_field(); - sys_trx_end->set_time(); - error= file->ha_update_row(record[1], record[0]); - } - return error; -} + if (!versioned_by_sql() || !vers_end_field()->is_max()) + return file->ha_delete_row(record[0]); + store_record(this, record[1]); + vers_end_field()->set_time(); + return file->ha_update_row(record[1], record[0]); +} /** Implement DELETE SQL word. @@ -269,6 +263,34 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, if (open_and_lock_tables(thd, table_list, TRUE, 0)) DBUG_RETURN(TRUE); + bool truncate_history= + select_lex->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED; + if (truncate_history) + { + TABLE *table= table_list->table; + DBUG_ASSERT(table); + + if (table->versioned_by_engine() && + table->file->check_table_binlog_row_based(1)) + { + my_error(ER_VERS_NOT_ALLOWED, MYF(0), + "TRUNCATE FOR SYSTEM_TIME with row-based replication"); + DBUG_RETURN(TRUE); + } + + DBUG_ASSERT(!conds); + if (vers_setup_select(thd, table_list, &conds, select_lex)) + DBUG_RETURN(TRUE); + + // trx_sees() in InnoDB reads sys_trx_start + if (!table->versioned_by_sql() && + (select_lex->vers_conditions.type == FOR_SYSTEM_TIME_BETWEEN || + select_lex->vers_conditions.type == FOR_SYSTEM_TIME_FROM_TO)) + { + bitmap_set_bit(table->read_set, table->vers_start_field()->field_index); + } + } + if (mysql_handle_list_of_derived(thd->lex, table_list, DT_MERGE_FOR_INSERT)) DBUG_RETURN(TRUE); if (mysql_handle_list_of_derived(thd->lex, table_list, DT_PREPARE)) @@ -577,9 +599,13 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, while (!(error=info.read_record(&info)) && !thd->killed && ! thd->is_error()) { - if (table->versioned() && !table->vers_end_field()->is_max()) + if (table->versioned()) { - continue; + bool row_is_alive= table->vers_end_field()->is_max(); + if (truncate_history && row_is_alive) + continue; + if (!truncate_history && !row_is_alive) + continue; } explain->tracker.on_record_read(); @@ -589,7 +615,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, if (!select || select->skip_record(thd) > 0) { explain->tracker.on_record_after_where(); - if (table->triggers && + if (!truncate_history && table->triggers && table->triggers->process_triggers(thd, TRG_EVENT_DELETE, TRG_ACTION_BEFORE, FALSE)) { @@ -607,7 +633,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, if (!error) { deleted++; - if (table->triggers && + if (!truncate_history && table->triggers && table->triggers->process_triggers(thd, TRG_EVENT_DELETE, TRG_ACTION_AFTER, FALSE)) { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 4dc67267b74..6655f71e10a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -667,8 +667,8 @@ setup_without_group(THD *thd, Ref_ptr_array ref_pointer_array, DBUG_RETURN(res); } -static int -vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LEX *slex) +int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, + SELECT_LEX *slex) { DBUG_ENTER("vers_setup_select"); #define newx new (thd->mem_root) diff --git a/sql/sql_select.h b/sql/sql_select.h index 77cf73d785f..aa238c9b741 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -2301,4 +2301,7 @@ int create_sort_index(THD *thd, JOIN *join, JOIN_TAB *tab, Filesort *fsort); JOIN_TAB *first_explain_order_tab(JOIN* join); JOIN_TAB *next_explain_order_tab(JOIN* join, JOIN_TAB* tab); +int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, + SELECT_LEX *slex); + #endif /* SQL_SELECT_INCLUDED */ diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc index daa295d768e..4faad5b4711 100644 --- a/sql/sql_truncate.cc +++ b/sql/sql_truncate.cc @@ -26,7 +26,8 @@ #include "sql_truncate.h" #include "wsrep_mysqld.h" #include "sql_show.h" //append_identifier() - +#include "sql_select.h" +#include "sql_delete.h" /** Append a list of field names to a string. @@ -480,7 +481,6 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref) DBUG_RETURN(error); } - /** Execute a TRUNCATE statement at runtime. @@ -495,6 +495,11 @@ bool Sql_cmd_truncate_table::execute(THD *thd) TABLE_LIST *first_table= thd->lex->select_lex.table_list.first; DBUG_ENTER("Sql_cmd_truncate_table::execute"); + bool truncate_history= thd->lex->current_select->vers_conditions.type != + FOR_SYSTEM_TIME_UNSPECIFIED; + if (truncate_history) + DBUG_RETURN(mysql_delete(thd, first_table, NULL, NULL, -1, 0, NULL)); + if (check_one_table_access(thd, DROP_ACL, first_table)) DBUG_RETURN(res); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index f591566d91a..4c781a6afd1 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -12998,8 +12998,9 @@ truncate: lex->select_lex.init_order(); YYPS->m_lock_type= TL_WRITE; YYPS->m_mdl_type= MDL_EXCLUSIVE; + Select->vers_conditions.empty(); } - table_name opt_lock_wait_timeout + table_name opt_for_system_time_clause opt_lock_wait_timeout { LEX* lex= thd->lex; DBUG_ASSERT(!lex->m_sql_cmd); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 4ad15369ac5..60e34103d76 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -9644,7 +9644,11 @@ ha_innobase::delete_row( innobase_srv_conc_enter_innodb(m_prebuilt); - error = row_update_for_mysql((byte*) record, m_prebuilt); + bool delete_history_row = + table->versioned() && !table->vers_end_field()->is_max(); + + error = row_update_for_mysql( + (byte *)record, m_prebuilt, delete_history_row); innobase_srv_conc_exit_innodb(m_prebuilt); diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index 6fa0a926e3f..922236283ea 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -280,7 +280,8 @@ row_table_got_default_clust_index( dberr_t row_update_for_mysql( const byte* mysql_rec, - row_prebuilt_t* prebuilt) + row_prebuilt_t* prebuilt, + bool delete_history_row = false) MY_ATTRIBUTE((warn_unused_result)); /** This can only be used when srv_locks_unsafe_for_binlog is TRUE or this diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 14a393830af..fceaf65c407 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -1859,7 +1859,8 @@ static dberr_t row_update_for_mysql_using_upd_graph( const byte* mysql_rec, - row_prebuilt_t* prebuilt) + row_prebuilt_t* prebuilt, + bool delete_history_row) { trx_savept_t savept; dberr_t err; @@ -1993,7 +1994,7 @@ row_update_for_mysql_using_upd_graph( run_again: if (DICT_TF2_FLAG_IS_SET(node->table, DICT_TF2_VERSIONED) && - (node->is_delete || node->versioned)) + (node->is_delete || node->versioned) && !delete_history_row) { /* System Versioning: modify update vector to set sys_trx_start (or sys_trx_end in case of DELETE) @@ -2257,10 +2258,12 @@ error: dberr_t row_update_for_mysql( const byte* mysql_rec, - row_prebuilt_t* prebuilt) + row_prebuilt_t* prebuilt, + bool delete_history_row) { ut_a(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW); - return(row_update_for_mysql_using_upd_graph(mysql_rec, prebuilt)); + return (row_update_for_mysql_using_upd_graph( + mysql_rec, prebuilt, delete_history_row)); } /** This can only be used when srv_locks_unsafe_for_binlog is TRUE or this -- cgit v1.2.1 From 57692d71176693cb9ee8e8946336b4e2c1feb2ef Mon Sep 17 00:00:00 2001 From: kevg Date: Tue, 10 Jan 2017 15:15:39 +0300 Subject: SQL, IB: ALTER ADD AUTO_INCREMENT for versioned tables [closes #112] --- mysql-test/suite/versioning/r/alter.result | 70 ++++++++++++++++++++++++++++++ mysql-test/suite/versioning/t/alter.test | 32 ++++++++++++++ sql/handler.cc | 31 ++++++++++++- sql/handler.h | 2 + sql/sql_table.cc | 4 ++ storage/innobase/row/row0merge.cc | 19 +++++++- 6 files changed, 156 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/versioning/r/alter.result b/mysql-test/suite/versioning/r/alter.result index 5db4020f7f2..d9353f957dd 100644 --- a/mysql-test/suite/versioning/r/alter.result +++ b/mysql-test/suite/versioning/r/alter.result @@ -353,6 +353,70 @@ Table Create Table t CREATE TABLE `t` ( `a` int(11) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1 +create or replace table t (a int) with system versioning engine=innodb; +insert into t values (1), (2), (3); +delete from t where a<3; +alter table t add b int auto_increment unique; +select * from t for system_time all; +a b +1 -1 +2 -2 +3 1 +insert into t values (4, NULL); +select * from t for system_time all; +a b +1 -1 +2 -2 +3 1 +4 2 +create or replace table t (a int) with system versioning; +insert into t values (1), (2), (3); +delete from t where a<3; +alter table t add b int auto_increment unique; +select * from t for system_time all; +a b +1 -1 +2 -2 +3 1 +insert into t values (4, NULL); +select * from t for system_time all; +a b +1 -1 +2 -2 +3 1 +4 2 +create or replace table t (a int) with system versioning engine=innodb; +insert into t values (1), (2), (3); +delete from t where a<3; +alter table t add b tinyint auto_increment unique; +select * from t for system_time all; +a b +1 -1 +2 -2 +3 1 +insert into t values (4, NULL); +select * from t for system_time all; +a b +1 -1 +2 -2 +3 1 +4 2 +create or replace table t (a int) with system versioning; +insert into t values (1), (2), (3); +delete from t where a<3; +alter table t add b tinyint auto_increment unique; +select * from t for system_time all; +a b +1 -1 +2 -2 +3 1 +insert into t values (4, NULL); +select * from t for system_time all; +a b +1 -1 +2 -2 +3 1 +4 2 call verify_vtq; No A B C D 1 1 1 1 1 @@ -360,5 +424,11 @@ No A B C D 3 1 1 1 1 4 1 1 1 1 5 1 1 1 1 +6 1 1 1 1 +7 1 1 1 1 +8 1 1 1 1 +9 1 1 1 1 +10 1 1 1 1 +11 1 1 1 1 drop table t; drop procedure verify_vtq; diff --git a/mysql-test/suite/versioning/t/alter.test b/mysql-test/suite/versioning/t/alter.test index 2fdd59979dc..99d200c93f0 100644 --- a/mysql-test/suite/versioning/t/alter.test +++ b/mysql-test/suite/versioning/t/alter.test @@ -165,6 +165,38 @@ alter table t without system versioning, algorithm=inplace; alter table t without system versioning, algorithm=copy; show create table t; +create or replace table t (a int) with system versioning engine=innodb; +insert into t values (1), (2), (3); +delete from t where a<3; +alter table t add b int auto_increment unique; +select * from t for system_time all; +insert into t values (4, NULL); +select * from t for system_time all; + +create or replace table t (a int) with system versioning; +insert into t values (1), (2), (3); +delete from t where a<3; +alter table t add b int auto_increment unique; +select * from t for system_time all; +insert into t values (4, NULL); +select * from t for system_time all; + +create or replace table t (a int) with system versioning engine=innodb; +insert into t values (1), (2), (3); +delete from t where a<3; +alter table t add b tinyint auto_increment unique; +select * from t for system_time all; +insert into t values (4, NULL); +select * from t for system_time all; + +create or replace table t (a int) with system versioning; +insert into t values (1), (2), (3); +delete from t where a<3; +alter table t add b tinyint auto_increment unique; +select * from t for system_time all; +insert into t values (4, NULL); +select * from t for system_time all; + call verify_vtq; drop table t; drop procedure verify_vtq; diff --git a/sql/handler.cc b/sql/handler.cc index 98f558f50cc..c19d04236d7 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -3023,6 +3023,35 @@ int handler::update_auto_increment() enum enum_check_fields save_count_cuted_fields; DBUG_ENTER("handler::update_auto_increment"); + if (table->versioned_by_sql()) + { + Field *end= table->vers_end_field(); + DBUG_ASSERT(end); + bitmap_set_bit(table->read_set, end->field_index); + if (!end->is_max()) + { + uchar *ptr= table->next_number_field->ptr; + switch (table->next_number_field->pack_length()) + { + case 8: + int8store(ptr, vers_auto_decrement--); + break; + case 4: + int4store(ptr, vers_auto_decrement--); + break; + case 2: + int2store(ptr, vers_auto_decrement--); + break; + case 1: + *ptr= vers_auto_decrement--; + break; + default: + DBUG_ASSERT(false); + } + DBUG_RETURN(0); + } + } + /* next_insert_id is a "cursor" into the reserved interval, it may go greater than the interval, but not smaller. @@ -3145,7 +3174,7 @@ int handler::update_auto_increment() /* Store field without warning (Warning will be printed by insert) */ save_count_cuted_fields= thd->count_cuted_fields; thd->count_cuted_fields= CHECK_FIELD_IGNORE; - tmp= table->next_number_field->store((longlong) nr, TRUE); + tmp= table->next_number_field->store((longlong)nr, TRUE); thd->count_cuted_fields= save_count_cuted_fields; if (unlikely(tmp)) // Out of range value in store diff --git a/sql/handler.h b/sql/handler.h index 56ee1addd6d..e20f95df1f3 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -2835,6 +2835,8 @@ public: */ uint auto_inc_intervals_count; + ulonglong vers_auto_decrement; + /** Instrumented table associated with this handler. This member should be set to NULL when no instrumentation is in place, diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 9ad37134c86..b5cf35ed17c 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -9777,6 +9777,10 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, { from_sys_trx_end= from->field[from->s->row_end_field]; } + else if (from->versioned() && to->versioned()) + { + to->file->vers_auto_decrement= 0xffffffffffffffff; + } THD_STAGE_INFO(thd, stage_copy_to_tmp_table); /* Tell handler that we have values for all columns in the to table */ diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index 85f0ce2c9e6..810e285da26 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -1832,6 +1832,7 @@ row_merge_read_clustered_index( double curr_progress = 0.0; ib_uint64_t read_rows = 0; ib_uint64_t table_total_rows = 0; + ulonglong historic_auto_decrement = 0xffffffffffffffff; DBUG_ENTER("row_merge_read_clustered_index"); @@ -2236,6 +2237,18 @@ end_of_index: ut_ad(add_autoinc < dict_table_get_n_user_cols(new_table)); + bool row_is_historic = false; + if (DICT_TF2_FLAG_IS_SET( + new_table, DICT_TF2_VERSIONED)) { + const dfield_t *dfield = dtuple_get_nth_field( + row, new_table->vers_row_end); + const byte *data = static_cast( + dfield_get_data(dfield)); + ut_ad(dfield_get_len(dfield) == 8); + row_is_historic = + mach_read_from_8(data) != TRX_ID_MAX; + } + const dfield_t* dfield; dfield = dtuple_get_nth_field(row, add_autoinc); @@ -2256,7 +2269,11 @@ end_of_index: goto func_exit; } - ulonglong value = sequence++; + ulonglong value; + if (likely(!row_is_historic)) + value = sequence++; + else + value = historic_auto_decrement--; switch (dtype_get_mtype(dtype)) { case DATA_INT: { -- cgit v1.2.1 From 3a64d55aede6db2b3d520e7fbc17e70cfeb8916e Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Fri, 13 Jan 2017 13:56:01 +0000 Subject: Parser, SQL: table-specific FOR SYSTEM_TIME [closes #116] * Syntax sugar: query-global QUERY FOR SYSTEM_TIME --- .../suite/versioning/r/optimized_fields.result | 12 +-- mysql-test/suite/versioning/r/select.result | 6 +- mysql-test/suite/versioning/r/view.result | 2 +- .../suite/versioning/t/optimized_fields.test | 12 +-- mysql-test/suite/versioning/t/select.test | 6 +- sql/item.cc | 6 +- sql/sql_lex.cc | 15 +++ sql/sql_lex.h | 3 + sql/sql_select.cc | 105 +++++++++++---------- sql/sql_yacc.yy | 97 ++++++++++--------- sql/table.h | 5 +- 11 files changed, 153 insertions(+), 116 deletions(-) diff --git a/mysql-test/suite/versioning/r/optimized_fields.result b/mysql-test/suite/versioning/r/optimized_fields.result index ea5b174f6dd..20fab121a69 100644 --- a/mysql-test/suite/versioning/r/optimized_fields.result +++ b/mysql-test/suite/versioning/r/optimized_fields.result @@ -25,7 +25,7 @@ a b 3 NULL Warnings: Warning 4075 Attempt to read unversioned field `b` in historical query -select count(*) from t group by b for system_time as of timestamp now(6); +select count(*) from t group by b query for system_time as of timestamp now(6); count(*) 2 Warnings: @@ -42,23 +42,23 @@ a b 3 NULL Warnings: Warning 4075 Attempt to read unversioned field `b` in historical query -select * from t group by a having a=2 for system_time as of timestamp now(6); +select * from t group by a having a=2 query for system_time as of timestamp now(6); a b Warnings: Warning 4075 Attempt to read unversioned field `b` in historical query -select * from t group by b having b=2 for system_time as of timestamp now(6); +select * from t group by b having b=2 query for system_time as of timestamp now(6); a b Warnings: Warning 4075 Attempt to read unversioned field `b` in historical query -select a from t where b=2 for system_time as of timestamp now(6); +select a from t where b=2 query for system_time as of timestamp now(6); a Warnings: Warning 4075 Attempt to read unversioned field `b` in historical query -select a from t where b=NULL for system_time as of timestamp now(6); +select a from t where b=NULL query for system_time as of timestamp now(6); a Warnings: Warning 4075 Attempt to read unversioned field `b` in historical query -select count(*), b from t group by b having b=NULL for system_time as of timestamp now(6); +select count(*), b from t group by b having b=NULL query for system_time as of timestamp now(6); count(*) b Warnings: Warning 4075 Attempt to read unversioned field `b` in historical query diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index dad8b394079..72f8e0424d6 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -95,11 +95,11 @@ select t1.x as RJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 delete from t1; delete from t2; select t1.x as IJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x -for system_time as of timestamp @t0; +query for system_time as of timestamp @t0; select t1.x as LJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x -for system_time as of timestamp @t0; +query for system_time as of timestamp @t0; select t1.x as RJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x -for system_time as of timestamp @t0; +query for system_time as of timestamp @t0; drop table t1; drop table t2; end~~ diff --git a/mysql-test/suite/versioning/r/view.result b/mysql-test/suite/versioning/r/view.result index eeec506f933..5fa59b23c47 100644 --- a/mysql-test/suite/versioning/r/view.result +++ b/mysql-test/suite/versioning/r/view.result @@ -23,7 +23,7 @@ x create or replace view vt1 as select * from t1; show create view vt1; View Create View character_set_client collation_connection -vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`x` AS `x` from `t1` where `t1`.`sys_trx_end` = 18446744073709551615 for system_time all latin1 latin1_swedish_ci +vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`x` AS `x` from `t1` where `t1`.`sys_trx_end` = 18446744073709551615 query for system_time all latin1 latin1_swedish_ci drop view vt1; drop view vt2; drop table t1; diff --git a/mysql-test/suite/versioning/t/optimized_fields.test b/mysql-test/suite/versioning/t/optimized_fields.test index 62f245dc28d..02f51423cc1 100644 --- a/mysql-test/suite/versioning/t/optimized_fields.test +++ b/mysql-test/suite/versioning/t/optimized_fields.test @@ -9,14 +9,14 @@ select * from t; select a from t for system_time as of timestamp now(6); select a, b, b+0 from t for system_time as of timestamp now(6); select * from t for system_time as of timestamp now(6); -select count(*) from t group by b for system_time as of timestamp now(6); +select count(*) from t group by b query for system_time as of timestamp now(6); select * from t for system_time as of timestamp now(6) order by b asc; select * from t for system_time as of timestamp now(6) order by b desc; -select * from t group by a having a=2 for system_time as of timestamp now(6); -select * from t group by b having b=2 for system_time as of timestamp now(6); -select a from t where b=2 for system_time as of timestamp now(6); -select a from t where b=NULL for system_time as of timestamp now(6); -select count(*), b from t group by b having b=NULL for system_time as of timestamp now(6); +select * from t group by a having a=2 query for system_time as of timestamp now(6); +select * from t group by b having b=2 query for system_time as of timestamp now(6); +select a from t where b=2 query for system_time as of timestamp now(6); +select a from t where b=NULL query for system_time as of timestamp now(6); +select count(*), b from t group by b having b=NULL query for system_time as of timestamp now(6); select a, b from t; drop table t; diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index d47b09e2205..ca3f8d2b3b7 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -91,11 +91,11 @@ begin delete from t2; select t1.x as IJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x - for system_time as of timestamp @t0; + query for system_time as of timestamp @t0; select t1.x as LJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x - for system_time as of timestamp @t0; + query for system_time as of timestamp @t0; select t1.x as RJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x - for system_time as of timestamp @t0; + query for system_time as of timestamp @t0; drop table t1; drop table t2; diff --git a/sql/item.cc b/sql/item.cc index 4bcdb477a51..bb1efca232b 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2762,8 +2762,10 @@ void Item_field::set_field(Field *field_par) field->force_null= false; if (field->flags & VERS_OPTIMIZED_UPDATE_FLAG && context && - context->select_lex && - context->select_lex->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED) + ((field->table->pos_in_table_list && + field->table->pos_in_table_list->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED) || + (context->select_lex && + context->select_lex->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED))) { field->force_null= true; push_warning_printf( diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 3375324b027..75a4c3bbc0c 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -766,6 +766,8 @@ void LEX::start(THD *thd_arg) frame_bottom_bound= NULL; win_spec= NULL; + vers_conditions.empty(); + is_lex_started= TRUE; DBUG_VOID_RETURN; } @@ -1366,6 +1368,19 @@ int MYSQLlex(YYSTYPE *yylval, THD *thd) return FOR_SYM; } break; + case QUERY_SYM: + token= lex_one_token(yylval, thd); + lip->add_digest_token(token, yylval); + switch(token) { + case FOR_SYM: + return QUERY_FOR_SYM; + default: + lip->lookahead_yylval= lip->yylval; + lip->yylval= NULL; + lip->lookahead_token= token; + return QUERY_SYM; + } + break; default: break; } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index c0e28ab8fd2..06aa248ee02 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -2920,6 +2920,9 @@ public: Window_frame_bound *frame_bottom_bound; Window_spec *win_spec; + /* System Versioning */ + vers_select_conds_t vers_conditions; + inline void free_set_stmt_mem_root() { DBUG_ASSERT(!is_arena_for_set_stmt()); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 6655f71e10a..a00304760de 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -688,42 +688,21 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, { if (table->table && table->table->versioned()) versioned_tables++; - } - - vers_range_type_t query_type= slex->vers_conditions.type; - - if (versioned_tables == 0) - { - if (query_type != FOR_SYSTEM_TIME_UNSPECIFIED) + else if (table->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED) { my_error(ER_VERSIONING_REQUIRED, MYF(0), "`FOR SYSTEM_TIME` query"); DBUG_RETURN(-1); } - DBUG_RETURN(0); } - if (query_type != FOR_SYSTEM_TIME_UNSPECIFIED) + if (versioned_tables == 0) { - switch (slex->lock_type) + if (slex->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED) { - case TL_WRITE_ALLOW_WRITE: - case TL_WRITE_CONCURRENT_INSERT: - case TL_WRITE_DELAYED: - case TL_WRITE_DEFAULT: - case TL_WRITE_LOW_PRIORITY: - case TL_WRITE: - case TL_WRITE_ONLY: - my_error(ER_VERS_WRONG_PARAMS, MYF(0), "FOR SYSTEM_TIME query", "write-locking of historic rows"); + my_error(ER_VERSIONING_REQUIRED, MYF(0), "`FOR SYSTEM_TIME` query"); DBUG_RETURN(-1); - default: - break; - } - - if (query_type == FOR_SYSTEM_TIME_ALL) - { - slex->vers_conditions.unwrapped= true; - DBUG_RETURN(0); } + DBUG_RETURN(0); } /* For prepared statements we create items on statement arena, @@ -779,6 +758,36 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, { if (table->table && table->table->versioned()) { + vers_select_conds_t &vers_conditions= + table->vers_conditions.type == FOR_SYSTEM_TIME_UNSPECIFIED ? + slex->vers_conditions : table->vers_conditions; + + if (vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED) + { + switch (slex->lock_type) + { + case TL_WRITE_ALLOW_WRITE: + case TL_WRITE_CONCURRENT_INSERT: + case TL_WRITE_DELAYED: + case TL_WRITE_DEFAULT: + case TL_WRITE_LOW_PRIORITY: + case TL_WRITE: + case TL_WRITE_ONLY: + my_error(ER_VERS_WRONG_PARAMS, MYF(0), "FOR SYSTEM_TIME query", "write-locking of historic rows"); + if (arena) + thd->restore_active_arena(arena, &backup); + DBUG_RETURN(-1); + default: + break; + } + + if (vers_conditions.type == FOR_SYSTEM_TIME_ALL) + { + vers_conditions.unwrapped= true; + continue; + } + } + COND** dst_cond= where_expr; if (table->on_expr) { @@ -798,14 +807,14 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, if (table->table->versioned_by_sql()) { - if (slex->vers_conditions.unit == UNIT_TRX_ID) + if (vers_conditions.unit == UNIT_TRX_ID) { my_error(ER_VERS_ENGINE_UNSUPPORTED, MYF(0), table->table_name); DBUG_RETURN(-1); } } - else if (vers_simple_select && slex->vers_conditions.unit == UNIT_TIMESTAMP - && query_type != FOR_SYSTEM_TIME_UNSPECIFIED) + else if (vers_simple_select && vers_conditions.unit == UNIT_TIMESTAMP + && vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED) { DBUG_ASSERT(table->table->s && table->table->s->db_plugin); handlerton *hton= plugin_hton(table->table->s->db_plugin); @@ -826,7 +835,7 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, Item *cond1= 0, *cond2= 0, *curr= 0; if (table->table->versioned_by_sql() || vers_simple_select) { - switch (query_type) + switch (vers_conditions.type) { case FOR_SYSTEM_TIME_UNSPECIFIED: if (table->table->versioned_by_sql()) @@ -844,21 +853,21 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, break; case FOR_SYSTEM_TIME_AS_OF: cond1= newx Item_func_le(thd, row_start, - slex->vers_conditions.start); + vers_conditions.start); cond2= newx Item_func_gt(thd, row_end, - slex->vers_conditions.start); + vers_conditions.start); break; case FOR_SYSTEM_TIME_FROM_TO: cond1= newx Item_func_lt(thd, row_start, - slex->vers_conditions.end); + vers_conditions.end); cond2= newx Item_func_ge(thd, row_end, - slex->vers_conditions.start); + vers_conditions.start); break; case FOR_SYSTEM_TIME_BETWEEN: cond1= newx Item_func_le(thd, row_start, - slex->vers_conditions.end); + vers_conditions.end); cond2= newx Item_func_ge(thd, row_end, - slex->vers_conditions.start); + vers_conditions.start); break; default: DBUG_ASSERT(0); @@ -872,33 +881,33 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, Item *trx_id0, *trx_id1; - switch (query_type) + switch (vers_conditions.type) { case FOR_SYSTEM_TIME_UNSPECIFIED: curr= newx Item_int(thd, ULONGLONG_MAX); cond1= newx Item_func_eq(thd, row_end2, curr); break; case FOR_SYSTEM_TIME_AS_OF: - trx_id0= slex->vers_conditions.unit == UNIT_TIMESTAMP ? - newx Item_func_vtq_id(thd, slex->vers_conditions.start, VTQ_TRX_ID) : - slex->vers_conditions.start; + trx_id0= vers_conditions.unit == UNIT_TIMESTAMP ? + newx Item_func_vtq_id(thd, vers_conditions.start, VTQ_TRX_ID) : + vers_conditions.start; cond1= newx Item_func_vtq_trx_sees_eq(thd, trx_id0, row_start); cond2= newx Item_func_vtq_trx_sees(thd, row_end, trx_id0); break; case FOR_SYSTEM_TIME_FROM_TO: case FOR_SYSTEM_TIME_BETWEEN: - if (slex->vers_conditions.unit == UNIT_TIMESTAMP) + if (vers_conditions.unit == UNIT_TIMESTAMP) { - trx_id0= newx Item_func_vtq_id(thd, slex->vers_conditions.start, VTQ_TRX_ID, true); - trx_id1= newx Item_func_vtq_id(thd, slex->vers_conditions.end, VTQ_TRX_ID, false); + trx_id0= newx Item_func_vtq_id(thd, vers_conditions.start, VTQ_TRX_ID, true); + trx_id1= newx Item_func_vtq_id(thd, vers_conditions.end, VTQ_TRX_ID, false); } else { - trx_id0= slex->vers_conditions.start; - trx_id1= slex->vers_conditions.end; + trx_id0= vers_conditions.start; + trx_id1= vers_conditions.end; } - cond1= query_type == FOR_SYSTEM_TIME_FROM_TO ? + cond1= vers_conditions.type == FOR_SYSTEM_TIME_FROM_TO ? newx Item_func_vtq_trx_sees(thd, trx_id1, row_start) : newx Item_func_vtq_trx_sees_eq(thd, trx_id1, row_start); cond2= newx Item_func_vtq_trx_sees_eq(thd, row_end, trx_id0); @@ -925,9 +934,7 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, } // for (table= tables; ...) if (arena) - { thd->restore_active_arena(arena, &backup); - } slex->vers_conditions.unwrapped= true; @@ -25554,7 +25561,7 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type) if (vers_conditions.unwrapped) { // versioning conditions are already unwrapped to WHERE clause - str->append(STRING_WITH_LEN(" for system_time all ")); + str->append(STRING_WITH_LEN(" query for system_time all ")); } if (order_list.elements) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 4c781a6afd1..11f4b53eb8b 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -751,6 +751,7 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr) %} %union { + bool BOOL; int num; ulong ulong_num; ulonglong ulonglong_number; @@ -1352,6 +1353,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token PURGE %token QUARTER_SYM %token QUERY_SYM +%token QUERY_FOR_SYM /* INTERNAL */ %token QUICK %token RAISE_SYM /* Oracle-PLSQL-R */ %token RANGE_SYM /* SQL-2003-R */ @@ -1970,6 +1972,7 @@ END_OF_INPUT %type opt_with_column_list %type trans_or_timestamp +%type opt_for_system_time_clause %% @@ -8762,7 +8765,7 @@ table_expression: opt_group_clause opt_having_clause opt_window_clause - opt_for_system_time_clause + opt_query_for_system_time_clause ; opt_table_expression: @@ -8808,75 +8811,74 @@ trans_or_timestamp: } ; -opt_for_system_time_clause: +opt_query_for_system_time_clause: /* empty */ {} - | FOR_SYSTEM_TIME_SYM - AS OF_SYM - trans_or_timestamp simple_expr + | QUERY_FOR_SYM SYSTEM_TIME_SYM for_system_time_expr + { + DBUG_ASSERT(Select); + Select->vers_conditions= Lex->vers_conditions; + } + ; + +opt_for_system_time_clause: + /* empty */ + { + $$= false; + } + | FOR_SYSTEM_TIME_SYM for_system_time_expr + { + $$= true; + } + ; + +for_system_time_expr: + AS OF_SYM trans_or_timestamp simple_expr { - Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_AS_OF, $4, $5); + Lex->vers_conditions.init(FOR_SYSTEM_TIME_AS_OF, $3, $4); } - | FOR_SYSTEM_TIME_SYM - AS OF_SYM - NOW_SYM + | AS OF_SYM NOW_SYM { Item *item= new (thd->mem_root) Item_func_now_local(thd, 6); if (item == NULL) MYSQL_YYABORT; - Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_AS_OF, UNIT_TIMESTAMP, item); + Lex->vers_conditions.init(FOR_SYSTEM_TIME_AS_OF, UNIT_TIMESTAMP, item); } - | FOR_SYSTEM_TIME_SYM ALL + | ALL { - Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_ALL, UNIT_TIMESTAMP); + Lex->vers_conditions.init(FOR_SYSTEM_TIME_ALL, UNIT_TIMESTAMP); } - | FOR_SYSTEM_TIME_SYM - FROM - trans_or_timestamp - simple_expr - TO_SYM - trans_or_timestamp - simple_expr + | FROM trans_or_timestamp simple_expr + TO_SYM trans_or_timestamp simple_expr { - if ($3 != $6) + if ($2 != $5) { Lex->parse_error(ER_VERS_RANGE_UNITS_MISMATCH); MYSQL_YYABORT; } - Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_FROM_TO, $3, $4, $7); + Lex->vers_conditions.init(FOR_SYSTEM_TIME_FROM_TO, $2, $3, $6); } - | FOR_SYSTEM_TIME_SYM - trans_or_timestamp - FROM - simple_expr - TO_SYM - simple_expr + | trans_or_timestamp + FROM simple_expr + TO_SYM simple_expr { - Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_FROM_TO, $2, $4, $6); + Lex->vers_conditions.init(FOR_SYSTEM_TIME_FROM_TO, $1, $3, $5); } - | FOR_SYSTEM_TIME_SYM - BETWEEN_SYM - trans_or_timestamp - simple_expr - AND_SYM - trans_or_timestamp - simple_expr + | BETWEEN_SYM trans_or_timestamp simple_expr + AND_SYM trans_or_timestamp simple_expr { - if ($3 != $6) + if ($2 != $5) { Lex->parse_error(ER_VERS_RANGE_UNITS_MISMATCH); MYSQL_YYABORT; } - Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_BETWEEN, $3, $4, $7); + Lex->vers_conditions.init(FOR_SYSTEM_TIME_BETWEEN, $2, $3, $6); } - | FOR_SYSTEM_TIME_SYM - trans_or_timestamp - BETWEEN_SYM - simple_expr - AND_SYM - simple_expr + | trans_or_timestamp + BETWEEN_SYM simple_expr + AND_SYM simple_expr { - Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_BETWEEN, $2, $4, $6); + Lex->vers_conditions.init(FOR_SYSTEM_TIME_BETWEEN, $1, $3, $5); } ; @@ -11284,10 +11286,11 @@ table_factor: table_primary_ident: { + DBUG_ASSERT(Select); SELECT_LEX *sel= Select; sel->table_join_options= 0; } - table_ident opt_use_partition opt_table_alias opt_key_definition + table_ident opt_use_partition opt_table_alias opt_key_definition opt_for_system_time_clause { if (!($$= Select->add_table_to_list(thd, $2, $4, Select->get_table_join_options(), @@ -11297,6 +11300,8 @@ table_primary_ident: $3))) MYSQL_YYABORT; Select->add_joined_table($$); + if ($6) + $$->vers_conditions= Lex->vers_conditions; } ; @@ -13007,6 +13012,8 @@ truncate: lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_truncate_table(); if (lex->m_sql_cmd == NULL) MYSQL_YYABORT; + if ($5) + Select->vers_conditions= Lex->vers_conditions; } ; diff --git a/sql/table.h b/sql/table.h index da91162523a..a13de8d7128 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1856,7 +1856,7 @@ enum vers_range_unit_t UNIT_TRX_ID }; -/** System versioning support. */ +/** last_leaf_for_name_resolutioning support. */ struct vers_select_conds_t { vers_range_type_t type; @@ -2344,6 +2344,9 @@ struct TABLE_LIST TABLE_LIST *first_leaf_for_name_resolution(); TABLE_LIST *last_leaf_for_name_resolution(); + /* System Versioning */ + vers_select_conds_t vers_conditions; + /** @brief Find the bottom in the chain of embedded table VIEWs. -- cgit v1.2.1 From e069de7d9da69dd0aed3147a493402cbdeca2c12 Mon Sep 17 00:00:00 2001 From: kevg Date: Thu, 12 Jan 2017 13:51:12 +0300 Subject: SQL: TRUNCATE FOR SYSTEM_TIME BEFORE [closes #111] --- .../suite/versioning/r/truncate_history.result | 48 ++++++++++++++++++++++ .../suite/versioning/t/truncate_history.test | 25 +++++++++++ sql/share/errmsg-utf8.txt | 3 ++ sql/sql_delete.cc | 15 ++++--- sql/sql_select.cc | 18 ++++++++ sql/sql_yacc.yy | 6 +++ sql/table.h | 3 +- 7 files changed, 112 insertions(+), 6 deletions(-) diff --git a/mysql-test/suite/versioning/r/truncate_history.result b/mysql-test/suite/versioning/r/truncate_history.result index d71354bcc36..667fb002d4b 100644 --- a/mysql-test/suite/versioning/r/truncate_history.result +++ b/mysql-test/suite/versioning/r/truncate_history.result @@ -111,5 +111,53 @@ select * from t for system_time all; a 9 8 +create or replace table t (a int) with system versioning; +insert into t values (1), (2); +update t set a=11 where a=1; +set @ts1=now(6); +update t set a=22 where a=2; +select * from t for system_time all; +a +11 +22 +1 +2 +truncate t for system_time before timestamp @ts1; +select * from t for system_time all; +a +11 +22 +2 +truncate t for system_time before timestamp now(6); +select * from t for system_time all; +a +11 +22 +create or replace table t (a int) with system versioning engine=innodb; +insert into t values (1), (2); +update t set a=11 where a=1; +set @ts1=now(6); +update t set a=22 where a=2; +select * from t for system_time all; +a +11 +22 +1 +2 +truncate t for system_time before timestamp @ts1; +select * from t for system_time all; +a +11 +22 +1 +2 +truncate t for system_time before timestamp now(6); +select * from t for system_time all; +a +11 +22 +2 +select * from t for system_time before timestamp now(); +ERROR HY000: `FOR SYSTEM_TIME BEFORE` works only with `TRUNCATE` query type drop table t; drop procedure truncate_history_of_t; diff --git a/mysql-test/suite/versioning/t/truncate_history.test b/mysql-test/suite/versioning/t/truncate_history.test index 42f60f51d46..d112af63df3 100644 --- a/mysql-test/suite/versioning/t/truncate_history.test +++ b/mysql-test/suite/versioning/t/truncate_history.test @@ -90,5 +90,30 @@ update t set a=9; truncate t for system_time timestamp between '1-1-1' and @ts2; select * from t for system_time all; +create or replace table t (a int) with system versioning; +insert into t values (1), (2); +update t set a=11 where a=1; +set @ts1=now(6); +update t set a=22 where a=2; +select * from t for system_time all; +truncate t for system_time before timestamp @ts1; +select * from t for system_time all; +truncate t for system_time before timestamp now(6); +select * from t for system_time all; + +create or replace table t (a int) with system versioning engine=innodb; +insert into t values (1), (2); +update t set a=11 where a=1; +set @ts1=now(6); +update t set a=22 where a=2; +select * from t for system_time all; +truncate t for system_time before timestamp @ts1; +select * from t for system_time all; +truncate t for system_time before timestamp now(6); +select * from t for system_time all; + +--error ER_VERS_WRONG_QUERY_TYPE +select * from t for system_time before timestamp now(); + drop table t; drop procedure truncate_history_of_t; diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index daca9b4ce52..b30240f64c3 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7525,3 +7525,6 @@ WARN_VERS_PART_ROTATION ER_VERS_NOT_ALLOWED eng "%`s is not allowed for versioned table" + +ER_VERS_WRONG_QUERY_TYPE + eng "%`s works only with %`s query type" diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 5d62b54b297..7d59d5164e1 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -283,11 +283,16 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, DBUG_RETURN(TRUE); // trx_sees() in InnoDB reads sys_trx_start - if (!table->versioned_by_sql() && - (select_lex->vers_conditions.type == FOR_SYSTEM_TIME_BETWEEN || - select_lex->vers_conditions.type == FOR_SYSTEM_TIME_FROM_TO)) - { - bitmap_set_bit(table->read_set, table->vers_start_field()->field_index); + if (!table->versioned_by_sql()) { + if (select_lex->vers_conditions.type == FOR_SYSTEM_TIME_BETWEEN || + select_lex->vers_conditions.type == FOR_SYSTEM_TIME_FROM_TO) + { + bitmap_set_bit(table->read_set, table->vers_start_field()->field_index); + } + else if (select_lex->vers_conditions.type == FOR_SYSTEM_TIME_BEFORE) + { + bitmap_set_bit(table->read_set, table->vers_end_field()->field_index); + } } } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a00304760de..2d4d603c078 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -762,6 +762,14 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, table->vers_conditions.type == FOR_SYSTEM_TIME_UNSPECIFIED ? slex->vers_conditions : table->vers_conditions; + if (vers_conditions.type == FOR_SYSTEM_TIME_BEFORE && + thd->lex->sql_command != SQLCOM_TRUNCATE) + { + my_error(ER_VERS_WRONG_QUERY_TYPE, MYF(0), "FOR SYSTEM_TIME BEFORE", + "TRUNCATE"); + DBUG_RETURN(-1); + } + if (vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED) { switch (slex->lock_type) @@ -869,6 +877,10 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, cond2= newx Item_func_ge(thd, row_end, vers_conditions.start); break; + case FOR_SYSTEM_TIME_BEFORE: + cond1= newx Item_func_lt(thd, row_end, + vers_conditions.start); + break; default: DBUG_ASSERT(0); } @@ -912,6 +924,12 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, newx Item_func_vtq_trx_sees_eq(thd, trx_id1, row_start); cond2= newx Item_func_vtq_trx_sees_eq(thd, row_end, trx_id0); break; + case FOR_SYSTEM_TIME_BEFORE: + trx_id0= vers_conditions.unit == UNIT_TIMESTAMP ? + newx Item_func_vtq_id(thd, vers_conditions.start, VTQ_TRX_ID) : + vers_conditions.start; + cond1= newx Item_func_lt(thd, row_end, trx_id0); + break; default: DBUG_ASSERT(0); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 11f4b53eb8b..2f1346eeb40 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -8880,6 +8880,12 @@ for_system_time_expr: { Lex->vers_conditions.init(FOR_SYSTEM_TIME_BETWEEN, $1, $3, $5); } + | BEFORE_SYM + trans_or_timestamp + simple_expr + { + Lex->vers_conditions.init(FOR_SYSTEM_TIME_BEFORE, $2, $3); + } ; select_option_list: diff --git a/sql/table.h b/sql/table.h index a13de8d7128..cb24d211261 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1847,7 +1847,8 @@ enum vers_range_type_t FOR_SYSTEM_TIME_AS_OF, FOR_SYSTEM_TIME_FROM_TO, FOR_SYSTEM_TIME_BETWEEN, - FOR_SYSTEM_TIME_ALL + FOR_SYSTEM_TIME_ALL, + FOR_SYSTEM_TIME_BEFORE }; enum vers_range_unit_t -- cgit v1.2.1 From 26a3ff0a22e931e44edf97b37c41db395eee6553 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Sat, 31 Dec 2016 15:33:26 +0000 Subject: SQL: (0.6) Pruning for VERSIONING partitions [closes #97] * based on RANGE pruning by COLUMNS (sys_trx_end) condition * removed DEFAULT; AS OF NOW is always last; current VERSIONING as last non-empty (or first empty) * Min/Max stats in TABLE_SHARE * ALTER TABLE ADD PARTITION adds before AS OF NOW partition --- .../perfschema/r/dml_setup_instruments.result | 2 +- mysql-test/suite/versioning/r/partition.result | 155 +++++------- mysql-test/suite/versioning/t/partition.test | 109 +++----- sql/ha_partition.cc | 9 + sql/ha_partition.h | 4 +- sql/item.cc | 20 ++ sql/item.h | 6 + sql/mysqld.cc | 7 +- sql/mysqld.h | 3 +- sql/opt_range.cc | 7 +- sql/partition_element.h | 65 +++-- sql/partition_info.cc | 273 ++++++++++++++++----- sql/partition_info.h | 89 ++++++- sql/sql_partition.cc | 51 +++- sql/sql_yacc.yy | 35 ++- sql/table.cc | 32 ++- sql/table.h | 20 +- 17 files changed, 580 insertions(+), 307 deletions(-) diff --git a/mysql-test/suite/perfschema/r/dml_setup_instruments.result b/mysql-test/suite/perfschema/r/dml_setup_instruments.result index 4c123663597..679ba5331c6 100644 --- a/mysql-test/suite/perfschema/r/dml_setup_instruments.result +++ b/mysql-test/suite/perfschema/r/dml_setup_instruments.result @@ -28,7 +28,7 @@ wait/synch/rwlock/sql/LOGGER::LOCK_logger YES YES wait/synch/rwlock/sql/MDL_context::LOCK_waiting_for YES YES wait/synch/rwlock/sql/MDL_lock::rwlock YES YES wait/synch/rwlock/sql/Query_cache_query::lock YES YES -wait/synch/rwlock/sql/THR_LOCK_servers YES YES +wait/synch/rwlock/sql/TABLE_SHARE::LOCK_stat_serial YES YES select * from performance_schema.setup_instruments where name like 'Wait/Synch/Cond/sql/%' and name not in ( diff --git a/mysql-test/suite/versioning/r/partition.result b/mysql-test/suite/versioning/r/partition.result index babd1b4bd4f..104ec304883 100644 --- a/mysql-test/suite/versioning/r/partition.result +++ b/mysql-test/suite/versioning/r/partition.result @@ -30,14 +30,14 @@ x 300 create or replace table t1 (x int) partition by system_time ( -partition p0 as of now, -partition p1 versioning); +partition p0 versioning, +partition pn as of now); ERROR HY000: System Versioning required: `BY SYSTEM_TIME` partitioning create or replace table t1 (x int); alter table t1 partition by system_time ( -partition p0 as of now, -partition p1 versioning); +partition p0 versioning, +partition pn as of now); ERROR HY000: System Versioning required: `BY SYSTEM_TIME` partitioning create or replace table t1 (x int) with system versioning @@ -59,19 +59,37 @@ ERROR HY000: Wrong parameters for `BY SYSTEM_TIME`: no `AS OF NOW` partition def create or replace table t1 (x int) with system versioning partition by system_time ( -partition p0 as of now, -partition p1 versioning); +partition pn as of now, +partition p0 versioning); +ERROR HY000: Wrong parameters for `BY SYSTEM_TIME`: AS OF NOW partition is not last +create or replace table t1 (x int) +with system versioning +partition by system_time ( +partition p0 versioning, +partition pn as of now); alter table t1 add partition ( -partition p2 as of now); -ERROR HY000: Wrong parameters for `BY SYSTEM_TIME`: multiple `AS OF NOW` partitions +partition p1 as of now); +ERROR HY000: Wrong parameters for `BY SYSTEM_TIME`: AS OF NOW partition can not be added alter table t1 add partition ( -partition p2 versioning default); +partition p1 versioning); Warnings: Warning 4078 Maybe missing parameters: no rotation condition for multiple `VERSIONING` partitions. -alter table t1 drop partition p0; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `x` int(11) DEFAULT NULL, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING + PARTITION BY SYSTEM_TIME +(PARTITION p0 VERSIONING ENGINE = MyISAM, + PARTITION p1 VERSIONING ENGINE = MyISAM, + PARTITION pn AS OF NOW ENGINE = MyISAM) +alter table t1 drop partition pn; ERROR HY000: Wrong parameters for `BY SYSTEM_TIME`: `AS OF NOW` partition can not be dropped -alter table t1 drop partition p2; alter table t1 drop partition p1; +alter table t1 drop partition p0; ERROR HY000: Wrong parameters for `BY SYSTEM_TIME`: one `AS OF NOW` and at least one `VERSIONING` partition required insert into t1 values (1); select * from t1; @@ -79,63 +97,41 @@ x 1 select * from t1 partition (p0); x -1 -select * from t1 partition (p1); -x -delete from t1; -select * from t1 partition (p0) for system_time all; -x -select * from t1 partition (p1) for system_time all; -x -1 -create or replace table t1 (x int) -with system versioning -partition by system_time ( -partition p0 versioning, -partition p1 as of now); -insert into t1 values (1); -select * from t1; -x -1 -select * from t1 partition (p0); -x -select * from t1 partition (p1); +select * from t1 partition (pn); x 1 delete from t1; select * from t1 partition (p0) for system_time all; x 1 -select * from t1 partition (p1) for system_time all; +select * from t1 partition (pn) for system_time all; x create or replace table t1 (x int) with system versioning engine myisam partition by system_time limit 1 ( -partition p0 as of now, +partition p0 versioning, partition p1 versioning, -partition p2 versioning); -Warnings: -Warning 4078 No `DEFAULT` for `VERSIONING` partitions. Setting `p1` as default. +partition pn as of now); insert into t1 values (1), (2); -select * from t1 partition (p0); +select * from t1 partition (pn); x 1 2 delete from t1; Warnings: -Note 4079 Switching from partition `p1` to `p2` -select * from t1 partition (p1) for system_time all; +Note 4079 Switching from partition `p0` to `p1` +select * from t1 partition (p0) for system_time all; x 1 -select * from t1 partition (p2) for system_time all; +select * from t1 partition (p1) for system_time all; x 2 insert into t1 values (3); delete from t1; Warnings: -Warning 4077 Using full partition `p2`, need more VERSIONING partitions! -select * from t1 partition (p2) for system_time all; +Warning 4077 Using full partition `p1`, need more VERSIONING partitions! +select * from t1 partition (p1) for system_time all; x 2 3 @@ -143,17 +139,17 @@ create or replace table t1 (x int) with system versioning engine myisam partition by system_time interval 1 second ( -partition p0 as of now, -partition p1 versioning default, -partition p2 versioning); +partition p0 versioning, +partition p1 versioning, +partition pn as of now); insert into t1 values (1), (2), (3); -select * from t1 partition (p0); +select * from t1 partition (pn); x 1 2 3 delete from t1; -select * from t1 partition (p1) for system_time all; +select * from t1 partition (p0) for system_time all; x 1 2 @@ -161,77 +157,40 @@ x insert into t1 values (4); delete from t1; Warnings: -Note 4079 Switching from partition `p1` to `p2` -select * from t1 partition (p2) for system_time all; -x -4 -create or replace table t1 (x int) -with system versioning -engine myisam -partition by system_time limit 1 ( -partition p0 as of now, -partition p1 versioning default, -partition p2 versioning default); -ERROR HY000: Wrong parameters for `BY SYSTEM_TIME`: multiple `DEFAULT` partitions -create or replace table t1 (x int) -with system versioning -engine myisam -partition by system_time limit 1 ( -partition p0 as of now, -partition p1 versioning, -partition p2 versioning default); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `x` int(11) DEFAULT NULL, - `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, - `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, - PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING - PARTITION BY SYSTEM_TIME LIMIT 1 -(PARTITION p0 AS OF NOW ENGINE = MyISAM, - PARTITION p1 VERSIONING ENGINE = MyISAM, - PARTITION p2 VERSIONING DEFAULT ENGINE = MyISAM) -insert into t1 values (4), (5); -delete from t1; -Warnings: -Note 4079 Switching from partition `p2` to `p1` -select * from t1 partition (p2) for system_time all; -x -4 +Note 4079 Switching from partition `p0` to `p1` select * from t1 partition (p1) for system_time all; x -5 +4 create or replace table t1 (x int) with system versioning engine myisam partition by system_time limit 1 subpartition by key (x) subpartitions 2 ( -partition p0 as of now, -partition p1 versioning default, -partition p2 versioning); +partition p0 versioning, +partition p1 versioning, +partition pn as of now); insert into t1 (x) values (1), (2), (3); -select * from t1 partition (p0sp0); +select * from t1 partition (pnsp0); x 1 3 -select * from t1 partition (p0sp1); +select * from t1 partition (pnsp1); x 2 delete from t1; Warnings: -Note 4079 Switching from partition `p1` to `p2` -Warning 4077 Using full partition `p2`, need more VERSIONING partitions! -select * from t1 partition (p1sp0) for system_time all; +Note 4079 Switching from partition `p0` to `p1` +Warning 4077 Using full partition `p1`, need more VERSIONING partitions! +select * from t1 partition (p0sp0) for system_time all; x 1 -select * from t1 partition (p1sp1) for system_time all; +select * from t1 partition (p0sp1) for system_time all; x -select * from t1 partition (p2sp0) for system_time all; +select * from t1 partition (p1sp0) for system_time all; x 3 -select * from t1 partition (p2sp1) for system_time all; +select * from t1 partition (p1sp1) for system_time all; x 2 drop table t1; diff --git a/mysql-test/suite/versioning/t/partition.test b/mysql-test/suite/versioning/t/partition.test index c2b7c097a5f..9483915c4ac 100644 --- a/mysql-test/suite/versioning/t/partition.test +++ b/mysql-test/suite/versioning/t/partition.test @@ -27,15 +27,15 @@ select * from t1 partition (p1) for system_time all; --error ER_VERSIONING_REQUIRED create or replace table t1 (x int) partition by system_time ( - partition p0 as of now, - partition p1 versioning); + partition p0 versioning, + partition pn as of now); create or replace table t1 (x int); --error ER_VERSIONING_REQUIRED alter table t1 partition by system_time ( - partition p0 as of now, - partition p1 versioning); + partition p0 versioning, + partition pn as of now); --error ER_VERS_WRONG_PARAMS create or replace table t1 (x int) @@ -57,112 +57,81 @@ partition by system_time ( partition p0 versioning, partition p1 versioning); +--error ER_VERS_WRONG_PARAMS create or replace table t1 (x int) with system versioning partition by system_time ( - partition p0 as of now, - partition p1 versioning); + partition pn as of now, + partition p0 versioning); + +create or replace table t1 (x int) +with system versioning +partition by system_time ( + partition p0 versioning, + partition pn as of now); # alter table --error ER_VERS_WRONG_PARAMS alter table t1 add partition ( - partition p2 as of now); + partition p1 as of now); alter table t1 add partition ( - partition p2 versioning default); + partition p1 versioning); + +show create table t1; --error ER_VERS_WRONG_PARAMS -alter table t1 drop partition p0; -alter table t1 drop partition p2; ---error ER_VERS_WRONG_PARAMS +alter table t1 drop partition pn; alter table t1 drop partition p1; +--error ER_VERS_WRONG_PARAMS +alter table t1 drop partition p0; # insertion, deletion insert into t1 values (1); select * from t1; select * from t1 partition (p0); -select * from t1 partition (p1); +select * from t1 partition (pn); delete from t1; select * from t1 partition (p0) for system_time all; -select * from t1 partition (p1) for system_time all; - -create or replace table t1 (x int) -with system versioning -partition by system_time ( - partition p0 versioning, - partition p1 as of now); - -insert into t1 values (1); -select * from t1; -select * from t1 partition (p0); -select * from t1 partition (p1); - -delete from t1; -select * from t1 partition (p0) for system_time all; -select * from t1 partition (p1) for system_time all; +select * from t1 partition (pn) for system_time all; # rotation by LIMIT create or replace table t1 (x int) with system versioning engine myisam partition by system_time limit 1 ( - partition p0 as of now, + partition p0 versioning, partition p1 versioning, - partition p2 versioning); + partition pn as of now); insert into t1 values (1), (2); -select * from t1 partition (p0); +select * from t1 partition (pn); delete from t1; +select * from t1 partition (p0) for system_time all; select * from t1 partition (p1) for system_time all; -select * from t1 partition (p2) for system_time all; insert into t1 values (3); delete from t1; -select * from t1 partition (p2) for system_time all; +select * from t1 partition (p1) for system_time all; # rotation by INTERVAL create or replace table t1 (x int) with system versioning engine myisam partition by system_time interval 1 second ( - partition p0 as of now, - partition p1 versioning default, - partition p2 versioning); + partition p0 versioning, + partition p1 versioning, + partition pn as of now); insert into t1 values (1), (2), (3); -select * from t1 partition (p0); +select * from t1 partition (pn); delete from t1; -select * from t1 partition (p1) for system_time all; +select * from t1 partition (p0) for system_time all; --sleep 2 insert into t1 values (4); delete from t1; -select * from t1 partition (p2) for system_time all; - -# DEFAULT partition ---error ER_VERS_WRONG_PARAMS -create or replace table t1 (x int) -with system versioning -engine myisam -partition by system_time limit 1 ( - partition p0 as of now, - partition p1 versioning default, - partition p2 versioning default); - -create or replace table t1 (x int) -with system versioning -engine myisam -partition by system_time limit 1 ( - partition p0 as of now, - partition p1 versioning, - partition p2 versioning default); - -show create table t1; - -insert into t1 values (4), (5); -delete from t1; -select * from t1 partition (p2) for system_time all; select * from t1 partition (p1) for system_time all; # Subpartitions @@ -172,19 +141,19 @@ engine myisam partition by system_time limit 1 subpartition by key (x) subpartitions 2 ( - partition p0 as of now, - partition p1 versioning default, - partition p2 versioning); + partition p0 versioning, + partition p1 versioning, + partition pn as of now); insert into t1 (x) values (1), (2), (3); -select * from t1 partition (p0sp0); -select * from t1 partition (p0sp1); +select * from t1 partition (pnsp0); +select * from t1 partition (pnsp1); delete from t1; +select * from t1 partition (p0sp0) for system_time all; +select * from t1 partition (p0sp1) for system_time all; select * from t1 partition (p1sp0) for system_time all; select * from t1 partition (p1sp1) for system_time all; -select * from t1 partition (p2sp0) for system_time all; -select * from t1 partition (p2sp1) for system_time all; drop table t1; diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 1ba3210d62b..0fa461e1807 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -4289,6 +4289,15 @@ int ha_partition::update_row(const uchar *old_data, uchar *new_data) if (error) goto exit; + if (m_part_info->part_type == VERSIONING_PARTITION) + { + uint sub_factor= m_part_info->num_subparts ? m_part_info->num_subparts : 1; + DBUG_ASSERT(m_tot_parts == m_part_info->num_parts * sub_factor); + uint lpart_id= new_part_id / sub_factor; + // lpart_id is VERSIONING partition because new_part_id != old_part_id + m_part_info->vers_update_stats(thd, lpart_id); + } + tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */ error= m_file[old_part_id]->ha_delete_row(old_data); reenable_binlog(thd); diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 1ca320eef1a..2c7f4a0861f 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -1295,9 +1295,7 @@ public: { handler *file= m_file[part_id]; DBUG_ASSERT(bitmap_is_set(&(m_part_info->read_partitions), part_id)); - file->info(HA_STATUS_TIME | HA_STATUS_VARIABLE | - HA_STATUS_VARIABLE_EXTRA | HA_STATUS_NO_LOCK); - + file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); part_recs+= file->stats.records; } return part_recs; diff --git a/sql/item.cc b/sql/item.cc index bb1efca232b..410fa32f234 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -6989,6 +6989,26 @@ bool Item_temporal_literal::eq(const Item *item, bool binary_cmp) const &((Item_temporal_literal *) item)->cached_time); } +bool Item_temporal_literal::set_lower(MYSQL_TIME * ltime) +{ + if (my_time_compare(ltime, &cached_time) < 0) + { + cached_time= *ltime; + return true; + } + return false; +} + +bool Item_temporal_literal::set_higher(MYSQL_TIME * ltime) +{ + if (my_time_compare(ltime, &cached_time) > 0) + { + cached_time= *ltime; + return true; + } + return false; +} + void Item_date_literal::print(String *str, enum_query_type query_type) { diff --git a/sql/item.h b/sql/item.h index b7381bde260..357eabd72e1 100644 --- a/sql/item.h +++ b/sql/item.h @@ -3865,6 +3865,12 @@ public: { return val_decimal_from_date(decimal_value); } int save_in_field(Field *field, bool no_conversions) { return save_date_in_field(field, no_conversions); } + void set_time(MYSQL_TIME *ltime) + { + cached_time= *ltime; + } + bool set_lower(MYSQL_TIME *ltime); + bool set_higher(MYSQL_TIME *ltime); }; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index acda4b51627..5196ec41c11 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1017,7 +1017,8 @@ static PSI_mutex_info all_server_mutexes[]= PSI_rwlock_key key_rwlock_LOCK_grant, key_rwlock_LOCK_logger, key_rwlock_LOCK_sys_init_connect, key_rwlock_LOCK_sys_init_slave, - key_rwlock_LOCK_system_variables_hash, key_rwlock_query_cache_query_lock; + key_rwlock_LOCK_system_variables_hash, key_rwlock_query_cache_query_lock, + key_rwlock_LOCK_vers_stats, key_rwlock_LOCK_stat_serial; static PSI_rwlock_info all_server_rwlocks[]= { @@ -1029,7 +1030,9 @@ static PSI_rwlock_info all_server_rwlocks[]= { &key_rwlock_LOCK_sys_init_connect, "LOCK_sys_init_connect", PSI_FLAG_GLOBAL}, { &key_rwlock_LOCK_sys_init_slave, "LOCK_sys_init_slave", PSI_FLAG_GLOBAL}, { &key_rwlock_LOCK_system_variables_hash, "LOCK_system_variables_hash", PSI_FLAG_GLOBAL}, - { &key_rwlock_query_cache_query_lock, "Query_cache_query::lock", 0} + { &key_rwlock_query_cache_query_lock, "Query_cache_query::lock", 0}, + { &key_rwlock_LOCK_vers_stats, "Vers_field_stats::lock", 0}, + { &key_rwlock_LOCK_stat_serial, "TABLE_SHARE::LOCK_stat_serial", 0} }; #ifdef HAVE_MMAP diff --git a/sql/mysqld.h b/sql/mysqld.h index 8ac0625b755..46382396a5a 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -314,7 +314,8 @@ extern PSI_mutex_key key_LOCK_gtid_waiting; extern PSI_rwlock_key key_rwlock_LOCK_grant, key_rwlock_LOCK_logger, key_rwlock_LOCK_sys_init_connect, key_rwlock_LOCK_sys_init_slave, - key_rwlock_LOCK_system_variables_hash, key_rwlock_query_cache_query_lock; + key_rwlock_LOCK_system_variables_hash, key_rwlock_query_cache_query_lock, + key_rwlock_LOCK_vers_stats, key_rwlock_LOCK_stat_serial; #ifdef HAVE_MMAP extern PSI_cond_key key_PAGE_cond, key_COND_active, key_COND_pool; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index fbdbf76ffd9..fcf038a212b 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -3454,6 +3454,11 @@ bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond) free_root(&alloc,MYF(0)); // Return memory & allocator DBUG_RETURN(FALSE); } + + if (part_info->part_type == VERSIONING_PARTITION) + { + part_info->vers_update_range_constants(thd); + } dbug_tmp_use_all_columns(table, old_sets, table->read_set, table->write_set); @@ -3980,7 +3985,7 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree) simply set res= -1 as if the mapper had returned that. TODO: What to do here is defined in WL#4065. */ - if (ppar->arg_stack[0]->part == 0) + if (ppar->arg_stack[0]->part == 0 || ppar->part_info->part_type == VERSIONING_PARTITION) { uint32 i; uint32 store_length_array[MAX_KEY]; diff --git a/sql/partition_element.h b/sql/partition_element.h index e76558bf7ae..18276ef713e 100644 --- a/sql/partition_element.h +++ b/sql/partition_element.h @@ -90,38 +90,64 @@ typedef struct p_elem_val struct st_ddl_log_memory_entry; -class Stat_timestampf : public Sql_alloc +class Vers_field_stats : public Sql_alloc { static const uint buf_size= 4 + (TIME_SECOND_PART_DIGITS + 1) / 2; uchar min_buf[buf_size]; uchar max_buf[buf_size]; Field_timestampf min_value; Field_timestampf max_value; + mysql_rwlock_t lock; public: - Stat_timestampf(const char *field_name, TABLE_SHARE *share) : + Vers_field_stats(const char *field_name, TABLE_SHARE *share) : min_value(min_buf, NULL, 0, Field::NONE, field_name, share, 6), max_value(max_buf, NULL, 0, Field::NONE, field_name, share, 6) { min_value.set_max(); memset(max_buf, 0, buf_size); + mysql_rwlock_init(key_rwlock_LOCK_vers_stats, &lock); } - void update(Field *from) + ~Vers_field_stats() { - from->update_min(&min_value, false); - from->update_max(&max_value, false); + mysql_rwlock_destroy(&lock); + } + bool update_unguarded(Field *from) + { + return + from->update_min(&min_value, false) + + from->update_max(&max_value, false); + } + bool update(Field *from) + { + mysql_rwlock_wrlock(&lock); + bool res= update_unguarded(from); + mysql_rwlock_unlock(&lock); + return res; } my_time_t min_time() { - return min_value.get_timestamp(); + mysql_rwlock_rdlock(&lock); + my_time_t res= min_value.get_timestamp(); + mysql_rwlock_unlock(&lock); + return res; } my_time_t max_time() { - return max_value.get_timestamp(); + mysql_rwlock_rdlock(&lock); + my_time_t res= max_value.get_timestamp(); + mysql_rwlock_unlock(&lock); + return res; } }; -class partition_element :public Sql_alloc { +enum stat_trx_field +{ + STAT_TRX_END= 0 +}; + +class partition_element :public Sql_alloc +{ public: List subpartitions; List list_val_list; @@ -142,6 +168,7 @@ public: bool signed_flag; // Range value signed bool max_value; // MAXVALUE range uint32 id; + bool empty; enum elem_type { @@ -151,7 +178,6 @@ public: }; elem_type type; - Stat_timestampf *stat_trx_end; partition_element() : part_max_rows(0), part_min_rows(0), range_value(0), @@ -162,10 +188,9 @@ public: nodegroup_id(UNDEF_NODEGROUP), has_null_value(FALSE), signed_flag(FALSE), max_value(FALSE), id(UINT32_MAX), - type(CONVENTIONAL), - stat_trx_end(NULL) - { - } + empty(true), + type(CONVENTIONAL) + {} partition_element(partition_element *part_elem) : part_max_rows(part_elem->part_max_rows), part_min_rows(part_elem->part_min_rows), @@ -180,11 +205,19 @@ public: nodegroup_id(part_elem->nodegroup_id), has_null_value(FALSE), id(part_elem->id), - type(part_elem->type), - stat_trx_end(NULL) + empty(part_elem->empty), + type(part_elem->type) + {} + ~partition_element() {} + + part_column_list_val& get_col_val(uint idx) { + DBUG_ASSERT(type != CONVENTIONAL); + DBUG_ASSERT(list_val_list.elements == 1); + part_elem_value *ev= static_cast(list_val_list.first_node()->info); + DBUG_ASSERT(ev && ev->col_val_array); + return ev->col_val_array[idx]; } - ~partition_element() {} }; #endif /* PARTITION_ELEMENT_INCLUDED */ diff --git a/sql/partition_info.cc b/sql/partition_info.cc index e83fced4495..f45b45548b0 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -21,6 +21,7 @@ #endif #include +#include #include "sql_priv.h" // Required to get server definitions for mysql/plugin.h right #include "sql_plugin.h" @@ -796,6 +797,7 @@ bool partition_info::vers_init_info(THD * thd) part_type= VERSIONING_PARTITION; list_of_part_fields= TRUE; column_list= TRUE; + num_columns= 1; vers_info= new (thd->mem_root) Vers_part_info; if (!vers_info) { @@ -854,8 +856,11 @@ partition_element* partition_info::vers_part_rotate(THD * thd) { DBUG_ASSERT(table && table->s); - if (table->s->free_parts.is_empty()) + DBUG_ASSERT(vers_info && vers_info->initialized()); + + if (table->s->hist_part_id >= vers_info->now_part->id - 1) { + DBUG_ASSERT(table->s->hist_part_id == vers_info->now_part->id - 1); push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, WARN_VERS_PART_FULL, @@ -864,8 +869,7 @@ partition_info::vers_part_rotate(THD * thd) return vers_info->hist_part; } - table->s->vers_part_rotate(); - DBUG_ASSERT(table->s->hist_part_id < num_parts); + table->s->hist_part_id++; const char* old_part_name= vers_info->hist_part->partition_name; vers_hist_part(); @@ -879,18 +883,100 @@ partition_info::vers_part_rotate(THD * thd) return vers_info->hist_part; } -bool partition_info::vers_setup_1(THD * thd) +bool partition_info::vers_setup_1(THD * thd, uint32 added) { DBUG_ASSERT(part_type == VERSIONING_PARTITION); + if (!table->versioned()) { my_error(ER_VERSIONING_REQUIRED, MYF(0), "`BY SYSTEM_TIME` partitioning"); return true; } - Field *sys_trx_end= table->vers_end_field(); - part_field_list.empty(); - part_field_list.push_back(const_cast(sys_trx_end->field_name), thd->mem_root); - sys_trx_end->flags|= GET_FIXED_FIELDS_FLAG; // needed in handle_list_of_fields() + + if (added) + { + DBUG_ASSERT(partitions.elements > added + 1); + Vers_field_stats** old_array= table->s->stat_trx; + table->s->stat_trx= static_cast( + alloc_root(&table->s->mem_root, sizeof(void *) * partitions.elements * num_columns)); + memcpy(table->s->stat_trx, old_array, sizeof(void *) * (partitions.elements - added) * num_columns); + } + else + { + Field *sys_trx_end= table->vers_end_field(); + part_field_list.empty(); + part_field_list.push_back(const_cast(sys_trx_end->field_name), thd->mem_root); + DBUG_ASSERT(part_field_list.elements == num_columns); + // needed in handle_list_of_fields() + sys_trx_end->flags|= GET_FIXED_FIELDS_FLAG; + } + + List_iterator it(partitions); + partition_element *el; + MYSQL_TIME t; + memset(&t, 0, sizeof(t)); + my_time_t ts= TIMESTAMP_MAX_VALUE - partitions.elements; + uint32 id= 0; + while ((el= it++)) + { + DBUG_ASSERT(el->type != partition_element::CONVENTIONAL); + ++ts; + if (added) + { + if (el->type == partition_element::VERSIONING && !el->empty) + { + ++id; + continue; + } + if (el->id == UINT32_MAX || el->type == partition_element::AS_OF_NOW) + { + DBUG_ASSERT(table && table->s); + Vers_field_stats *stat_trx_end= new (&table->s->mem_root) + Vers_field_stats(table->s->vers_end_field()->field_name, table->s); + table->s->stat_trx[id * num_columns + STAT_TRX_END]= stat_trx_end; + el->id= id++; + if (el->type == partition_element::AS_OF_NOW) + break; + goto create_col_val; + } + thd->variables.time_zone->gmt_sec_to_TIME(&t, ts); + for (uint i= 0; i < num_columns; ++i) + { + part_column_list_val &col_val= el->get_col_val(i); + static_cast(col_val.item_expression)->set_time(&t); + col_val.fixed= 0; + } + ++id; + continue; + } + + create_col_val: + curr_part_elem= el; + init_column_part(thd); + el->list_val_list.empty(); + el->list_val_list.push_back(curr_list_val, thd->mem_root); + thd->variables.time_zone->gmt_sec_to_TIME(&t, ts); + for (uint i= 0; i < num_columns; ++i) + { + part_column_list_val *col_val= add_column_value(thd); + if (el->type == partition_element::AS_OF_NOW) + { + col_val->max_value= true; + col_val->item_expression= NULL; + col_val->column_value= NULL; + col_val->part_info= this; + col_val->fixed= 1; + continue; + } + Item *item_expression= new (thd->mem_root) Item_datetime_literal(thd, &t); + /* We initialize col_val with bogus max value to make fix_partition_func() and check_range_constants() happy. + Later in vers_setup_2() it is initialized with real stat value if there will be any. */ + /* FIXME: TIME_RESULT in col_val is expensive. It should be INT_RESULT + (got to be fixed when InnoDB is supported). */ + init_col_val(col_val, item_expression); + DBUG_ASSERT(item_expression == el->get_col_val(i).item_expression); + } + } return false; } @@ -902,6 +988,8 @@ bool partition_info::vers_scan_min_max(THD *thd, partition_element *part) uint32 sub_factor= num_subparts ? num_subparts : 1; uint32 part_id= part->id * sub_factor; uint32 part_id_end= part_id + sub_factor; + DBUG_ASSERT(part->empty); + DBUG_ASSERT(table->s->stat_trx); for (; part_id < part_id_end; ++part_id) { handler *file= table->file->part_handler(part_id); @@ -913,6 +1001,8 @@ bool partition_info::vers_scan_min_max(THD *thd, partition_element *part) { while ((rc= file->ha_rnd_next(table->record[0])) != HA_ERR_END_OF_FILE) { + if (part->empty) + part->empty= false; if (thd->killed) { file->ha_rnd_end(); @@ -924,7 +1014,7 @@ bool partition_info::vers_scan_min_max(THD *thd, partition_element *part) continue; break; } - part->stat_trx_end->update(table->vers_end_field()); + vers_stat_trx(STAT_TRX_END, part).update_unguarded(table->vers_end_field()); } file->ha_rnd_end(); } @@ -939,12 +1029,49 @@ bool partition_info::vers_scan_min_max(THD *thd, partition_element *part) return false; } +void partition_info::vers_update_col_vals(THD *thd, partition_element *el0, partition_element *el1) +{ + MYSQL_TIME t; + memset(&t, 0, sizeof(t)); + DBUG_ASSERT(table && table->s && table->s->stat_trx); + DBUG_ASSERT(!el0 || el1->id == el0->id + 1); + const uint idx= el1->id * num_columns; + my_time_t ts; + part_column_list_val *col_val; + Item_datetime_literal *val_item; + Vers_field_stats *stat_trx_x; + for (uint i= 0; i < num_columns; ++i) + { + stat_trx_x= table->s->stat_trx[idx + i]; + if (el0) + { + ts= stat_trx_x->min_time(); + thd->variables.time_zone->gmt_sec_to_TIME(&t, ts); + col_val= &el0->get_col_val(i); + val_item= static_cast(col_val->item_expression); + DBUG_ASSERT(val_item); + if (val_item->set_lower(&t)) + col_val->fixed= 0; + } + col_val= &el1->get_col_val(i); + if (!col_val->max_value) + { + ts= stat_trx_x->max_time() + 1; + thd->variables.time_zone->gmt_sec_to_TIME(&t, ts); + val_item= static_cast(col_val->item_expression); + DBUG_ASSERT(val_item); + if (val_item->set_higher(&t)) + col_val->fixed= 0; + } + } +} + // setup at open stage (TABLE_SHARE is initialized) bool partition_info::vers_setup_2(THD * thd, bool is_create_table_ind) { DBUG_ASSERT(part_type == VERSIONING_PARTITION); - DBUG_ASSERT(vers_info && vers_info->initialized(is_create_table_ind) && vers_info->hist_default != UINT32_MAX); + DBUG_ASSERT(vers_info && vers_info->initialized(false)); DBUG_ASSERT(table && table->s); if (!table->versioned_by_sql()) { @@ -961,38 +1088,78 @@ bool partition_info::vers_setup_2(THD * thd, bool is_create_table_ind) { table->s->busy_rotation= true; mysql_mutex_unlock(&table->s->LOCK_rotation); + + DBUG_ASSERT(part_field_list.elements == num_columns); + + bool dont_stat= true; + bool col_val_updated= false; + if (!table->s->stat_trx) + { + DBUG_ASSERT(partitions.elements > 1); + table->s->stat_trx= static_cast( + alloc_root(&table->s->mem_root, sizeof(void *) * partitions.elements * num_columns)); + dont_stat= false; + } + // build freelist, scan min/max, assign hist_part List_iterator it(partitions); - partition_element *el; - while ((el= it++)) + partition_element *el= NULL, *prev; + while ((prev= el, el= it++)) { - DBUG_ASSERT(el->type != partition_element::CONVENTIONAL); - if (el->type == partition_element::VERSIONING) + if (el->type == partition_element::VERSIONING && dont_stat) + { + if (el->id == table->s->hist_part_id) + { + vers_info->hist_part= el; + break; + } + continue; + } + + { + Vers_field_stats *stat_trx_end= new (&table->s->mem_root) + Vers_field_stats(table->s->vers_end_field()->field_name, table->s); + table->s->stat_trx[el->id * num_columns + STAT_TRX_END]= stat_trx_end; + } + + if (!is_create_table_ind) { - DBUG_ASSERT(!el->stat_trx_end); - el->stat_trx_end= new (&table->mem_root) - Stat_timestampf(table->s->vers_end_field()->field_name, table->s); - if (!is_create_table_ind && vers_scan_min_max(thd, el)) + if (vers_scan_min_max(thd, el)) return true; + if (!el->empty) + { + vers_update_col_vals(thd, prev, el); + col_val_updated= true; + } } - if (el == vers_info->now_part || el == vers_info->hist_part) - continue; - if (!vers_info->hist_part && el->id == vers_info->hist_default) + + if (el->type == partition_element::AS_OF_NOW) + break; + + DBUG_ASSERT(el->type == partition_element::VERSIONING); + + if (vers_info->hist_part) { - vers_info->hist_part= el; + if (!el->empty) + goto set_hist_part; } - if (is_create_table_ind || ( - table->s->free_parts_init && - !vers_limit_exceed(el) && - !vers_interval_exceed(el))) + else { - table->s->free_parts.push_back((void *) el->id, &table->s->mem_root); + set_hist_part: + vers_info->hist_part= el; + continue; } + } // while + + if (!dont_stat) + { + if (col_val_updated) + table->s->stat_serial++; + + table->s->hist_part_id= vers_info->hist_part->id; + if (!is_create_table_ind && (vers_limit_exceed() || vers_interval_exceed())) + vers_part_rotate(thd); } - table->s->hist_part_id= vers_info->hist_part->id; - if (!is_create_table_ind && (vers_limit_exceed() || vers_interval_exceed())) - vers_part_rotate(thd); - table->s->free_parts_init= false; mysql_mutex_lock(&table->s->LOCK_rotation); mysql_cond_broadcast(&table->s->COND_rotation); table->s->busy_rotation= false; @@ -1184,7 +1351,7 @@ error: called for RANGE PARTITIONed tables. */ -bool partition_info::check_range_constants(THD *thd) +bool partition_info::check_range_constants(THD *thd, bool init) { partition_element* part_def; bool first= TRUE; @@ -1201,12 +1368,15 @@ bool partition_info::check_range_constants(THD *thd) part_column_list_val *UNINIT_VAR(current_largest_col_val); uint num_column_values= part_field_list.elements; uint size_entries= sizeof(part_column_list_val) * num_column_values; - range_col_array= (part_column_list_val*) thd->calloc(num_parts * - size_entries); - if (unlikely(range_col_array == NULL)) + if (init) { - mem_alloc_error(num_parts * size_entries); - goto end; + range_col_array= (part_column_list_val*) thd->calloc(num_parts * + size_entries); + if (unlikely(range_col_array == NULL)) + { + mem_alloc_error(num_parts * size_entries); + goto end; + } } loc_range_col_array= range_col_array; i= 0; @@ -1239,11 +1409,14 @@ bool partition_info::check_range_constants(THD *thd) longlong part_range_value; bool signed_flag= !part_expr->unsigned_flag; - range_int_array= (longlong*) thd->alloc(num_parts * sizeof(longlong)); - if (unlikely(range_int_array == NULL)) + if (init) { - mem_alloc_error(num_parts * sizeof(longlong)); - goto end; + range_int_array= (longlong*) thd->alloc(num_parts * sizeof(longlong)); + if (unlikely(range_int_array == NULL)) + { + mem_alloc_error(num_parts * sizeof(longlong)); + goto end; + } } i= 0; do @@ -1609,7 +1782,6 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, char *same_name; uint32 hist_parts= 0; uint32 now_parts= 0; - const char* hist_default= NULL; DBUG_ENTER("partition_info::check_partition_info"); DBUG_ASSERT(default_engine_type != partition_hton); @@ -1816,13 +1988,6 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, if (part_elem->type == partition_element::VERSIONING) { hist_parts++; - if (vers_info->hist_default == UINT32_MAX) - { - vers_info->hist_default= part_elem->id; - hist_default= part_elem->partition_name; - } - if (vers_info->hist_default == part_elem->id) - vers_info->hist_part= part_elem; } else { @@ -1861,7 +2026,7 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, if (add_or_reorg_part) { - if (unlikely((part_type == RANGE_PARTITION && + if (unlikely(((part_type == RANGE_PARTITION || part_type == VERSIONING_PARTITION) && check_range_constants(thd)) || (part_type == LIST_PARTITION && check_list_constants(thd)))) @@ -1878,14 +2043,6 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, ER_THD(thd, WARN_VERS_PARAMETERS), "no rotation condition for multiple `VERSIONING` partitions."); } - if (hist_default) - { - push_warning_printf(thd, - Sql_condition::WARN_LEVEL_WARN, - WARN_VERS_PARAMETERS, - "No `DEFAULT` for `VERSIONING` partitions. Setting `%s` as default.", - hist_default); - } } if (now_parts > 1) { diff --git a/sql/partition_info.h b/sql/partition_info.h index 844956594ff..5a671bfc50f 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -41,7 +41,7 @@ struct Vers_part_info : public Sql_alloc limit(0), now_part(NULL), hist_part(NULL), - hist_default(UINT32_MAX) + stat_serial(0) { } Vers_part_info(Vers_part_info &src) : @@ -49,7 +49,7 @@ struct Vers_part_info : public Sql_alloc limit(src.limit), now_part(NULL), hist_part(NULL), - hist_default(src.hist_default) + stat_serial(src.stat_serial) { } bool initialized(bool fully= true) @@ -71,7 +71,7 @@ struct Vers_part_info : public Sql_alloc ulonglong limit; partition_element *now_part; partition_element *hist_part; - uint32 hist_default; + ulonglong stat_serial; }; class partition_info : public Sql_alloc @@ -182,8 +182,9 @@ public: LIST_PART_ENTRY *list_array; part_column_list_val *range_col_array; part_column_list_val *list_col_array; - Vers_part_info *vers_info; }; + + Vers_part_info *vers_info; /******************************************** * INTERVAL ANALYSIS @@ -350,7 +351,7 @@ public: char *find_duplicate_field(); char *find_duplicate_name(); bool check_engine_mix(handlerton *engine_type, bool default_engine); - bool check_range_constants(THD *thd); + bool check_range_constants(THD *thd, bool init= true); bool check_list_constants(THD *thd); bool check_partition_info(THD *thd, handlerton **eng_type, handler *file, HA_CREATE_INFO *info, @@ -400,9 +401,10 @@ public: bool vers_set_interval(const INTERVAL &i); bool vers_set_limit(ulonglong limit); partition_element* vers_part_rotate(THD *thd); - bool vers_setup_1(THD *thd); + bool vers_setup_1(THD *thd, uint32 added= 0); bool vers_setup_2(THD *thd, bool is_create_table_ind); bool vers_scan_min_max(THD *thd, partition_element *part); + void vers_update_col_vals(THD *thd, partition_element *el0, partition_element *el1); partition_element *vers_hist_part() { @@ -427,6 +429,17 @@ public: DBUG_ASSERT(0); return NULL; } + partition_element *get_partition(uint part_id) + { + List_iterator it(partitions); + partition_element *el; + while ((el= it++)) + { + if (el->id == part_id) + return el; + } + return NULL; + } bool vers_limit_exceed(partition_element *part= NULL) { DBUG_ASSERT(vers_info); @@ -440,6 +453,18 @@ public: // TODO: cache thread-shared part_recs and increment on INSERT return table->file->part_recs_slow(part) >= vers_info->limit; } + Vers_field_stats& vers_stat_trx(stat_trx_field fld, uint32 part_element_id) + { + DBUG_ASSERT(table && table->s && table->s->stat_trx); + Vers_field_stats* res= table->s->stat_trx[part_element_id * num_columns + fld]; + DBUG_ASSERT(res); + return *res; + } + Vers_field_stats& vers_stat_trx(stat_trx_field fld, partition_element *part) + { + DBUG_ASSERT(part); + return vers_stat_trx(fld, part->id); + } bool vers_interval_exceed(my_time_t max_time, partition_element *part= NULL) { DBUG_ASSERT(vers_info); @@ -450,19 +475,63 @@ public: DBUG_ASSERT(vers_info->initialized()); part= vers_hist_part(); } - DBUG_ASSERT(part->stat_trx_end); - max_time-= part->stat_trx_end->min_time(); + max_time-= vers_stat_trx(STAT_TRX_END, part).min_time(); return max_time > vers_info->interval; } bool vers_interval_exceed(partition_element *part) { - DBUG_ASSERT(part->stat_trx_end); - return vers_interval_exceed(part->stat_trx_end->max_time(), part); + return vers_interval_exceed(vers_stat_trx(STAT_TRX_END, part).max_time(), part); } bool vers_interval_exceed() { return vers_interval_exceed(vers_hist_part()); } + void vers_update_stats(THD *thd, partition_element *el) + { + DBUG_ASSERT(vers_info && vers_info->initialized()); + DBUG_ASSERT(table && table->s); + DBUG_ASSERT(el && el->type == partition_element::VERSIONING); + mysql_rwlock_wrlock(&table->s->LOCK_stat_serial); + el->empty= false; + bool updated= + vers_stat_trx(STAT_TRX_END, el->id).update(table->vers_end_field()); + if (updated) + table->s->stat_serial++; + mysql_rwlock_unlock(&table->s->LOCK_stat_serial); + if (updated) + { + vers_update_col_vals(thd, + el->id > 0 ? get_partition(el->id - 1) : NULL, + el); + } + } + void vers_update_stats(THD *thd, uint part_id) + { + DBUG_ASSERT(vers_info && vers_info->initialized()); + if (part_id < vers_info->now_part->id) + vers_update_stats(thd, get_partition(part_id)); + } + void vers_update_range_constants(THD *thd) + { + DBUG_ASSERT(vers_info && vers_info->initialized()); + DBUG_ASSERT(table && table->s); + + mysql_rwlock_rdlock(&table->s->LOCK_stat_serial); + if (vers_info->stat_serial == table->s->stat_serial) + { + mysql_rwlock_unlock(&table->s->LOCK_stat_serial); + return; + } + + for (uint i= 0; i < num_columns; ++i) + { + Field *f= part_field_array[i]; + bitmap_set_bit(f->table->write_set, f->field_index); + } + check_range_constants(thd, false); + vers_info->stat_serial= table->s->stat_serial; + mysql_rwlock_unlock(&table->s->LOCK_stat_serial); + } }; uint32 get_next_partition_id_range(struct st_partition_iter* part_iter); diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 816cd374e67..b358fe3386e 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -1716,6 +1716,8 @@ bool fix_partition_func(THD *thd, TABLE *table, else if (part_info->part_type == VERSIONING_PARTITION) { error_str= partition_keywords[PKW_SYSTEM_TIME].str; + if (unlikely(part_info->check_range_constants(thd))) + goto end; } else { @@ -2396,9 +2398,6 @@ static int add_partition_values(File fptr, partition_info *part_info, break; case partition_element::VERSIONING: err+= add_string(fptr, " VERSIONING"); - DBUG_ASSERT(part_info->vers_info); - if (part_info->vers_info->hist_default == p_elem->id) - err+= add_string(fptr, " DEFAULT"); break; default: DBUG_ASSERT(0 && "wrong p_elem->type"); @@ -3423,7 +3422,8 @@ int vers_get_partition_id(partition_info *part_info, longlong *func_value) { DBUG_ENTER("vers_get_partition_id"); - Field *sys_trx_end= part_info->part_field_array[0]; + DBUG_ASSERT(part_info); + Field *sys_trx_end= part_info->part_field_array[STAT_TRX_END]; DBUG_ASSERT(sys_trx_end); DBUG_ASSERT(part_info->table); Vers_part_info *vers_info= part_info->vers_info; @@ -3438,7 +3438,6 @@ int vers_get_partition_id(partition_info *part_info, } else // row is historical { - partition_element *part= vers_info->hist_part; THD *thd= current_thd; TABLE *table= part_info->table; @@ -3461,18 +3460,13 @@ int vers_get_partition_id(partition_info *part_info, mysql_mutex_unlock(&table->s->LOCK_rotation); if (part_info->vers_limit_exceed() || part_info->vers_interval_exceed(sys_trx_end->get_timestamp())) { - part= part_info->vers_part_rotate(thd); + part_info->vers_part_rotate(thd); } mysql_mutex_lock(&table->s->LOCK_rotation); mysql_cond_broadcast(&table->s->COND_rotation); table->s->busy_rotation= false; } mysql_mutex_unlock(&table->s->LOCK_rotation); - if (vers_info->interval) - { - DBUG_ASSERT(part->stat_trx_end); - part->stat_trx_end->update(sys_trx_end); - } break; default: ; @@ -5295,6 +5289,21 @@ that are reorganised. partition configuration is made. */ { + partition_element *now_part= NULL; + if (tab_part_info->part_type == VERSIONING_PARTITION) + { + List_iterator it(tab_part_info->partitions); + partition_element *el; + while ((el= it++)) + { + if (el->type == partition_element::AS_OF_NOW) + { + DBUG_ASSERT(tab_part_info->vers_info && el == tab_part_info->vers_info->now_part); + it.remove(); + now_part= el; + } + } + } List_iterator alt_it(alt_part_info->partitions); uint part_count= 0; do @@ -5309,6 +5318,15 @@ that are reorganised. } } while (++part_count < num_new_partitions); tab_part_info->num_parts+= num_new_partitions; + if (tab_part_info->part_type == VERSIONING_PARTITION) + { + DBUG_ASSERT(now_part); + if (tab_part_info->partitions.push_back(now_part, thd->mem_root)) + { + mem_alloc_error(1); + goto err; + } + } } /* If we specify partitions explicitly we don't use defaults anymore. @@ -5697,6 +5715,12 @@ the generated partition syntax in a correct manner. tab_part_info->use_default_subpartitions= FALSE; tab_part_info->use_default_num_subpartitions= FALSE; } + + if (alter_info->flags & Alter_info::ALTER_ADD_PARTITION && + tab_part_info->part_type == VERSIONING_PARTITION && + tab_part_info->vers_setup_1(thd, alt_part_info->partitions.elements)) + goto err; + if (tab_part_info->check_partition_info(thd, (handlerton**)NULL, table->file, 0, TRUE)) { @@ -7548,6 +7572,7 @@ static void set_up_range_analysis_info(partition_info *part_info) switch (part_info->part_type) { case RANGE_PARTITION: case LIST_PARTITION: + case VERSIONING_PARTITION: if (!part_info->column_list) { if (part_info->part_expr->get_monotonicity_info() != NON_MONOTONIC) @@ -7848,7 +7873,7 @@ int get_part_iter_for_interval_cols_via_map(partition_info *part_info, uint full_length= 0; DBUG_ENTER("get_part_iter_for_interval_cols_via_map"); - if (part_info->part_type == RANGE_PARTITION) + if (part_info->part_type == RANGE_PARTITION || part_info->part_type == VERSIONING_PARTITION) { get_col_endpoint= get_partition_id_cols_range_for_endpoint; part_iter->get_next= get_next_partition_id_range; @@ -7894,7 +7919,7 @@ int get_part_iter_for_interval_cols_via_map(partition_info *part_info, } if (flags & NO_MAX_RANGE) { - if (part_info->part_type == RANGE_PARTITION) + if (part_info->part_type == RANGE_PARTITION || part_info->part_type == VERSIONING_PARTITION) part_iter->part_nums.end= part_info->num_parts; else /* LIST_PARTITION */ { diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 2f1346eeb40..f66c79a52ca 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5197,6 +5197,7 @@ opt_part_values: { LEX *lex= Lex; partition_info *part_info= lex->part_info; + partition_element *elem= part_info->curr_part_elem; if (! lex->is_partition_management()) { if (part_info->part_type != VERSIONING_PARTITION) @@ -5205,17 +5206,22 @@ opt_part_values: } else { - part_info->vers_init_info(thd); + // FIXME: other ALTER commands? + my_yyabort_error((ER_VERS_WRONG_PARAMS, MYF(0), "BY SYSTEM_TIME", "AS OF NOW partition can not be added")); } - partition_element *elem= part_info->curr_part_elem; elem->type= partition_element::AS_OF_NOW; DBUG_ASSERT(part_info->vers_info); part_info->vers_info->now_part= elem; + if (part_info->init_column_part(thd)) + { + MYSQL_YYABORT; + } } | VERSIONING_SYM { LEX *lex= Lex; partition_info *part_info= lex->part_info; + partition_element *elem= part_info->curr_part_elem; if (! lex->is_partition_management()) { if (part_info->part_type != VERSIONING_PARTITION) @@ -5225,10 +5231,17 @@ opt_part_values: else { part_info->vers_init_info(thd); + elem->id= UINT32_MAX; + } + DBUG_ASSERT(part_info->vers_info); + if (part_info->vers_info->now_part) + my_yyabort_error((ER_VERS_WRONG_PARAMS, MYF(0), "BY SYSTEM_TIME", "AS OF NOW partition is not last")); + elem->type= partition_element::VERSIONING; + if (part_info->init_column_part(thd)) + { + MYSQL_YYABORT; } - part_info->curr_part_elem->type= partition_element::VERSIONING; } - opt_default_hist_part | DEFAULT { LEX *lex= Lex; @@ -5556,20 +5569,6 @@ opt_versioning_limit: } ; -opt_default_hist_part: - /* empty */ {} - | DEFAULT - { - partition_info *part_info= Lex->part_info; - DBUG_ASSERT(part_info && part_info->vers_info && part_info->curr_part_elem); - if (part_info->vers_info->hist_part) - my_yyabort_error((ER_VERS_WRONG_PARAMS, MYF(0), - "BY SYSTEM_TIME", "multiple `DEFAULT` partitions")); - part_info->vers_info->hist_part= part_info->curr_part_elem; - part_info->vers_info->hist_default= part_info->curr_part_elem->id; - } - ; - /* End of partition parser part */ diff --git a/sql/table.cc b/sql/table.cc index 4b7d5ef0d6f..354658ba476 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -3226,6 +3226,7 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, } #ifdef WITH_PARTITION_STORAGE_ENGINE + bool work_part_info_used; if (share->partition_info_str_len && outparam->file) { /* @@ -3246,7 +3247,6 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, thd->set_n_backup_active_arena(&part_func_arena, &backup_arena); thd->stmt_arena= &part_func_arena; bool tmp; - bool work_part_info_used; tmp= mysql_unpack_partition(thd, share->partition_info_str, share->partition_info_str_len, @@ -3412,12 +3412,32 @@ partititon_err: #ifdef WITH_PARTITION_STORAGE_ENGINE if (outparam->part_info && - outparam->part_info->part_type == VERSIONING_PARTITION && - outparam->part_info->vers_setup_2(thd, is_create_table)) + outparam->part_info->part_type == VERSIONING_PARTITION) { - error= OPEN_FRM_OPEN_ERROR; - error_reported= true; - goto err; + Query_arena *backup_stmt_arena_ptr= thd->stmt_arena; + Query_arena backup_arena; + Query_arena part_func_arena(&outparam->mem_root, + Query_arena::STMT_INITIALIZED); + if (!work_part_info_used) + { + thd->set_n_backup_active_arena(&part_func_arena, &backup_arena); + thd->stmt_arena= &part_func_arena; + } + + bool err= outparam->part_info->vers_setup_2(thd, is_create_table); + + if (!work_part_info_used) + { + thd->stmt_arena= backup_stmt_arena_ptr; + thd->restore_active_arena(&part_func_arena, &backup_arena); + } + + if (err) + { + error= OPEN_FRM_OPEN_ERROR; + error_reported= true; + goto err; + } } #endif diff --git a/sql/table.h b/sql/table.h index cb24d211261..402b2548873 100644 --- a/sql/table.h +++ b/sql/table.h @@ -561,6 +561,8 @@ struct TABLE_STATISTICS_CB bool histograms_are_read; }; +class Vers_field_stats; + #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif @@ -752,26 +754,30 @@ struct TABLE_SHARE uint16 row_start_field; uint16 row_end_field; uint32 hist_part_id; - List free_parts; - bool free_parts_init; + Vers_field_stats** stat_trx; + ulonglong stat_serial; // guards check_range_constants() updates + bool busy_rotation; mysql_mutex_t LOCK_rotation; mysql_cond_t COND_rotation; + mysql_rwlock_t LOCK_stat_serial; void vers_init() { hist_part_id= UINT32_MAX; busy_rotation= false; - free_parts.empty(); - free_parts_init= true; + stat_trx= NULL; + stat_serial= 0; mysql_mutex_init(key_TABLE_SHARE_LOCK_rotation, &LOCK_rotation, MY_MUTEX_INIT_FAST); mysql_cond_init(key_TABLE_SHARE_COND_rotation, &COND_rotation, NULL); + mysql_rwlock_init(key_rwlock_LOCK_stat_serial, &LOCK_stat_serial); } void vers_destroy() { mysql_mutex_destroy(&LOCK_rotation); mysql_cond_destroy(&COND_rotation); + mysql_rwlock_destroy(&LOCK_stat_serial); } Field *vers_start_field() @@ -784,12 +790,6 @@ struct TABLE_SHARE return field[row_end_field]; } - void vers_part_rotate() - { - DBUG_ASSERT(!free_parts.is_empty()); - hist_part_id= (ulong)(void *)(free_parts.pop()); - } - void vers_wait_rotation() { while (busy_rotation) -- cgit v1.2.1 From 8378ddad2d6249712f5c59ff350d2f1ae4a2d7fd Mon Sep 17 00:00:00 2001 From: kevg Date: Thu, 19 Jan 2017 23:09:47 +0300 Subject: Tests: disable tests failing in 10.3 --- mysql-test/suite/archive/disabled.def | 12 ++++++++++++ storage/connect/mysql-test/connect/disabled.def | 4 ++++ storage/tokudb/mysql-test/tokudb/disabled.def | 7 ++++++- storage/tokudb/mysql-test/tokudb_bugs/disabled.def | 7 +++++++ 4 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/archive/disabled.def diff --git a/mysql-test/suite/archive/disabled.def b/mysql-test/suite/archive/disabled.def new file mode 100644 index 00000000000..1aeb519e763 --- /dev/null +++ b/mysql-test/suite/archive/disabled.def @@ -0,0 +1,12 @@ +############################################################################## +# +# List the test cases that are to be disabled temporarily. +# +# Separate the test case name and the comment with ':'. +# +# : BUG# +# +# Do not use any TAB characters for whitespace. +# +############################################################################## +archive-big: versioning branch \ No newline at end of file diff --git a/storage/connect/mysql-test/connect/disabled.def b/storage/connect/mysql-test/connect/disabled.def index 0e5a5fc64e3..c5cd5402a16 100644 --- a/storage/connect/mysql-test/connect/disabled.def +++ b/storage/connect/mysql-test/connect/disabled.def @@ -16,3 +16,7 @@ jdbc_postgresql : Variable settings depend on machine configuration json : TABLE_TYPE = JSON conflicts with the SQL syntax json_udf : conflicts with the server JSON functions json_udf_bin : conflicts with the server JSON functions + +mrr: versioning branch +index: versioning branch +mysql_index: versioning branch \ No newline at end of file diff --git a/storage/tokudb/mysql-test/tokudb/disabled.def b/storage/tokudb/mysql-test/tokudb/disabled.def index 1f5ed441254..0a62e8b136c 100644 --- a/storage/tokudb/mysql-test/tokudb/disabled.def +++ b/storage/tokudb/mysql-test/tokudb/disabled.def @@ -31,4 +31,9 @@ i_s_tokudb_locks_released: unstable, race conditions row_format: n/a rows-32m-rand-insert: versioning branch -rows-32m-seq-insert: versioning branch \ No newline at end of file +rows-32m-seq-insert: versioning branch +background_job_manager: versioning branch +i_s_tokudb_lock_waits_timeout: versioning branch +i_s_tokudb_locks: versioning branch +i_s_tokudb_trx: versioning branch +card_auto_analyze_lots: versioning branch \ No newline at end of file diff --git a/storage/tokudb/mysql-test/tokudb_bugs/disabled.def b/storage/tokudb/mysql-test/tokudb_bugs/disabled.def index d0d1a47e006..a9d35d5f751 100644 --- a/storage/tokudb/mysql-test/tokudb_bugs/disabled.def +++ b/storage/tokudb/mysql-test/tokudb_bugs/disabled.def @@ -1,2 +1,9 @@ 5585: times out, too many huge insert...selects db233: different execution path in mariadb, debug_sync point is not hit + +db397_insert_trigger: versioning branch +db397_delete_trigger: versioning branch +db397_update_trigger: versioning branch +db938: versioning branch +tokudb718: versioning branch +db945: versioning branch \ No newline at end of file -- cgit v1.2.1 From daa9bc8bdf02af7b0fe35c56b6d2a28ac928d119 Mon Sep 17 00:00:00 2001 From: kevg Date: Sat, 21 Jan 2017 18:19:46 +0300 Subject: Scripts: by default test versioning too --- mysql-test/mysql-test-run.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 05169b23531..04203a2a84f 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -197,6 +197,7 @@ my @DEFAULT_SUITES= qw( sql_sequence- unit- vcol- + versioning- wsrep- ); my $opt_suites; -- cgit v1.2.1 From 8be01458a388ab75a58294540bef6f3d49a284a5 Mon Sep 17 00:00:00 2001 From: kevg Date: Sat, 21 Jan 2017 19:34:06 +0300 Subject: Scripts: try to fix Travis --- .travis.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 311c45fabbe..103f5bd73be 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,7 @@ env: - GCC_VERSION=4.8 - GCC_VERSION=5 - GCC_VERSION=6 + addons: apt: sources: @@ -32,10 +33,6 @@ addons: # https://github.com/travis-ci/apt-source-whitelist/pull/288 # https://github.com/travis-ci/apt-source-whitelist/pull/309 packages: # make sure these match debian/control contents - - gcc-5 - - g++-5 - - gcc-6 - - g++-6 - bison - chrpath - cmake @@ -76,7 +73,6 @@ env: # libsystemd-daemon-dev # https://github.com/travis-ci/apt-package-whitelist/issues/3882 script: - - export MYSQL_BUILD_CC=/usr/bin/gcc-${GCC_VERSION} MYSQL_BUILD_CXX=/usr/bin/g++-${GCC_VERSION} - - ${MYSQL_BUILD_CC} --version ; ${MYSQL_BUILD_CXX} --version + - ${CC} --version ; ${CXX} --version - cd "${TRAVIS_BUILD_DIR}" - "LD_PRELOAD=/usr/lib/libtcmalloc_minimal.so.4 cmake -DWITH_INNOBASE_STORAGE_ENGINE=yes $BUILD_TYPE && LD_PRELOAD=/usr/lib/libtcmalloc_minimal.so.4 make -j $(grep -c processor /proc/cpuinfo) && cd ./mysql-test && ./mtr $MTR_FLAGS --suite=versioning --force --max-test-fail=0" -- cgit v1.2.1 From 64be66b6c0328d02b205d3fda51aa1dd1492e31f Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Sun, 22 Jan 2017 15:03:13 +0300 Subject: Scripts: suppress warnings via suppress.warnings file [closes #78] --- BUILD/capture_warnings.sh | 71 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 5 deletions(-) diff --git a/BUILD/capture_warnings.sh b/BUILD/capture_warnings.sh index bb6341fd799..4eeae4e89dc 100755 --- a/BUILD/capture_warnings.sh +++ b/BUILD/capture_warnings.sh @@ -6,18 +6,79 @@ shift 2 warn_file="$warn_path/compile.warnings" suppress_file="$warn_path/suppress.warnings" +# suppress_warnings: +# +# 1. treat STDIN as sequence of warnings (w) delimited by ^~~~... lines +# +# 2. sanitize each w to matchable m: +# a. ignore 'In file included from' lines; +# b. protect BRE chars; +# c. ignore text coords (NNN:NNN); +# d. convert multiline to X-delimited single line. +# +# 3. match sanitized m against X-delimited suppress.warnings: +# if match not found print w to STDOUT. + +suppress_warnings() +{ + [ -f "$suppress_file" ] || { + cat + return + } + [ -z "$suppress_file" ] && { + cat > /dev/null + return + } + local m w from + IFS="" + while read -r l + do + w="$w$l"$'\n' + + [[ $l =~ ^"In file included from " ]] && { + from=1 + continue + } + + [[ $from && $l =~ ^[[:space:]]+"from " ]] && + continue + + unset from + + if [[ $l =~ ^[[:space:]]*\^~*$ ]] + then + cat "$suppress_file" | tr '\n' 'X' | /bin/grep -Gq "$m" || + echo "$w" + unset m w + else + # Protect BRE metacharacters \.[*^$ + l=${l//\\/\\\\} + l=${l//./\\.} + l=${l//[/\\[} + l=${l//-/\\-} + l=${l//\*/\\*} + l=${l//^/\\^} + l=${l//\$/\\\$} + # replace text coords line:char with BRE wildcard + [[ $l =~ ^(.*:)[[:digit:]]+:[[:digit:]]+(.*)$ ]] && + l=${BASH_REMATCH[1]}[[:digit:]]\\+:[[:digit:]]\\+${BASH_REMATCH[2]} + m="$m$l"$'X' + fi + done +} + exec 3>&1 -cmderr=$("$@" 2>&1 1>&3) || { - error=$? +cmderr=$("$@" 2>&1 1>&3 | suppress_warnings) || { + error=${PIPESTATUS} echo "$cmderr" >&2 exit $error } if [[ -n "$cmderr" ]]; then - [[ "$warn_mode" != "late" ]] && + [[ "$warn_mode" != "late" || "$cmderr" =~ error: ]] && echo "$cmderr" >&2 - [[ "$warn_mode" != "early" && "$cmderr" =~ warning:(.+)$ ]] && - echo -n "$cmderr" >> "$warn_file" + [[ "$warn_mode" != "early" && "$cmderr" =~ (warning|note): ]] && + echo "$cmderr" >> "$warn_file" fi true -- cgit v1.2.1 From 94f83b262d7405c2259984be819d479362b289d4 Mon Sep 17 00:00:00 2001 From: kevg Date: Sat, 21 Jan 2017 16:38:57 +0300 Subject: SQL: fix assertion failure in parser [closes #119] --- sql/sql_lex.cc | 13 ------------- sql/sql_yacc.yy | 27 ++++++++++++++++----------- 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 75a4c3bbc0c..5260e81ff8b 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1368,19 +1368,6 @@ int MYSQLlex(YYSTYPE *yylval, THD *thd) return FOR_SYM; } break; - case QUERY_SYM: - token= lex_one_token(yylval, thd); - lip->add_digest_token(token, yylval); - switch(token) { - case FOR_SYM: - return QUERY_FOR_SYM; - default: - lip->lookahead_yylval= lip->yylval; - lip->yylval= NULL; - lip->lookahead_token= token; - return QUERY_SYM; - } - break; default: break; } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index f66c79a52ca..7a17b90a191 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -861,10 +861,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %parse-param { THD *thd } %lex-param { THD *thd } /* - Currently there are 103 shift/reduce conflicts. + Currently there are 106 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 103 +%expect 106 /* Comments for TOKENS. @@ -1353,7 +1353,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token PURGE %token QUARTER_SYM %token QUERY_SYM -%token QUERY_FOR_SYM /* INTERNAL */ %token QUICK %token RAISE_SYM /* Oracle-PLSQL-R */ %token RANGE_SYM /* SQL-2003-R */ @@ -8813,7 +8812,7 @@ trans_or_timestamp: opt_query_for_system_time_clause: /* empty */ {} - | QUERY_FOR_SYM SYSTEM_TIME_SYM for_system_time_expr + | QUERY_SYM FOR_SYSTEM_TIME_SYM for_system_time_expr { DBUG_ASSERT(Select); Select->vers_conditions= Lex->vers_conditions; @@ -11690,15 +11689,21 @@ date_time_type: | TIMESTAMP {$$=MYSQL_TIMESTAMP_DATETIME;} ; -table_alias: - /* empty */ - | AS - | '=' - ; - opt_table_alias: /* empty */ { $$=0; } - | table_alias ident + | ident + { + $$= (LEX_STRING*) thd->memdup(&$1,sizeof(LEX_STRING)); + if ($$ == NULL) + MYSQL_YYABORT; + } + | AS ident + { + $$= (LEX_STRING*) thd->memdup(&$2,sizeof(LEX_STRING)); + if ($$ == NULL) + MYSQL_YYABORT; + } + | '=' ident { $$= (LEX_STRING*) thd->memdup(&$2,sizeof(LEX_STRING)); if ($$ == NULL) -- cgit v1.2.1 From e7ac369a72f6b564aeb607e376411d25cb149e25 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Thu, 2 Feb 2017 16:21:06 +0300 Subject: Scripts: print_warnings deps fix --- cmake/print_warnings.cmake | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/cmake/print_warnings.cmake b/cmake/print_warnings.cmake index 2d4bd39a332..0991ceef7fb 100644 --- a/cmake/print_warnings.cmake +++ b/cmake/print_warnings.cmake @@ -21,5 +21,17 @@ ADD_CUSTOM_TARGET(rm_compile.warnings ALL WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) ADD_CUSTOM_TARGET(print_warnings ALL COMMAND bash -c '[ -f compile.warnings ] && { echo "Warnings found:" \; cat compile.warnings \; echo "" \; } \; true' - DEPENDS mysql udf_example rm_compile.warnings + DEPENDS mysqld rm_compile.warnings WORKING_DIRECTORY "${CMAKE_BINARY_DIR}") + +IF(TARGET explain_filename-t) + ADD_DEPENDENCIES(print_warnings explain_filename-t) +ENDIF() + +IF(TARGET mysql_client_test) + ADD_DEPENDENCIES(print_warnings mysql_client_test) +ENDIF() + +IF(TARGET udf_example) + ADD_DEPENDENCIES(print_warnings udf_example) +ENDIF() -- cgit v1.2.1 From 5853266fab57fa695403f260fed97257bc31f13b Mon Sep 17 00:00:00 2001 From: kevg Date: Wed, 8 Feb 2017 21:54:13 +0300 Subject: Style: condition rewrite --- sql/sql_delete.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 7d59d5164e1..27e112c3285 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -607,9 +607,12 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, if (table->versioned()) { bool row_is_alive= table->vers_end_field()->is_max(); - if (truncate_history && row_is_alive) - continue; - if (!truncate_history && !row_is_alive) + if (truncate_history) + { + if (row_is_alive) + continue; + } + else if (!row_is_alive) continue; } -- cgit v1.2.1 From 7aa3ebdd189c1ba5b8556959839362514190dbd1 Mon Sep 17 00:00:00 2001 From: kevg Date: Tue, 31 Jan 2017 22:41:38 +0300 Subject: SQL, Tests: FOR SYSTEM_TIME for VIEWs [closes #98] --- mysql-test/suite/versioning/r/insert.result | 29 --------- mysql-test/suite/versioning/r/view.result | 93 ++++++++++++++++++++++++++++- mysql-test/suite/versioning/t/insert.test | 14 ----- mysql-test/suite/versioning/t/view.test | 54 ++++++++++++++++- sql/sql_base.cc | 13 ++++ sql/sql_select.cc | 48 +++++++++++---- sql/sql_view.cc | 45 ++++++++++++-- sql/table.h | 4 -- 8 files changed, 231 insertions(+), 69 deletions(-) diff --git a/mysql-test/suite/versioning/r/insert.result b/mysql-test/suite/versioning/r/insert.result index 8527f763c4e..cd89083480a 100644 --- a/mysql-test/suite/versioning/r/insert.result +++ b/mysql-test/suite/versioning/r/insert.result @@ -76,16 +76,12 @@ set @str= concat(' engine ', engine); prepare stmt from @str; execute stmt; drop prepare stmt; create view vt1_1 as select x, y from t1; -create view vt1_2 as select x, y, sys_end from t1; insert into t1(x, y) values(8001, 9001); insert into vt1_1(x, y) values(1001, 2001); insert into vt1_1 values(1002, 2002); -insert into vt1_2(x, y) values(3001, 4001); set @str= concat('select x, y, ', fields, ' from t1'); prepare stmt from @str; execute stmt; drop prepare stmt; select x, y from vt1_1; -set @str= concat('select x, y, ', fields, ' from vt1_2'); -prepare stmt from @str; execute stmt; drop prepare stmt; end~~ create procedure test_04( sys_type varchar(255), @@ -176,47 +172,23 @@ x y sys_end 8001 9001 2038-01-19 03:14:07.000000 1001 2001 2038-01-19 03:14:07.000000 1002 2002 2038-01-19 03:14:07.000000 -3001 4001 2038-01-19 03:14:07.000000 x y 8001 9001 1001 2001 1002 2002 -3001 4001 -x y sys_end -8001 9001 2038-01-19 03:14:07.000000 -1001 2001 2038-01-19 03:14:07.000000 -1002 2002 2038-01-19 03:14:07.000000 -3001 4001 2038-01-19 03:14:07.000000 -insert into t1(x, y, sys_end) values(8001, 9001, '2015-1-1 1:1:1'); -ERROR HY000: System field `sys_end` is read-only -insert into vt1_2 values(3002, 4002, '2015-2-2 2:2:2'); -ERROR HY000: System field `sys_end` is read-only drop table t1; drop view vt1_1; -drop view vt1_2; call test_03('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); x y vtq_commit_ts(sys_end) 8001 9001 2038-01-19 03:14:07.000000 1001 2001 2038-01-19 03:14:07.000000 1002 2002 2038-01-19 03:14:07.000000 -3001 4001 2038-01-19 03:14:07.000000 x y 8001 9001 1001 2001 1002 2002 -3001 4001 -x y vtq_commit_ts(sys_end) -8001 9001 2038-01-19 03:14:07.000000 -1001 2001 2038-01-19 03:14:07.000000 -1002 2002 2038-01-19 03:14:07.000000 -3001 4001 2038-01-19 03:14:07.000000 -insert into t1(x, y, sys_end) values(8001, 9001, 1111111); -ERROR HY000: System field `sys_end` is read-only -insert into vt1_2 values(3002, 4002, 2222222); -ERROR HY000: System field `sys_end` is read-only drop table t1; drop view vt1_1; -drop view vt1_2; call test_04('timestamp(6)', 'myisam', 'sys_end'); id a b 1 1 1 @@ -304,7 +276,6 @@ No A B C D 13 1 1 1 1 14 1 1 1 1 15 1 1 1 1 -16 1 1 1 1 create table t1( x int unsigned, sys_start bigint unsigned generated always as row start, diff --git a/mysql-test/suite/versioning/r/view.result b/mysql-test/suite/versioning/r/view.result index 5fa59b23c47..0406f47cf3b 100644 --- a/mysql-test/suite/versioning/r/view.result +++ b/mysql-test/suite/versioning/r/view.result @@ -12,10 +12,10 @@ set @vt2= concat("create view vt2 as select * from t1 for system_time as of time prepare stmt from @vt2; execute stmt; drop prepare stmt; -select * from vt1; +select * from vt1 for system_time all; x 1 -select * from vt2; +select * from vt2 for system_time all; x 2 select * from t1; @@ -23,7 +23,94 @@ x create or replace view vt1 as select * from t1; show create view vt1; View Create View character_set_client collation_connection -vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`x` AS `x` from `t1` where `t1`.`sys_trx_end` = 18446744073709551615 query for system_time all latin1 latin1_swedish_ci +vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`x` AS `x`,`t1`.`sys_trx_start` AS `sys_trx_start`,`t1`.`sys_trx_end` AS `sys_trx_end` from `t1` FOR SYSTEM_TIME ALL where `t1`.`sys_trx_end` = 18446744073709551615 latin1 latin1_swedish_ci drop view vt1; drop view vt2; +create view vt1 as select * from t1 for system_time all; +select * from vt1 for system_time all; +x +2 +1 +prepare stmt from 'select * from vt1 for system_time all'; +execute stmt; +x +2 +1 +drop prepare stmt; +select * from vt1; +x +2 +1 +prepare stmt from 'select * from vt1'; +execute stmt; +x +drop prepare stmt; +select * from t1 for system_time as of timestamp @t1; +x +1 +select * from vt1 for system_time as of timestamp @t1; +x +2 +1 +prepare stmt from 'select * from vt1 for system_time as of timestamp @t1'; +execute stmt; +x +drop prepare stmt; +create or replace view vt1 as select * from t1; +select * from vt1 for system_time all; +x +prepare stmt from 'select * from vt1 for system_time all'; +execute stmt; +x +drop prepare stmt; +insert into vt1 values (3); +select * from t1; +x +3 +select * from vt1; +x +3 +select * from t1 for system_time all; +x +2 +1 +3 +select * from vt1 for system_time all; +x +3 +create view error_view as select *, sys_trx_start from t1; +ERROR 42S21: Duplicate column name 'sys_trx_start' +create view error_view as select *, sys_trx_end from t1; +ERROR 42S21: Duplicate column name 'sys_trx_end' +create or replace table t1 (x int) with system versioning; +insert into t1 values (1), (2); +set @t1=now(6); +delete from t1 where x=2; +set @t2=now(6); +delete from t1 where x=1; +set @t3=now(6); +set @tmp= concat("create or replace view vt1 as select * from t1 for system_time as of timestamp '", @t1, "'"); +prepare stmt from @tmp; +execute stmt; +drop prepare stmt; +set @tmp= concat("create or replace view vvt1 as select * from vt1 for system_time as of timestamp '", @t2, "'"); +prepare stmt from @tmp; +execute stmt; +drop prepare stmt; +set @tmp= concat("create or replace view vvvt1 as select * from vvt1 for system_time as of timestamp '", @t3, "'"); +prepare stmt from @tmp; +execute stmt; +drop prepare stmt; +select * from vt1 for system_time all; +x +1 +2 +select * from vvt1 for system_time all; +x +1 +select * from vvvt1 for system_time all; +x +drop view vvvt1; +drop view vvt1; +drop view vt1; drop table t1; diff --git a/mysql-test/suite/versioning/t/insert.test b/mysql-test/suite/versioning/t/insert.test index 6b9ebeef708..2ed44d3ec98 100644 --- a/mysql-test/suite/versioning/t/insert.test +++ b/mysql-test/suite/versioning/t/insert.test @@ -64,16 +64,12 @@ begin engine ', engine); prepare stmt from @str; execute stmt; drop prepare stmt; create view vt1_1 as select x, y from t1; - create view vt1_2 as select x, y, sys_end from t1; insert into t1(x, y) values(8001, 9001); insert into vt1_1(x, y) values(1001, 2001); insert into vt1_1 values(1002, 2002); - insert into vt1_2(x, y) values(3001, 4001); set @str= concat('select x, y, ', fields, ' from t1'); prepare stmt from @str; execute stmt; drop prepare stmt; select x, y from vt1_1; - set @str= concat('select x, y, ', fields, ' from vt1_2'); - prepare stmt from @str; execute stmt; drop prepare stmt; end~~ create procedure test_04( @@ -150,22 +146,12 @@ call test_02('timestamp(6)', 'myisam', 'sys_end'); call test_02('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); call test_03('timestamp(6)', 'myisam', 'sys_end'); ---ERROR ER_VERS_READONLY_FIELD -insert into t1(x, y, sys_end) values(8001, 9001, '2015-1-1 1:1:1'); ---ERROR ER_VERS_READONLY_FIELD -insert into vt1_2 values(3002, 4002, '2015-2-2 2:2:2'); drop table t1; drop view vt1_1; -drop view vt1_2; call test_03('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); ---ERROR ER_VERS_READONLY_FIELD -insert into t1(x, y, sys_end) values(8001, 9001, 1111111); ---ERROR ER_VERS_READONLY_FIELD -insert into vt1_2 values(3002, 4002, 2222222); drop table t1; drop view vt1_1; -drop view vt1_2; call test_04('timestamp(6)', 'myisam', 'sys_end'); call test_04('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); diff --git a/mysql-test/suite/versioning/t/view.test b/mysql-test/suite/versioning/t/view.test index 445dcc1f633..1ed487fec44 100644 --- a/mysql-test/suite/versioning/t/view.test +++ b/mysql-test/suite/versioning/t/view.test @@ -15,8 +15,8 @@ prepare stmt from @vt1; execute stmt; drop prepare stmt; set @vt2= concat("create view vt2 as select * from t1 for system_time as of timestamp '", @t2, "'"); prepare stmt from @vt2; execute stmt; drop prepare stmt; -select * from vt1; -select * from vt2; +select * from vt1 for system_time all; +select * from vt2 for system_time all; select * from t1; create or replace view vt1 as select * from t1; @@ -24,5 +24,53 @@ show create view vt1; drop view vt1; drop view vt2; -drop table t1; +create view vt1 as select * from t1 for system_time all; +select * from vt1 for system_time all; +prepare stmt from 'select * from vt1 for system_time all'; execute stmt; drop prepare stmt; + +select * from vt1; +prepare stmt from 'select * from vt1'; execute stmt; drop prepare stmt; + +select * from t1 for system_time as of timestamp @t1; +select * from vt1 for system_time as of timestamp @t1; +prepare stmt from 'select * from vt1 for system_time as of timestamp @t1'; execute stmt; drop prepare stmt; + +create or replace view vt1 as select * from t1; +select * from vt1 for system_time all; +prepare stmt from 'select * from vt1 for system_time all'; execute stmt; drop prepare stmt; + +insert into vt1 values (3); +select * from t1; +select * from vt1; +select * from t1 for system_time all; +select * from vt1 for system_time all; + +--error ER_DUP_FIELDNAME +create view error_view as select *, sys_trx_start from t1; +--error ER_DUP_FIELDNAME +create view error_view as select *, sys_trx_end from t1; + +create or replace table t1 (x int) with system versioning; +insert into t1 values (1), (2); +set @t1=now(6); +delete from t1 where x=2; +set @t2=now(6); +delete from t1 where x=1; +set @t3=now(6); + +set @tmp= concat("create or replace view vt1 as select * from t1 for system_time as of timestamp '", @t1, "'"); +prepare stmt from @tmp; execute stmt; drop prepare stmt; +set @tmp= concat("create or replace view vvt1 as select * from vt1 for system_time as of timestamp '", @t2, "'"); +prepare stmt from @tmp; execute stmt; drop prepare stmt; +set @tmp= concat("create or replace view vvvt1 as select * from vvt1 for system_time as of timestamp '", @t3, "'"); +prepare stmt from @tmp; execute stmt; drop prepare stmt; + +select * from vt1 for system_time all; +select * from vvt1 for system_time all; +select * from vvvt1 for system_time all; + +drop view vvvt1; +drop view vvt1; +drop view vt1; +drop table t1; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index eb8bcf2148f..02adbb656c1 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7576,6 +7576,19 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, if (f->field->flags & HIDDEN_FLAG) continue; } + if (item->type() == Item::REF_ITEM) + { + Item *i= item; + while (i->type() == Item::REF_ITEM) + i= *((Item_ref *)i)->ref; + if (i->type() == Item::FIELD_ITEM) + { + Item_field *f= (Item_field *)i; + DBUG_ASSERT(f->field); + if (f->field->flags & HIDDEN_FLAG) + continue; + } + } /* cache the table for the Item_fields inserted by expanding stars */ if (item->type() == Item::FIELD_ITEM && tables->cacheable_table) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 2d4d603c078..c41801401e7 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -684,6 +684,11 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, DBUG_RETURN(0); } + while (tables && tables->is_view() && !thd->stmt_arena->is_stmt_prepare()) + { + tables= tables->view->select_lex.table_list.first; + } + for (table= tables; table; table= table->next_local) { if (table->table && table->table->versioned()) @@ -790,10 +795,7 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, } if (vers_conditions.type == FOR_SYSTEM_TIME_ALL) - { - vers_conditions.unwrapped= true; continue; - } } COND** dst_cond= where_expr; @@ -954,8 +956,6 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, if (arena) thd->restore_active_arena(arena, &backup); - slex->vers_conditions.unwrapped= true; - DBUG_RETURN(0); #undef newx } @@ -16728,6 +16728,8 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List &fields, List_iterator_fast li(fields); Item *item; Field **tmp_from_field=from_field; + Field *sys_trx_start= NULL; + Field *sys_trx_end= NULL; while ((item=li++)) { Item::Type type=item->type(); @@ -16843,6 +16845,20 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List &fields, goto err; // Got OOM continue; // Some kind of const item } + + if (type == Item::FIELD_ITEM) + { + Item_field *item_field= (Item_field *)item; + Field *field= item_field->field; + TABLE_SHARE *s= field->table->s; + if (s->versioned) + { + if (field->flags & VERS_SYS_START_FLAG) + sys_trx_start= new_field; + else if (field->flags & VERS_SYS_END_FLAG) + sys_trx_end= new_field; + } + } if (type == Item::SUM_FUNC_ITEM) { Item_sum *agg_item= (Item_sum *) item; @@ -16923,6 +16939,17 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List &fields, total_uneven_bit_length= 0; } } + + if (sys_trx_start && sys_trx_end) + { + sys_trx_start->flags|= VERS_SYS_START_FLAG | HIDDEN_FLAG; + sys_trx_end->flags|= VERS_SYS_END_FLAG | HIDDEN_FLAG; + share->versioned= true; + share->field= table->field; + share->row_start_field= field_count - 2; + share->row_end_field= field_count - 1; + } + DBUG_ASSERT(fieldnr == (uint) (reg_field - table->field)); DBUG_ASSERT(field_count >= (uint) (reg_field - table->field)); field_count= fieldnr; @@ -25416,6 +25443,11 @@ void TABLE_LIST::print(THD *thd, table_map eliminated_tables, String *str, append_identifier(thd, str, t_alias, strlen(t_alias)); } + if (table && table->versioned()) + { + // versioning conditions are already unwrapped to WHERE clause + str->append(" FOR SYSTEM_TIME ALL"); + } if (index_hints) { @@ -25576,12 +25608,6 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type) str->append(having_value != Item::COND_FALSE ? "1" : "0"); } - if (vers_conditions.unwrapped) - { - // versioning conditions are already unwrapped to WHERE clause - str->append(STRING_WITH_LEN(" query for system_time all ")); - } - if (order_list.elements) { str->append(STRING_WITH_LEN(" order by ")); diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 08f42e9ce70..8ee4a75e259 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -453,6 +453,26 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, goto err; } + /* Implicitly add versioning fields if needed */ + { + TABLE_LIST *tl = tables; + while (tl && tl->is_view()) + tl = tl->view->select_lex.table_list.first; + if (tl && tl->table) + { + TABLE_SHARE *s= tl->table->s; + if (s->versioned) + { + select_lex->item_list.push_back(new (thd->mem_root) Item_field( + thd, &select_lex->context, NULL, NULL, + s->vers_start_field()->field_name)); + select_lex->item_list.push_back(new (thd->mem_root) Item_field( + thd, &select_lex->context, NULL, NULL, + s->vers_end_field()->field_name)); + } + } + } + view= lex->unlink_first_table(&link_to_local); if (check_db_dir_existence(view->db)) @@ -605,14 +625,22 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, view->table_name, item->name) & VIEW_ANY_ACL); - if (fld && !fld->field->table->s->tmp_table) + if (!fld) + continue; + TABLE_SHARE *s= fld->field->table->s; + const char *field_name= fld->field->field_name; + if (s->tmp_table || + (s->versioned && + (!strcmp(field_name, s->vers_start_field()->field_name) || + !strcmp(field_name, s->vers_end_field()->field_name)))) { + continue; + } - final_priv&= fld->have_privileges; + final_priv&= fld->have_privileges; - if (~fld->have_privileges & priv) - report_item= item; - } + if (~fld->have_privileges & priv) + report_item= item; } } @@ -2027,7 +2055,14 @@ bool insert_view_fields(THD *thd, List *list, TABLE_LIST *view) { Item_field *fld; if ((fld= entry->item->field_for_view_update())) + { + TABLE_SHARE *s= fld->context->table_list->table->s; + if (s->versioned && + (!strcmp(fld->name, s->vers_start_field()->field_name) || + !strcmp(fld->name, s->vers_end_field()->field_name))) + continue; list->push_back(fld, thd->mem_root); + } else { my_error(ER_NON_INSERTABLE_TABLE, MYF(0), view->alias, "INSERT"); diff --git a/sql/table.h b/sql/table.h index 402b2548873..12e5830089d 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1864,14 +1864,11 @@ struct vers_select_conds_t vers_range_unit_t unit; Item *start, *end; - bool unwrapped; - void empty() { type= FOR_SYSTEM_TIME_UNSPECIFIED; unit= UNIT_TIMESTAMP; start= end= NULL; - unwrapped= false; } void init( @@ -1884,7 +1881,6 @@ struct vers_select_conds_t unit= u; start= s; end= e; - unwrapped= false; } }; -- cgit v1.2.1 From c9b2980c4f7277c5f36f799e8955eb5c44bdefca Mon Sep 17 00:00:00 2001 From: kevg Date: Fri, 17 Feb 2017 15:18:24 +0300 Subject: Scripts: fix Travis label in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2488f4a6d84..a8eaa1441a1 100644 --- a/README.md +++ b/README.md @@ -67,4 +67,4 @@ https://github.com/MariaDB/server Code status: ------------ -* [![tests status](https://travis-ci.org/natsys/mariadb_10.2.svg?branch=natsys%2Ftrunk)](https://travis-ci.org/natsys/mariadb_10.2) travis-ci.org (natsys/trunk) +* [![tests status](https://travis-ci.org/tempesta-tech/mariadb_10.2.svg?branch=natsys%2Ftrunk)](https://travis-ci.org/tempesta-tech/mariadb_10.2) travis-ci.org (natsys/trunk) -- cgit v1.2.1 From bcc8ba78bc89b075c169d4ab414f59922401ebeb Mon Sep 17 00:00:00 2001 From: kevg Date: Thu, 9 Feb 2017 12:01:05 +0300 Subject: SQL, Tests: versioning for nested queries and CTE [closes #74] --- .../suite/versioning/r/derived_tables.result | 129 +++++++++++++++++++++ mysql-test/suite/versioning/t/derived_tables.test | 91 +++++++++++++++ sql/item.cc | 9 +- sql/item.h | 2 + sql/sql_derived.cc | 20 ++++ sql/sql_select.cc | 28 ++++- 6 files changed, 272 insertions(+), 7 deletions(-) create mode 100644 mysql-test/suite/versioning/r/derived_tables.result create mode 100644 mysql-test/suite/versioning/t/derived_tables.test diff --git a/mysql-test/suite/versioning/r/derived_tables.result b/mysql-test/suite/versioning/r/derived_tables.result new file mode 100644 index 00000000000..638f5da665a --- /dev/null +++ b/mysql-test/suite/versioning/r/derived_tables.result @@ -0,0 +1,129 @@ +create table emp +( +emp_id int, +name varchar(127), +mgr int +) with system versioning; +insert into emp values (1, 'bill', 0), +(2, 'bill', 1), +(3, 'kate', 1); +set @ts=now(6); +delete from emp; +insert into emp values (4, 'john', 1); +with ancestors as (select * from emp) select * from ancestors; +emp_id name mgr +4 john 1 +set @tmp= "with ancestors as (select * from emp) select * from ancestors"; +prepare stmt from @tmp; +execute stmt; +emp_id name mgr +4 john 1 +drop prepare stmt; +with ancestors as (select * from emp for system_time all) select * from ancestors for system_time all; +emp_id name mgr +1 bill 0 +2 bill 1 +3 kate 1 +4 john 1 +set @tmp= "with ancestors as (select * from emp for system_time all) select * from ancestors for system_time all"; +prepare stmt from @tmp; +execute stmt; +emp_id name mgr +1 bill 0 +2 bill 1 +3 kate 1 +4 john 1 +drop prepare stmt; +with recursive ancestors as (select * from emp) select * from ancestors; +emp_id name mgr +4 john 1 +set @tmp= "with recursive ancestors as (select * from emp) select * from ancestors"; +prepare stmt from @tmp; +execute stmt; +emp_id name mgr +4 john 1 +drop prepare stmt; +select emp_id from (select emp_id from emp where sys_trx_end>'2031-1-1') as tmp; +emp_id +4 +set @tmp= "select emp_id from (select emp_id from emp where sys_trx_end>'2031-1-1') as tmp"; +prepare stmt from @tmp; +execute stmt; +emp_id +4 +drop prepare stmt; +with recursive +ancestors +as +( +select e.emp_id, e.name, e.mgr +from emp as e +where name = 'john' + union +select ee.emp_id, ee.name, ee.mgr +from emp as ee, ancestors as a +where ee.mgr = a.emp_id +) +select * from ancestors; +emp_id name mgr +4 john 1 +set @tmp= " +with recursive +ancestors +as +( + select e.emp_id, e.name, e.mgr + from emp as e + where name = 'john' + union + select ee.emp_id, ee.name, ee.mgr + from emp as ee, ancestors as a + where ee.mgr = a.emp_id +) +select * from ancestors +"; +prepare stmt from @tmp; +execute stmt; +emp_id name mgr +4 john 1 +drop prepare stmt; +with recursive +ancestors +as +( +select e.emp_id, e.name, e.mgr +from emp as e for system_time as of timestamp @ts +where name = 'bill' + union +select ee.emp_id, ee.name, ee.mgr +from emp as ee for system_time as of timestamp @ts, ancestors as a for system_time as of timestamp @ts +where ee.mgr = a.emp_id +) +select * from ancestors for system_time as of timestamp @ts; +emp_id name mgr +1 bill 0 +2 bill 1 +3 kate 1 +set @tmp= " +with recursive +ancestors +as +( + select e.emp_id, e.name, e.mgr + from emp as e for system_time as of timestamp @ts + where name = 'bill' + union + select ee.emp_id, ee.name, ee.mgr + from emp as ee for system_time as of timestamp @ts, ancestors as a for system_time as of timestamp @ts + where ee.mgr = a.emp_id +) +select * from ancestors for system_time as of timestamp @ts; +"; +prepare stmt from @tmp; +execute stmt; +emp_id name mgr +1 bill 0 +2 bill 1 +3 kate 1 +drop prepare stmt; +drop table emp; diff --git a/mysql-test/suite/versioning/t/derived_tables.test b/mysql-test/suite/versioning/t/derived_tables.test new file mode 100644 index 00000000000..e847a126ea4 --- /dev/null +++ b/mysql-test/suite/versioning/t/derived_tables.test @@ -0,0 +1,91 @@ +create table emp +( + emp_id int, + name varchar(127), + mgr int +) with system versioning; + +insert into emp values (1, 'bill', 0), + (2, 'bill', 1), + (3, 'kate', 1); +set @ts=now(6); +delete from emp; +insert into emp values (4, 'john', 1); + +with ancestors as (select * from emp) select * from ancestors; +set @tmp= "with ancestors as (select * from emp) select * from ancestors"; +prepare stmt from @tmp; execute stmt; drop prepare stmt; + +with ancestors as (select * from emp for system_time all) select * from ancestors for system_time all; +set @tmp= "with ancestors as (select * from emp for system_time all) select * from ancestors for system_time all"; +prepare stmt from @tmp; execute stmt; drop prepare stmt; + +with recursive ancestors as (select * from emp) select * from ancestors; +set @tmp= "with recursive ancestors as (select * from emp) select * from ancestors"; +prepare stmt from @tmp; execute stmt; drop prepare stmt; + +select emp_id from (select emp_id from emp where sys_trx_end>'2031-1-1') as tmp; +set @tmp= "select emp_id from (select emp_id from emp where sys_trx_end>'2031-1-1') as tmp"; +prepare stmt from @tmp; execute stmt; drop prepare stmt; + +with recursive +ancestors +as +( + select e.emp_id, e.name, e.mgr + from emp as e + where name = 'john' + union + select ee.emp_id, ee.name, ee.mgr + from emp as ee, ancestors as a + where ee.mgr = a.emp_id +) +select * from ancestors; +set @tmp= " +with recursive +ancestors +as +( + select e.emp_id, e.name, e.mgr + from emp as e + where name = 'john' + union + select ee.emp_id, ee.name, ee.mgr + from emp as ee, ancestors as a + where ee.mgr = a.emp_id +) +select * from ancestors +"; +prepare stmt from @tmp; execute stmt; drop prepare stmt; + +with recursive +ancestors +as +( + select e.emp_id, e.name, e.mgr + from emp as e for system_time as of timestamp @ts + where name = 'bill' + union + select ee.emp_id, ee.name, ee.mgr + from emp as ee for system_time as of timestamp @ts, ancestors as a for system_time as of timestamp @ts + where ee.mgr = a.emp_id +) +select * from ancestors for system_time as of timestamp @ts; +set @tmp= " +with recursive +ancestors +as +( + select e.emp_id, e.name, e.mgr + from emp as e for system_time as of timestamp @ts + where name = 'bill' + union + select ee.emp_id, ee.name, ee.mgr + from emp as ee for system_time as of timestamp @ts, ancestors as a for system_time as of timestamp @ts + where ee.mgr = a.emp_id +) +select * from ancestors for system_time as of timestamp @ts; +"; +prepare stmt from @tmp; execute stmt; drop prepare stmt; + +drop table emp; diff --git a/sql/item.cc b/sql/item.cc index 410fa32f234..80a38e4d1d2 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -10271,7 +10271,8 @@ void Item_cache_row::set_null() Item_type_holder::Item_type_holder(THD *thd, Item *item) :Item(thd, item), Type_handler_hybrid_field_type(item->real_type_handler()), - enum_set_typelib(0) + enum_set_typelib(0), + flags(0) { DBUG_ASSERT(item->fixed); maybe_null= item->maybe_null; @@ -10282,6 +10283,12 @@ Item_type_holder::Item_type_holder(THD *thd, Item *item) if (item->field_type() == MYSQL_TYPE_GEOMETRY) geometry_type= item->get_geometry_type(); #endif /* HAVE_SPATIAL */ + if (item->real_type() == Item::FIELD_ITEM) + { + Item_field *item_field= (Item_field*)item->real_item(); + flags|= + (item_field->field->flags & (VERS_SYS_START_FLAG | VERS_SYS_END_FLAG)); + } } diff --git a/sql/item.h b/sql/item.h index 357eabd72e1..f7bc1110898 100644 --- a/sql/item.h +++ b/sql/item.h @@ -5892,6 +5892,8 @@ public: Field *make_field_by_type(TABLE *table); Field::geometry_type get_geometry_type() const { return geometry_type; }; Item* get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; } + + uint flags; }; diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 827fb21edf4..43302498d57 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -713,6 +713,26 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived) cursor= cursor->next_local) cursor->outer_join|= JOIN_TYPE_OUTER; } + if ((thd->stmt_arena->is_stmt_prepare() || + !thd->stmt_arena->is_stmt_execute()) && + !derived->is_view() && sl->table_list.elements > 0) + { + TABLE_LIST *tl= sl->table_list.first; + if (tl->table && tl->table->versioned()) + { + TABLE_SHARE *s= tl->table->s; + const char *db= tl->db; + const char *alias= tl->alias; + Query_arena backup; + Query_arena *arena= thd->activate_stmt_arena_if_needed(&backup); + sl->item_list.push_back(new (thd->mem_root) Item_field( + thd, &sl->context, db, alias, s->vers_start_field()->field_name)); + sl->item_list.push_back(new (thd->mem_root) Item_field( + thd, &sl->context, db, alias, s->vers_end_field()->field_name)); + if (arena) + thd->restore_active_arena(arena, &backup); + } + } } unit->derived= derived; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c41801401e7..2ba2f2e7234 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -807,12 +807,20 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, Field *fstart= table->table->vers_start_field(); Field *fend= table->table->vers_end_field(); - DBUG_ASSERT(slex->parent_lex); - Name_resolution_context *context= slex->parent_lex->current_context(); - DBUG_ASSERT(context); - - Item *row_start= newx Item_field(thd, context, fstart); - Item *row_end= newx Item_field(thd, context, fend); + Item *row_start= NULL; + Item *row_end= NULL; + if (table->is_derived() && !table->is_recursive_with_table()) + { + row_start= newx Item_field(thd, &slex->context, NULL, NULL, + fstart->field_name); + row_end= + newx Item_field(thd, &slex->context, NULL, NULL, fend->field_name); + } + else + { + row_start= newx Item_field(thd, &slex->context, fstart); + row_end= newx Item_field(thd, &slex->context, fend); + } Item *row_end2= row_end; if (table->table->versioned_by_sql()) @@ -16859,6 +16867,14 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List &fields, sys_trx_end= new_field; } } + if (type == Item::TYPE_HOLDER) + { + Item_type_holder *ith= (Item_type_holder*)item; + if (ith->flags & VERS_SYS_START_FLAG) + sys_trx_start= new_field; + else if (ith->flags & VERS_SYS_END_FLAG) + sys_trx_end= new_field; + } if (type == Item::SUM_FUNC_ITEM) { Item_sum *agg_item= (Item_sum *) item; -- cgit v1.2.1 From fb801289f314bee6e5b1864f3ef58f8f38a59278 Mon Sep 17 00:00:00 2001 From: kevg Date: Fri, 17 Feb 2017 15:11:15 +0300 Subject: IB, Tests: ALTER with ALGORITHM=INPLACE for InnoDB [closes #87] --- mysql-test/suite/versioning/r/alter.result | 24 ++++++++++++++--- mysql-test/suite/versioning/t/alter.test | 17 +++++++----- storage/innobase/handler/handler0alter.cc | 9 ------- storage/innobase/row/row0merge.cc | 42 ++++++++++++++++++++++++++++++ 4 files changed, 73 insertions(+), 19 deletions(-) diff --git a/mysql-test/suite/versioning/r/alter.result b/mysql-test/suite/versioning/r/alter.result index d9353f957dd..7b0523d4e96 100644 --- a/mysql-test/suite/versioning/r/alter.result +++ b/mysql-test/suite/versioning/r/alter.result @@ -275,8 +275,6 @@ t CREATE TABLE `t` ( PERIOD FOR SYSTEM_TIME (`trx_start`, `trx_end`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING alter table t without system versioning; -alter table t with system versioning, algorithm=inplace; -ERROR 0A000: ALGORITHM=INPLACE is not supported for this operation. Try ALGORITHM=COPY alter table t with system versioning, algorithm=copy; show create table t; Table Create Table @@ -345,8 +343,6 @@ select * from t for system_time all; a 2 1 -alter table t without system versioning, algorithm=inplace; -ERROR 0A000: ALGORITHM=INPLACE is not supported for this operation. Try ALGORITHM=COPY alter table t without system versioning, algorithm=copy; show create table t; Table Create Table @@ -417,6 +413,26 @@ a b 2 -2 3 1 4 2 +create or replace table t (a int) engine innodb; +insert into t values (1); +alter table t with system versioning, algorithm=inplace; +select * from t for system_time all; +a +1 +update t set a=2; +select * from t for system_time all; +a +2 +1 +alter table t add column b int, algorithm=inplace; +select * from t for system_time all; +a b +2 NULL +1 NULL +alter table t without system versioning, algorithm=inplace; +select * from t; +a b +2 NULL call verify_vtq; No A B C D 1 1 1 1 1 diff --git a/mysql-test/suite/versioning/t/alter.test b/mysql-test/suite/versioning/t/alter.test index 99d200c93f0..da780f6ca55 100644 --- a/mysql-test/suite/versioning/t/alter.test +++ b/mysql-test/suite/versioning/t/alter.test @@ -134,9 +134,6 @@ alter table t show create table t; alter table t without system versioning; ---error ER_ALTER_OPERATION_NOT_SUPPORTED -alter table t with system versioning, algorithm=inplace; - alter table t with system versioning, algorithm=copy; show create table t; @@ -159,9 +156,6 @@ alter table t drop column b, algorithm=inplace; show create table t; select * from t for system_time all; ---error ER_ALTER_OPERATION_NOT_SUPPORTED -alter table t without system versioning, algorithm=inplace; - alter table t without system versioning, algorithm=copy; show create table t; @@ -197,6 +191,17 @@ select * from t for system_time all; insert into t values (4, NULL); select * from t for system_time all; +create or replace table t (a int) engine innodb; +insert into t values (1); +alter table t with system versioning, algorithm=inplace; +select * from t for system_time all; +update t set a=2; +select * from t for system_time all; +alter table t add column b int, algorithm=inplace; +select * from t for system_time all; +alter table t without system versioning, algorithm=inplace; +select * from t; + call verify_vtq; drop table t; drop procedure verify_vtq; diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 0e36bf04fde..672c3672c7c 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -588,15 +588,6 @@ ha_innobase::check_if_supported_inplace_alter( DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); } - // It looks like it's actually possible to do this INPLACE, but we - // disallow this for now. - if (ha_alter_info->create_info->vers_info - .declared_with_system_versioning || - ha_alter_info->create_info->vers_info - .declared_without_system_versioning) { - DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); - } - update_thd(); trx_assert_no_search_latch(m_prebuilt->trx); diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index 810e285da26..5f2ca6838e2 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -2301,6 +2301,48 @@ end_of_index: } } + if (DICT_TF2_FLAG_IS_SET(old_table, DICT_TF2_VERSIONED)) { + if (DICT_TF2_FLAG_IS_SET( + new_table, DICT_TF2_VERSIONED)) { + dfield_t *end = dtuple_get_nth_field( + row, new_table->vers_row_end); + byte *data = static_cast( + dfield_get_data(end)); + ut_ad(data); + if (mach_read_from_8(data) == TRX_ID_MAX) { + dfield_t *start = dtuple_get_nth_field( + row, new_table->vers_row_start); + void *data = dfield_get_data(start); + ut_ad(data); + mach_write_to_8(data, trx->id); + } + } else { + const dict_col_t *col = + &old_table->cols + [old_table->vers_row_end]; + const ulint nfield = dict_col_get_clust_pos( + col, clust_index); + ulint len = 0; + const rec_t *sys_trx_end = rec_get_nth_field( + rec, offsets, nfield, &len); + ut_ad(len == 8); + if (mach_read_from_8(sys_trx_end) != TRX_ID_MAX) + continue; + } + } else if (DICT_TF2_FLAG_IS_SET( + new_table, DICT_TF2_VERSIONED)) { + void *sys_trx_start = mem_heap_alloc(row_heap, 8); + void *sys_trx_end = mem_heap_alloc(row_heap, 8); + mach_write_to_8(sys_trx_start, trx->id); + mach_write_to_8(sys_trx_end, TRX_ID_MAX); + dfield_t *start = dtuple_get_nth_field( + row, new_table->vers_row_start); + dfield_t *end = dtuple_get_nth_field( + row, new_table->vers_row_end); + dfield_set_data(start, sys_trx_start, 8); + dfield_set_data(end, sys_trx_end, 8); + } + write_buffers: /* Build all entries for all the indexes to be created in a single scan of the clustered index. */ -- cgit v1.2.1 From fc7da4dd4f1e2b9b78b292f20d8fe61f1e9a1d11 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 20 Feb 2017 10:06:58 +0300 Subject: IB, SQL: InnoDB partitioning [closes #118] * native InnoDB partitioning for BY SYSTEM_TIME partitions. --- include/priority_queue.h | 527 +++ include/template_utils.h | 98 + mysql-test/suite/versioning/r/partition.result | 16 +- .../suite/versioning/t/partition.combinations | 10 + mysql-test/suite/versioning/t/partition.test | 11 +- sql/CMakeLists.txt | 4 +- sql/ha_partition.cc | 23 +- sql/ha_partition.h | 117 +- sql/handler.cc | 6 + sql/handler.h | 27 +- sql/partition_info.cc | 192 +- sql/partition_info.h | 49 +- sql/partitioning/partition_handler.cc | 3746 ++++++++++++++++++++ sql/partitioning/partition_handler.h | 1113 ++++++ sql/share/errmsg-utf8.txt | 9 + sql/sql_partition.cc | 142 +- sql/sql_partition.h | 34 + sql/sql_table.cc | 5 +- sql/sql_tablespace.cc | 64 + sql/sql_tablespace.h | 35 + sql/table.cc | 14 + storage/innobase/CMakeLists.txt | 2 +- storage/innobase/handler/ha_innodb.cc | 97 +- storage/innobase/handler/ha_innodb.h | 4 +- storage/innobase/handler/ha_innopart.cc | 206 +- storage/innobase/handler/ha_innopart.h | 203 +- storage/innobase/handler/handler0alter.cc | 16 +- storage/innobase/include/ha_prototypes.h | 3 +- storage/innobase/include/row0mysql.h | 15 +- storage/innobase/include/sync0policy.h | 6 +- storage/innobase/row/row0mysql.cc | 18 +- 31 files changed, 6554 insertions(+), 258 deletions(-) create mode 100644 include/priority_queue.h create mode 100644 include/template_utils.h create mode 100644 mysql-test/suite/versioning/t/partition.combinations create mode 100644 sql/partitioning/partition_handler.cc create mode 100644 sql/partitioning/partition_handler.h diff --git a/include/priority_queue.h b/include/priority_queue.h new file mode 100644 index 00000000000..1d2437f0e98 --- /dev/null +++ b/include/priority_queue.h @@ -0,0 +1,527 @@ +/* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef PRIORITY_QUEUE_INCLUDED +#define PRIORITY_QUEUE_INCLUDED + +#include "my_dbug.h" + +#include +#include +#include +#include "template_utils.h" + +#if defined(EXTRA_CODE_FOR_UNIT_TESTING) +#include +#include +#endif + +#ifndef MY_ATTRIBUTE +#if defined(__GNUC__) +# define MY_ATTRIBUTE(A) __attribute__(A) +#else +# define MY_ATTRIBUTE(A) +#endif +#endif + +namespace priority_queue_unittest { class PriorityQueueTest; }; + + +/** + Implements a priority queue using a vector-based max-heap. + + A priority queue is a container specifically designed such that its first + element is always the greatest of the elements it contains, according to + some strict weak ordering criterion. + + For object locality, the implementation is vector-based, rather than + node-based. + + The priority queue is mutable, which means that the priority of an element + can be changed. See increase/decrease/update member functions. + The typical use case is to change the value/priority of the root node. + + We provide iterators, which can be used to visit all elements. + Iterators do not visit queue elements in priority order. + Iterators should not be used to change the priority of elements. + + The underlying container must be + constructible from an iterator range, should provide const and + non-const random access iterators to access its elements, as well as + the following operations: + - size() + - empty() + - push_back() + - pop_back() + - swap() + - clear() + - capacity() + - reserve() + - max_size() + + @tparam T Type of the elements of the priority queue. + @tparam Container Type of the underlying container object where elements + are stored. Its value_type shall be T. + @tparam Less A binary predicate that takes two elements (of type T) + and returns a bool. The expression less(a,b), where + less is an object of this type and a and b are elements + in the container, shall return true if a is considered + to go before b in the strict weak ordering the + function defines. + */ +template +< + typename T, + typename Container = std::vector, + typename Less = std::less +> +class Priority_queue : public Less +{ +public: + typedef Container container_type; + typedef Less less_type; + typedef typename container_type::value_type value_type; + typedef typename container_type::size_type size_type; + typedef typename container_type::iterator iterator; + typedef typename container_type::const_iterator const_iterator; + typedef typename container_type::allocator_type allocator_type; + + friend class priority_queue_unittest::PriorityQueueTest; +private: + // Deriving from Less allows empty base-class optimization in some cases. + typedef Less Base; + + // Returns the index of the parent node of node i. + static size_type parent(size_type i) + { + DBUG_ASSERT(i != 0); + return (--i) >> 1; // (i - 1) / 2 + } + + // Returns the index of the left child of node i. + static size_type left(size_type i) + { + return (i << 1) | 1; // 2 * i + 1 + } + + // Returns the index of the right child of node i. + static size_type right(size_type i) + { + return (++i) << 1; // 2 * i + 2 + } + + void heapify(size_type i, size_type last) + { + DBUG_ASSERT(i < size()); + size_type largest = i; + + do + { + i = largest; + size_type l = left(i); + size_type r = right(i); + + if (l < last && Base::operator()(m_container[i], m_container[l])) + { + largest = l; + } + + if (r < last && Base::operator()(m_container[largest], m_container[r])) + { + largest = r; + } + + if (largest != i) + { + std::swap(m_container[i], m_container[largest]); + } + } while (largest != i); + } + + void heapify(size_type i) + { + heapify(i, m_container.size()); + } + + void reverse_heapify(size_type i) + { + DBUG_ASSERT(i < size()); + while (i > 0 && !Base::operator()(m_container[i], m_container[parent(i)])) + { + std::swap(m_container[parent(i)], m_container[i]); + i = parent(i); + } + } + + // Sets the value of element i, and rebuilds the priority queue. + void decrease_key(size_type i, value_type const &x) + { + m_container[i] = x; + heapify(i); + } + + // Sets the value of element i, and rebuilds the priority queue. + void increase_key(size_type i, value_type const &x) + { + m_container[i] = x; + reverse_heapify(i); + } + +public: + /// Constructs an empty priority queue. + Priority_queue(Less const &less = Less(), + const allocator_type& alloc = allocator_type()) + : Base(less), + m_container(alloc) + {} + + /// Constructs a heap of the objects between first and beyond. + template + Priority_queue(Input_iterator first, Input_iterator beyond, + Less const &less = Less(), + const allocator_type& alloc = allocator_type()) + : Base(less), + m_container(first, beyond, alloc) + { + build_heap(); + } + + /// Constructs a heap based on input argument. + void assign(const container_type &container) + { + m_container= container; + build_heap(); + } + + /** + Constructs a heap based on container contents. + Can also be used when many elements have changed. + */ + void build_heap() + { + if (m_container.size() > 1) + { + for (size_type i = parent(m_container.size() - 1); i > 0; --i) + { + heapify(i); + } + heapify(0); + } + } + + /// Returns a const reference to the top element of the priority queue. + value_type const &top() const + { + DBUG_ASSERT(!empty()); + return m_container[0]; + } + + /// Returns a reference to the top element of the priority queue. + value_type& top() + { + DBUG_ASSERT(!empty()); + return m_container[0]; + } + + /** + Inserts an element in the priority queue. + + @param x value to be pushed. + @retval true if out-of-memory, false otherwise. + */ + bool push(value_type const &x) + { + try + { + m_container.push_back(x); + } + catch(std::bad_alloc const &) + { + return true; + } + + reverse_heapify(m_container.size() - 1); + return false; + } + + /// Pops the top-most element in the priority queue. + void pop() + { + remove(0); + } + + /// Removes the element at position i from the priority queue. + void remove(size_type i) + { + DBUG_ASSERT(i < size()); + + if (i == m_container.size() - 1) + { + m_container.pop_back(); + return; + } + + m_container[i] = m_container[m_container.size() - 1]; + m_container.pop_back(); + heapify(i); + } + + /** + Decreases the priority of the element at position i, where the + new priority is x. + */ + void decrease(size_type i, value_type const &x) + { + DBUG_ASSERT(i < size()); + DBUG_ASSERT(!Base::operator()(m_container[i], x)); + decrease_key(i, x); + } + + /** + Increases the priority of the element at position i, where the + new priority is x. + */ + void increase(size_type i, value_type const &x) + { + DBUG_ASSERT(i < size()); + DBUG_ASSERT(!Base::operator()(x, m_container[i])); + increase_key(i, x); + } + + /** + Changes the priority of the element at position i, where the + new priority is x. + */ + void update(size_type i, value_type const &x) + { + DBUG_ASSERT(i < size()); + if (Base::operator()(x, m_container[i])) + { + decrease_key(i, x); + } + else + { + increase_key(i, x); + } + } + + /** + Assumes that the i-th element's value has increased + and rebuilds the priority queue. + */ + void increase(size_type i) + { + reverse_heapify(i); + } + + /** + Assumes that the i-th element's value has decreased + and rebuilds the priority queue. + */ + void decrease(size_type i) + { + heapify(i); + } + + /** + Assumes that the i-th element's value has changed + and rebuilds the priority queue. + */ + void update(size_type i) + { + DBUG_ASSERT(i < size()); + if (i == 0 || Base::operator()(m_container[i], m_container[parent(i)])) + { + heapify(i); + } + else + { + reverse_heapify(i); + } + } + + /** + Assumes that the top element's value has changed + and rebuilds the priority queue. + */ + void update_top() + { + DBUG_ASSERT(!empty()); + heapify(0); + } + + /// Returns the number of elements of the priority queue + size_type size() const { return m_container.size(); } + + /// Returns true if the priority queue is empty + bool empty() const { return m_container.empty(); } + + /// Returns a const reference to the i-th element in the underlying container. + value_type const& operator[](size_type i) const + { + DBUG_ASSERT(i < size()); + return m_container[i]; + } + + /// Returns a reference to the i-th element in the underlying container. + value_type& operator[](size_type i) + { + DBUG_ASSERT(i < size()); + return m_container[i]; + } + + /// Returns a const iterator to the first element of the underlying container. + const_iterator begin() const + { + return m_container.begin(); + } + + /// Returns a const iterator to the end element of the underlying container. + const_iterator end() const + { + return m_container.end(); + } + + /// Returns an iterator to the first element of the underlying container. + iterator begin() + { + return m_container.begin(); + } + + /// Returns an iterator to the end element of the underlying container. + iterator end() + { + return m_container.end(); + } + + /// Swaps the contents of two priority queues. + void swap(Priority_queue& other) + { + std::swap(static_cast(*this), static_cast(other)); + m_container.swap(other.m_container); + } + + /// Returns true if the priority queue has the heap property. + bool is_valid() const + { + for (size_type i = 1; i < m_container.size(); ++i) + { + if (Base::operator()(m_container[parent(i)], m_container[i])) + { + return false; + } + } + return true; + } + + /** + Sorts the elements of the priority queue according to the strict + partial ordering defined by the object of type Less passed to + the priority queue. + + The heap property of the priority queue is invalidated by this + operation. + */ + void sort() + { + if (!m_container.empty()) + { + for (size_type i = m_container.size() - 1; i > 0; --i) + { + std::swap(m_container[i], m_container[0]); + heapify(0, i); + } + } + } + + /// Clears the priority queue. + void clear() + { + m_container.clear(); + } + + /// Clears the priority queue, but deletes all elements first. + void delete_elements() + { + delete_container_pointers(m_container); + } + + /// Returns the capacity of the internal container. + size_type capacity() const + { + return m_container.capacity(); + } + + /** + Reserves space for array elements. + + @param n number of elements. + @retval true if out-of-memory, false otherwise. + */ + MY_ATTRIBUTE((warn_unused_result)) + bool reserve(size_type n) + { + DBUG_ASSERT(n <= m_container.max_size()); + try + { + m_container.reserve(n); + } + catch(std::bad_alloc const &) + { + return true; + } + return false; + } + +private: + container_type m_container; +}; + + +#if defined(EXTRA_CODE_FOR_UNIT_TESTING) +template +inline std::ostream& +operator<<(std::ostream& os, + Priority_queue const& pq) +{ + typedef typename Priority_queue::size_type size_type; + + for (size_type i = 0; i < pq.size(); i++) + { + os << pq[i] << " " << std::flush; + } + + return os; +} + + +template +inline std::stringstream& +operator<<(std::stringstream& ss, + Priority_queue const& pq) +{ + typedef typename Priority_queue::size_type size_type; + + for (size_type i = 0; i < pq.size(); i++) + { + ss << pq[i] << " ";; + } + + return ss; +} +#endif // EXTRA_CODE_FOR_UNIT_TESTING + + +#endif // PRIORITY_QUEUE_INCLUDED diff --git a/include/template_utils.h b/include/template_utils.h new file mode 100644 index 00000000000..7e12b11f703 --- /dev/null +++ b/include/template_utils.h @@ -0,0 +1,98 @@ +/* Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef TEMPLATE_UTILS_INCLUDED +#define TEMPLATE_UTILS_INCLUDED + +/** + Clears a container, but deletes all objects that the elements point to first. + @tparam Container of pointers. + */ +template +void delete_container_pointers(Container_type &container) +{ + typename Container_type::iterator it1= container.begin(); + typename Container_type::iterator it2= container.end(); + for (; it1 != it2; ++it1) + { + delete (*it1); + } + container.clear(); +} + +/** + Clears a container, but frees all objects that the elements point to first. + @tparam Container of pointers. + */ +template +void my_free_container_pointers(Container_type &container) +{ + typename Container_type::iterator it1= container.begin(); + typename Container_type::iterator it2= container.end(); + for (; it1 != it2; ++it1) + { + my_free(*it1); + } + container.clear(); +} + + +/** + Casts from one pointer type, to another, without using + reinterpret_cast or C-style cast: + foo *f; bar *b= pointer_cast(f); + This avoids having to do: + foo *f; bar *b= static_cast(static_cast(f)); + */ +template +inline T pointer_cast(void *p) +{ + return static_cast(p); +} + +template +inline const T pointer_cast(const void *p) +{ + return static_cast(p); +} + +/** + Casts from one pointer type to another in a type hierarchy. + In debug mode, we verify the cast is indeed legal. + */ +template +inline Target down_cast(Source arg) +{ + DBUG_ASSERT(NULL != dynamic_cast(arg)); + return static_cast(arg); +} + + +/** + Sometimes the compiler insists that types be the same and does not do any + implicit conversion. For example: + Derived1 *a; + Derived2 *b; // Derived1 and 2 are children classes of Base + Base *x= cond ? a : b; // Error, need to force a cast. + + Use: + Base *x= cond ? implicit_cast(a) : implicit_cast(b); + static_cast would work too, but would be less safe (allows any + pointer-to-pointer conversion, not only up-casts). +*/ +template +inline To implicit_cast(To x) { return x; } + +#endif // TEMPLATE_UTILS_INCLUDED diff --git a/mysql-test/suite/versioning/r/partition.result b/mysql-test/suite/versioning/r/partition.result index 104ec304883..f4c8ce3b286 100644 --- a/mysql-test/suite/versioning/r/partition.result +++ b/mysql-test/suite/versioning/r/partition.result @@ -1,6 +1,5 @@ create table t1 (x int) with system versioning -engine innodb partition by range columns (x) ( partition p0 values less than (100), partition p1 values less than (1000)); @@ -78,14 +77,14 @@ show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `x` int(11) DEFAULT NULL, - `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, - `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + `sys_trx_start` ${SYS_TRX_TYPE} GENERATED ALWAYS AS ROW START, + `sys_trx_end` ${SYS_TRX_TYPE} GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +) ENGINE=${INNODB_OR_MYISAM} DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING PARTITION BY SYSTEM_TIME -(PARTITION p0 VERSIONING ENGINE = MyISAM, - PARTITION p1 VERSIONING ENGINE = MyISAM, - PARTITION pn AS OF NOW ENGINE = MyISAM) +(PARTITION p0 VERSIONING ENGINE = ${INNODB_OR_MYISAM}, + PARTITION p1 VERSIONING ENGINE = ${INNODB_OR_MYISAM}, + PARTITION pn AS OF NOW ENGINE = ${INNODB_OR_MYISAM}) alter table t1 drop partition pn; ERROR HY000: Wrong parameters for `BY SYSTEM_TIME`: `AS OF NOW` partition can not be dropped alter table t1 drop partition p1; @@ -108,7 +107,6 @@ select * from t1 partition (pn) for system_time all; x create or replace table t1 (x int) with system versioning -engine myisam partition by system_time limit 1 ( partition p0 versioning, partition p1 versioning, @@ -137,7 +135,6 @@ x 3 create or replace table t1 (x int) with system versioning -engine myisam partition by system_time interval 1 second ( partition p0 versioning, partition p1 versioning, @@ -163,7 +160,6 @@ x 4 create or replace table t1 (x int) with system versioning -engine myisam partition by system_time limit 1 subpartition by key (x) subpartitions 2 ( diff --git a/mysql-test/suite/versioning/t/partition.combinations b/mysql-test/suite/versioning/t/partition.combinations new file mode 100644 index 00000000000..4c1c009e7be --- /dev/null +++ b/mysql-test/suite/versioning/t/partition.combinations @@ -0,0 +1,10 @@ +[innodb] +innodb +partition +default-storage-engine=innodb + +[myisam] +skip-innodb +partition +default-storage-engine=myisam + diff --git a/mysql-test/suite/versioning/t/partition.test b/mysql-test/suite/versioning/t/partition.test index 9483915c4ac..e0500284a6f 100644 --- a/mysql-test/suite/versioning/t/partition.test +++ b/mysql-test/suite/versioning/t/partition.test @@ -1,11 +1,7 @@ ---source include/have_innodb.inc ---source include/have_partition.inc - -### check InnoDB versioning and conventional partitioning +### check System Versioning and conventional partitioning create table t1 (x int) with system versioning -engine innodb partition by range columns (x) ( partition p0 values less than (100), partition p1 values less than (1000)); @@ -78,6 +74,7 @@ alter table t1 add partition ( alter table t1 add partition ( partition p1 versioning); +--replace_result InnoDB ${INNODB_OR_MYISAM} MyISAM ${INNODB_OR_MYISAM} "bigint(20) unsigned" ${SYS_TRX_TYPE} timestamp(6) ${SYS_TRX_TYPE} show create table t1; --error ER_VERS_WRONG_PARAMS @@ -99,7 +96,6 @@ select * from t1 partition (pn) for system_time all; # rotation by LIMIT create or replace table t1 (x int) with system versioning -engine myisam partition by system_time limit 1 ( partition p0 versioning, partition p1 versioning, @@ -118,7 +114,6 @@ select * from t1 partition (p1) for system_time all; # rotation by INTERVAL create or replace table t1 (x int) with system versioning -engine myisam partition by system_time interval 1 second ( partition p0 versioning, partition p1 versioning, @@ -137,7 +132,6 @@ select * from t1 partition (p1) for system_time all; # Subpartitions create or replace table t1 (x int) with system versioning -engine myisam partition by system_time limit 1 subpartition by key (x) subpartitions 2 ( @@ -156,4 +150,3 @@ select * from t1 partition (p1sp0) for system_time all; select * from t1 partition (p1sp1) for system_time all; drop table t1; - diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 1dfa313a70c..08a39b1975d 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -121,7 +121,7 @@ SET (SQL_SOURCE rpl_tblmap.cc sql_binlog.cc event_scheduler.cc event_data_objects.cc event_queue.cc event_db_repository.cc sql_tablespace.cc events.cc ../sql-common/my_user.c - partition_info.cc rpl_utility.cc rpl_injector.cc sql_locale.cc + partition_info.cc partitioning/partition_handler.cc rpl_utility.cc rpl_injector.cc sql_locale.cc rpl_rli.cc rpl_mi.cc sql_servers.cc sql_audit.cc sql_connect.cc scheduler.cc sql_partition_admin.cc sql_profile.cc event_parse_data.cc sql_alter.cc @@ -165,7 +165,7 @@ IF (CMAKE_SYSTEM_NAME MATCHES "Linux" OR ENDIF() -MYSQL_ADD_PLUGIN(partition ha_partition.cc STORAGE_ENGINE DEFAULT STATIC_ONLY +MYSQL_ADD_PLUGIN(partition ha_partition.cc partitioning/partition_handler.cc STORAGE_ENGINE DEFAULT STATIC_ONLY RECOMPILE_FOR_EMBEDDED) MYSQL_ADD_PLUGIN(sql_sequence ha_sequence.cc STORAGE_ENGINE MANDATORY STATIC_ONLY RECOMPILE_FOR_EMBEDDED) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 0fa461e1807..747b9a8871f 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -160,9 +160,6 @@ static int partition_initialize(void *p) bool Partition_share::init(uint num_parts) { DBUG_ENTER("Partition_share::init"); - mysql_mutex_init(key_partition_auto_inc_mutex, - &auto_inc_mutex, - MY_MUTEX_INIT_FAST); auto_inc_initialized= false; partition_name_hash_initialized= false; next_auto_inc_val= 0; @@ -1246,12 +1243,12 @@ int ha_partition::handle_opt_part(THD *thd, HA_CHECK_OPT *check_opt, (modelled after mi_check_print_msg) TODO: move this into the handler, or rewrite mysql_admin_table. */ -static bool print_admin_msg(THD* thd, uint len, +bool print_admin_msg(THD* thd, uint len, const char* msg_type, const char* db_name, String &table_name, const char* op_name, const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 7, 8); -static bool print_admin_msg(THD* thd, uint len, +bool print_admin_msg(THD* thd, uint len, const char* msg_type, const char* db_name, String &table_name, const char* op_name, const char *fmt, ...) @@ -5731,6 +5728,22 @@ int ha_partition::index_next_same(uchar *buf, const uchar *key, uint keylen) } +int ha_partition::index_read_last_map(uchar *buf, + const uchar *key, + key_part_map keypart_map) +{ + DBUG_ENTER("ha_partition::index_read_last_map"); + + m_ordered= true; // Safety measure + end_range= NULL; + m_index_scan_type= partition_index_read_last; + m_start_key.key= key; + m_start_key.keypart_map= keypart_map; + m_start_key.flag= HA_READ_PREFIX_LAST; + DBUG_RETURN(common_index_read(buf, true)); +} + + /* Read next record when performing index scan backwards diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 2c7f4a0861f..861ba47b94e 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -77,43 +77,118 @@ public: }; +extern PSI_mutex_key key_partition_auto_inc_mutex; + /** Partition specific Handler_share. */ class Partition_share : public Handler_share { public: - bool auto_inc_initialized; - mysql_mutex_t auto_inc_mutex; /**< protecting auto_inc val */ - ulonglong next_auto_inc_val; /**< first non reserved value */ - /** - Hash of partition names. Initialized in the first ha_partition::open() - for the table_share. After that it is read-only, i.e. no locking required. - */ - bool partition_name_hash_initialized; - HASH partition_name_hash; - /** Storage for each partitions Handler_share */ - Parts_share_refs *partitions_share_refs; - Partition_share() {} + Partition_share() + : auto_inc_initialized(false), + next_auto_inc_val(0), + partition_name_hash_initialized(false), + partitions_share_refs(NULL), + partition_names(NULL) + { + mysql_mutex_init(key_partition_auto_inc_mutex, + &auto_inc_mutex, + MY_MUTEX_INIT_FAST); + } + ~Partition_share() { - DBUG_ENTER("Partition_share::~Partition_share"); mysql_mutex_destroy(&auto_inc_mutex); + if (partition_names) + { + my_free(partition_names); + } if (partition_name_hash_initialized) + { my_hash_free(&partition_name_hash); + } if (partitions_share_refs) delete partitions_share_refs; - DBUG_VOID_RETURN; } + bool init(uint num_parts); - void lock_auto_inc() + + /** Set if auto increment is used an initialized. */ + bool auto_inc_initialized; + /** + Mutex protecting next_auto_inc_val. + Initialized if table uses auto increment. + */ + mysql_mutex_t auto_inc_mutex; + /** First non reserved auto increment value. */ + ulonglong next_auto_inc_val; + /** + Hash of partition names. Initialized by the first handler instance of a + table_share calling populate_partition_name_hash(). + After that it is read-only, i.e. no locking required for reading. + */ + HASH partition_name_hash; + /** flag that the name hash is initialized, so it only will do it once. */ + bool partition_name_hash_initialized; + + /** Storage for each partitions Handler_share */ + Parts_share_refs *partitions_share_refs; + + /** + Release reserved auto increment values not used. + @param thd Thread. + @param table_share Table Share + @param next_insert_id Next insert id (first non used auto inc value). + @param max_reserved End of reserved auto inc range. + */ + void release_auto_inc_if_possible(THD *thd, TABLE_SHARE *table_share, + const ulonglong next_insert_id, + const ulonglong max_reserved); + + /** lock mutex protecting auto increment value next_auto_inc_val. */ + inline void lock_auto_inc() { mysql_mutex_lock(&auto_inc_mutex); } - void unlock_auto_inc() + /** unlock mutex protecting auto increment value next_auto_inc_val. */ + inline void unlock_auto_inc() { mysql_mutex_unlock(&auto_inc_mutex); } + /** + Populate partition_name_hash with partition and subpartition names + from part_info. + @param part_info Partition info containing all partitions metadata. + + @return Operation status. + @retval false Success. + @retval true Failure. + */ + bool populate_partition_name_hash(partition_info *part_info); + /** Get partition name. + + @param part_id Partition id (for subpartitioned table only subpartition + names will be returned.) + + @return partition name or NULL if error. + */ + const char *get_partition_name(size_t part_id) const; +private: + const uchar **partition_names; + /** + Insert [sub]partition name into partition_name_hash + @param name Partition name. + @param part_id Partition id. + @param is_subpart True if subpartition else partition. + + @return Operation status. + @retval false Success. + @retval true Failure. + */ + bool insert_partition_name_in_hash(const char *name, + uint part_id, + bool is_subpart); }; @@ -605,6 +680,10 @@ public: virtual int index_last(uchar * buf); virtual int index_next_same(uchar * buf, const uchar * key, uint keylen); + int index_read_last_map(uchar *buf, + const uchar *key, + key_part_map keypart_map); + /* read_first_row is virtual method but is only implemented by handler.cc, no storage engine has implemented it so neither @@ -1086,7 +1165,6 @@ private: ulonglong nr= (((Field_num*) field)->unsigned_flag || field->val_int() > 0) ? field->val_int() : 0; lock_auto_increment(); - DBUG_ASSERT(part_share->auto_inc_initialized); /* must check when the mutex is taken */ if (nr >= part_share->next_auto_inc_val) part_share->next_auto_inc_val= nr + 1; @@ -1310,4 +1388,9 @@ public: friend int cmp_key_rowid_part_id(void *ptr, uchar *ref1, uchar *ref2); }; +bool print_admin_msg(THD* thd, uint len, + const char* msg_type, + const char* db_name, String &table_name, + const char* op_name, const char *fmt, ...); + #endif /* HA_PARTITION_INCLUDED */ diff --git a/sql/handler.cc b/sql/handler.cc index c19d04236d7..ba947fd7a2d 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2435,6 +2435,12 @@ LEX_STRING *handler::engine_name() } +void handler::ha_statistic_increment(ulong SSV::*offset) const +{ + (table->in_use->status_var.*offset)++; +} + + double handler::keyread_time(uint index, uint ranges, ha_rows rows) { /* diff --git a/sql/handler.h b/sql/handler.h index e20f95df1f3..f5e3d83d8d9 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1393,6 +1393,7 @@ struct handlerton bool (*vers_query_trx_id)(THD* thd, void *out, ulonglong trx_id, vtq_field_t field); bool (*vers_query_commit_ts)(THD* thd, void *out, const MYSQL_TIME &commit_ts, vtq_field_t field, bool backwards); bool (*vers_trx_sees)(THD *thd, bool &result, ulonglong trx_id1, ulonglong trx_id0, ulonglong commit_id1, uchar iso_level1, ulonglong commit_id0); + handler *(*vers_upgrade_handler)(handler *hnd, MEM_ROOT *mem_root); }; @@ -3271,6 +3272,18 @@ protected: virtual int index_last(uchar * buf) { return HA_ERR_WRONG_COMMAND; } virtual int index_next_same(uchar *buf, const uchar *key, uint keylen); + /** + @brief + The following functions works like index_read, but it find the last + row with the current key value or prefix. + @returns @see index_read_map(). + */ + virtual int index_read_last_map(uchar * buf, const uchar * key, + key_part_map keypart_map) + { + uint key_len= calculate_key_len(table, active_index, key, keypart_map); + return index_read_last(buf, key, key_len); + } virtual int close(void)=0; inline void update_rows_read() { @@ -3350,7 +3363,7 @@ public: void ft_end() { ft_handler=NULL; } virtual FT_INFO *ft_init_ext(uint flags, uint inx,String *key) { return NULL; } -private: +public: virtual int ft_read(uchar *buf) { return HA_ERR_WRONG_COMMAND; } virtual int rnd_next(uchar *buf)=0; virtual int rnd_pos(uchar * buf, uchar *pos)=0; @@ -4057,6 +4070,7 @@ public: TABLE_SHARE* get_table_share() { return table_share; } protected: /* Service methods for use by storage engines. */ + void ha_statistic_increment(ulong SSV::*offset) const; void **ha_data(THD *) const; THD *ha_thd(void) const; @@ -4082,7 +4096,7 @@ protected: public: bool check_table_binlog_row_based(bool binlog_row); -private: + /* Cache result to avoid extra calls */ inline void mark_trx_read_write() { @@ -4092,6 +4106,8 @@ private: mark_trx_read_write_internal(); } } + +private: void mark_trx_read_write_internal(); bool check_table_binlog_row_based_internal(bool binlog_row); @@ -4210,6 +4226,11 @@ protected: virtual int index_read(uchar * buf, const uchar * key, uint key_len, enum ha_rkey_function find_flag) { return HA_ERR_WRONG_COMMAND; } + virtual int index_read_last(uchar * buf, const uchar * key, uint key_len) + { + my_errno= HA_ERR_WRONG_COMMAND; + return HA_ERR_WRONG_COMMAND; + } friend class ha_partition; friend class ha_sequence; public: @@ -4340,6 +4361,8 @@ public: { DBUG_ASSERT(0); return false; } virtual handler* part_handler(uint32 part_id) { DBUG_ASSERT(0); return NULL; } + virtual void update_partition(uint part_id) + {} protected: Handler_share *get_ha_share_ptr(); void set_ha_share_ptr(Handler_share *arg_ha_share); diff --git a/sql/partition_info.cc b/sql/partition_info.cc index f45b45548b0..c1a792c87e0 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -208,6 +208,48 @@ bool partition_info::set_named_partition_bitmap(const char *part_name, +/** + Prune away partitions not mentioned in the PARTITION () clause, + if used. + + @param table_list Table list pointing to table to prune. + + @return Operation status + @retval false Success + @retval true Failure +*/ +bool partition_info::set_read_partitions(List *partition_names) +{ + DBUG_ENTER("partition_info::set_read_partitions"); + if (!partition_names || !partition_names->elements) + { + DBUG_RETURN(true); + } + + uint num_names= partition_names->elements; + List_iterator partition_names_it(*partition_names); + uint i= 0; + /* + TODO: When adding support for FK in partitioned tables, the referenced + table must probably lock all partitions for read, and also write depending + of ON DELETE/UPDATE. + */ + bitmap_clear_all(&read_partitions); + + /* No check for duplicate names or overlapping partitions/subpartitions. */ + + DBUG_PRINT("info", ("Searching through partition_name_hash")); + do + { + char *part_name= partition_names_it++; + if (add_named_partition(part_name, strlen(part_name))) + DBUG_RETURN(true); + } while (++i < num_names); + DBUG_RETURN(false); +} + + + /** Prune away partitions not mentioned in the PARTITION () clause, if used. @@ -989,13 +1031,22 @@ bool partition_info::vers_scan_min_max(THD *thd, partition_element *part) uint32 part_id= part->id * sub_factor; uint32 part_id_end= part_id + sub_factor; DBUG_ASSERT(part->empty); + DBUG_ASSERT(part->type == partition_element::VERSIONING); DBUG_ASSERT(table->s->stat_trx); for (; part_id < part_id_end; ++part_id) { - handler *file= table->file->part_handler(part_id); - int rc= file->ha_external_lock(thd, F_RDLCK); + handler *file= table->file->part_handler(part_id); // requires update_partition() for ha_innopart + int rc= file->ha_external_lock(thd, F_RDLCK); // requires ha_commit_trans() for ha_innobase if (rc) - goto error; + { + file->update_partition(part_id); + goto lock_fail; + } + + table->default_column_bitmaps(); + bitmap_set_bit(table->read_set, table->vers_end_field()->field_index); + file->column_bitmaps_signal(); + rc= file->ha_rnd_init(true); if (!rc) { @@ -1006,6 +1057,8 @@ bool partition_info::vers_scan_min_max(THD *thd, partition_element *part) if (thd->killed) { file->ha_rnd_end(); + file->update_partition(part_id); + ha_commit_trans(thd, false); return true; } if (rc) @@ -1014,18 +1067,44 @@ bool partition_info::vers_scan_min_max(THD *thd, partition_element *part) continue; break; } - vers_stat_trx(STAT_TRX_END, part).update_unguarded(table->vers_end_field()); + if (table->vers_end_field()->is_max()) + { + rc= HA_ERR_INTERNAL_ERROR; + push_warning_printf(thd, + Sql_condition::WARN_LEVEL_WARN, + WARN_VERS_PART_NON_HISTORICAL, + ER_THD(thd, WARN_VERS_PART_NON_HISTORICAL), + part->partition_name); + break; + } + if (table->versioned_by_engine()) + { + uchar buf[8]; + Field_timestampf fld(buf, NULL, 0, Field::NONE, table->vers_end_field()->field_name, NULL, 6); + if (!vers_trx_id_to_ts(thd, table->vers_end_field(), fld)) + { + vers_stat_trx(STAT_TRX_END, part).update_unguarded(&fld); + } + } + else + { + vers_stat_trx(STAT_TRX_END, part).update_unguarded(table->vers_end_field()); + } } file->ha_rnd_end(); } file->ha_external_lock(thd, F_UNLCK); + file->update_partition(part_id); if (rc != HA_ERR_END_OF_FILE) { - error: - my_error(ER_INTERNAL_ERROR, MYF(0), "partition/subpartition scan failed in versioned partitions setup"); + ha_commit_trans(thd, false); + lock_fail: + // TODO: print rc code + my_error(ER_INTERNAL_ERROR, MYF(0), "min/max scan failed in versioned partitions setup (see warnings)"); return true; } } + ha_commit_trans(thd, false); return false; } @@ -1073,11 +1152,9 @@ bool partition_info::vers_setup_2(THD * thd, bool is_create_table_ind) DBUG_ASSERT(part_type == VERSIONING_PARTITION); DBUG_ASSERT(vers_info && vers_info->initialized(false)); DBUG_ASSERT(table && table->s); - if (!table->versioned_by_sql()) - { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), table->s->table_name.str, "selected engine is not supported in `BY SYSTEM_TIME` partitioning"); - return true; - } + + bool error= false; + mysql_mutex_lock(&table->s->LOCK_rotation); if (table->s->busy_rotation) { @@ -1124,8 +1201,19 @@ bool partition_info::vers_setup_2(THD * thd, bool is_create_table_ind) if (!is_create_table_ind) { - if (vers_scan_min_max(thd, el)) - return true; + if (el->type == partition_element::AS_OF_NOW) + { + uchar buf[8]; + Field_timestampf fld(buf, NULL, 0, Field::NONE, table->vers_end_field()->field_name, NULL, 6); + fld.set_max(); + vers_stat_trx(STAT_TRX_END, el).update_unguarded(&fld); + el->empty= false; + } + else if (vers_scan_min_max(thd, el)) + { + error= true; + break; + } if (!el->empty) { vers_update_col_vals(thd, prev, el); @@ -1151,7 +1239,7 @@ bool partition_info::vers_setup_2(THD * thd, bool is_create_table_ind) } } // while - if (!dont_stat) + if (!error && !dont_stat) { if (col_val_updated) table->s->stat_serial++; @@ -1165,7 +1253,7 @@ bool partition_info::vers_setup_2(THD * thd, bool is_create_table_ind) table->s->busy_rotation= false; } mysql_mutex_unlock(&table->s->LOCK_rotation); - return false; + return error; } @@ -3262,6 +3350,80 @@ bool partition_info::has_same_partitioning(partition_info *new_part_info) } +static bool has_same_column_order(List *create_list, + Field** field_array) +{ + Field **f_ptr; + List_iterator_fast new_field_it; + Create_field *new_field= NULL; + new_field_it.init(*create_list); + + for (f_ptr= field_array; *f_ptr; f_ptr++) + { + while ((new_field= new_field_it++)) + { + if (new_field->field == *f_ptr) + break; + } + if (!new_field) + break; + } + + if (!new_field) + { + /* Not same order!*/ + return false; + } + return true; +} + +bool partition_info::vers_trx_id_to_ts(THD* thd, Field* in_trx_id, Field_timestamp& out_ts) +{ + handlerton *hton= plugin_hton(table->s->db_plugin); + DBUG_ASSERT(hton); + ulonglong trx_id= in_trx_id->val_int(); + MYSQL_TIME ts; + bool found= hton->vers_query_trx_id(thd, &ts, trx_id, VTQ_COMMIT_TS); + if (!found) + { + push_warning_printf(thd, + Sql_condition::WARN_LEVEL_WARN, + WARN_VERS_TRX_MISSING, + ER_THD(thd, WARN_VERS_TRX_MISSING), + trx_id); + return true; + } + out_ts.store_time_dec(&ts, 6); + return false; +} + + +/** + Check if the partitioning columns are in the same order as the given list. + + Used to see if INPLACE alter can be allowed or not. If the order is + different then the rows must be redistributed for KEY [sub]partitioning. + + @param[in] create_list Column list after ALTER TABLE. + @return true is same order as before ALTER TABLE, else false. +*/ +bool partition_info::same_key_column_order(List *create_list) +{ + /* Only need to check for KEY [sub] partitioning. */ + if (list_of_part_fields && !column_list) + { + if (!has_same_column_order(create_list, part_field_array)) + return false; + } + if (list_of_subpart_fields) + { + if (!has_same_column_order(create_list, subpart_field_array)) + return false; + } + return true; +} + + void partition_info::print_debug(const char *str, uint *value) { DBUG_ENTER("print_debug"); diff --git a/sql/partition_info.h b/sql/partition_info.h index 5a671bfc50f..ef20564837c 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -22,6 +22,7 @@ #include "sql_class.h" #include "partition_element.h" +#include "sql_partition.h" class partition_info; struct TABLE_LIST; @@ -382,6 +383,28 @@ public: uint32 *part_id); void report_part_expr_error(bool use_subpart_expr); bool has_same_partitioning(partition_info *new_part_info); + inline bool is_partition_used(uint part_id) const + { + return bitmap_is_set(&read_partitions, part_id); + } + inline bool is_partition_locked(uint part_id) const + { + return bitmap_is_set(&lock_partitions, part_id); + } + inline uint num_partitions_used() + { + return bitmap_bits_set(&read_partitions); + } + inline uint get_first_used_partition() const + { + return bitmap_get_first_set(&read_partitions); + } + inline uint get_next_used_partition(uint part_id) const + { + return bitmap_get_next_set(&read_partitions, part_id); + } + bool same_key_column_order(List *create_list); + private: static int list_part_cmp(const void* a, const void* b); bool set_up_default_partitions(THD *thd, handler *file, HA_CREATE_INFO *info, @@ -392,9 +415,11 @@ private: uint start_no); char *create_default_subpartition_name(THD *thd, uint subpart_no, const char *part_name); + // FIXME: prune_partition_bitmaps() is duplicate of set_read_partitions() bool prune_partition_bitmaps(TABLE_LIST *table_list); bool add_named_partition(const char *part_name, uint length); public: + bool set_read_partitions(List *partition_names); bool has_unique_name(partition_element *element); bool vers_init_info(THD *thd); @@ -475,8 +500,8 @@ public: DBUG_ASSERT(vers_info->initialized()); part= vers_hist_part(); } - max_time-= vers_stat_trx(STAT_TRX_END, part).min_time(); - return max_time > vers_info->interval; + my_time_t min_time= vers_stat_trx(STAT_TRX_END, part).min_time(); + return max_time - min_time > vers_info->interval; } bool vers_interval_exceed(partition_element *part) { @@ -486,15 +511,31 @@ public: { return vers_interval_exceed(vers_hist_part()); } + bool vers_trx_id_to_ts(THD *thd, Field *in_trx_id, Field_timestamp &out_ts); void vers_update_stats(THD *thd, partition_element *el) { DBUG_ASSERT(vers_info && vers_info->initialized()); DBUG_ASSERT(table && table->s); DBUG_ASSERT(el && el->type == partition_element::VERSIONING); + bool updated; mysql_rwlock_wrlock(&table->s->LOCK_stat_serial); el->empty= false; - bool updated= - vers_stat_trx(STAT_TRX_END, el->id).update(table->vers_end_field()); + if (table->versioned_by_engine()) + { + // transaction is not yet pushed to VTQ, so we use now-time + my_time_t end_ts= my_time(0); + + uchar buf[8]; + Field_timestampf fld(buf, NULL, 0, Field::NONE, table->vers_end_field()->field_name, NULL, 6); + fld.store_TIME(end_ts, 0); + updated= + vers_stat_trx(STAT_TRX_END, el->id).update(&fld); + } + else + { + updated= + vers_stat_trx(STAT_TRX_END, el->id).update(table->vers_end_field()); + } if (updated) table->s->stat_serial++; mysql_rwlock_unlock(&table->s->LOCK_stat_serial); diff --git a/sql/partitioning/partition_handler.cc b/sql/partitioning/partition_handler.cc new file mode 100644 index 00000000000..1e04439e100 --- /dev/null +++ b/sql/partitioning/partition_handler.cc @@ -0,0 +1,3746 @@ +/* + Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 of + the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "table.h" // TABLE_SHARE +#include "sql_partition.h" // LIST_PART_ENTRY, part_id_range +#include "partition_info.h" // NOT_A_PARTITION_ID +#include "partition_handler.h" +#include "log.h" // sql_print_error +#include "key.h" // key_rec_cmp +#include "sql_class.h" // THD +#include + +#define MI_MAX_MSG_BUF 1024 + +// In sql_class.cc: +extern "C" int thd_binlog_format(const MYSQL_THD thd); + +/** operation names for the enum_part_operation. */ +static const char *opt_op_name[]= {"optimize", "analyze", "check", "repair", + "assign_to_keycache", "preload_keys"}; + +// static PSI_memory_key key_memory_Partition_share; +// static PSI_memory_key key_memory_partition_sort_buffer; +// static PSI_memory_key key_memory_Partition_admin; +#ifdef HAVE_PSI_INTERFACE +extern PSI_mutex_key key_partition_auto_inc_mutex; +// static PSI_memory_info all_partitioning_memory[]= +// { { &key_memory_Partition_share, "Partition_share", 0}, +// { &key_memory_partition_sort_buffer, "partition_sort_buffer", 0}, +// { &key_memory_Partition_admin, "Partition_admin", 0} }; +static PSI_mutex_info all_partitioning_mutex[]= +{ { &key_partition_auto_inc_mutex, "Partiton_share::auto_inc_mutex", 0} }; +#endif + +void partitioning_init() +{ +#ifdef HAVE_PSI_INTERFACE + int count; +// count= array_elements(all_partitioning_memory); +// mysql_memory_register("sql", all_partitioning_memory, count); + count= array_elements(all_partitioning_mutex); + mysql_mutex_register("sql", all_partitioning_mutex, count); +#endif +} + + +/** + Release reserved auto increment values not used. + @param thd Thread. + @param table_share Table Share + @param next_insert_id Next insert id (first non used auto inc value). + @param max_reserved End of reserved auto inc range. +*/ +void +Partition_share::release_auto_inc_if_possible(THD *thd, TABLE_SHARE *table_share, + const ulonglong next_insert_id, + const ulonglong max_reserved) +{ +#ifndef DBUG_OFF + if (table_share->tmp_table == NO_TMP_TABLE) + { + mysql_mutex_assert_owner(&auto_inc_mutex); + } +#endif /* DBUG_OFF */ + + /* + If the current auto_increment values is lower than the reserved value (1) + and the reserved value was reserved by this thread (2), then we can + lower the reserved value. + However, we cannot lower the value if there are forced/non generated + values from 'SET INSERT_ID = forced_val' (3). */ + if (next_insert_id < next_auto_inc_val && // (1) + max_reserved >= next_auto_inc_val && // (2) + thd->auto_inc_intervals_forced.maximum() < next_insert_id) // (3) + { + next_auto_inc_val= next_insert_id; + } +} + + +/** + Get the partition name. + + @param part Struct containing name and length + @param[out] length Length of the name + + @return Partition name +*/ + +static uchar *get_part_name_from_def(PART_NAME_DEF *part, + size_t *length, + my_bool not_used MY_ATTRIBUTE((unused))) +{ + *length= part->length; + return part->partition_name; +} + + +/** + Populate the partition_name_hash in part_share. +*/ + +bool Partition_share::populate_partition_name_hash(partition_info *part_info) +{ + uint tot_names; + uint num_subparts= part_info->num_subparts; + DBUG_ENTER("Partition_share::populate_partition_name_hash"); + DBUG_ASSERT(!part_info->is_sub_partitioned() || num_subparts); + + if (num_subparts == 0) + { + num_subparts= 1; + } + + /* + TABLE_SHARE::LOCK_ha_data must been locked before calling this function. + This ensures only one thread/table instance will execute this. + */ + +#ifndef DBUG_OFF + if (part_info->table->s->tmp_table == NO_TMP_TABLE) + { + mysql_mutex_assert_owner(&part_info->table->s->LOCK_ha_data); + } +#endif + if (partition_name_hash_initialized) + { + DBUG_RETURN(false); + } + tot_names= part_info->num_parts; + if (part_info->is_sub_partitioned()) + { + tot_names+= part_info->num_parts * num_subparts; + } + partition_names= static_cast(my_malloc( + part_info->get_tot_partitions() * + sizeof(*partition_names), + MYF(MY_WME))); + if (!partition_names) + { + DBUG_RETURN(true); + } + if (my_hash_init(&partition_name_hash, + system_charset_info, tot_names, 0, 0, + (my_hash_get_key) get_part_name_from_def, + my_free, HASH_UNIQUE)) + { + my_free(partition_names); + partition_names= NULL; + DBUG_RETURN(true); + } + + List_iterator part_it(part_info->partitions); + uint i= 0; + do + { + partition_element *part_elem= part_it++; + DBUG_ASSERT(part_elem->part_state == PART_NORMAL); + if (part_elem->part_state == PART_NORMAL) + { + if (insert_partition_name_in_hash(part_elem->partition_name, + i * num_subparts, + false)) + goto err; + if (part_info->is_sub_partitioned()) + { + List_iterator + subpart_it(part_elem->subpartitions); + partition_element *sub_elem; + uint j= 0; + do + { + sub_elem= subpart_it++; + if (insert_partition_name_in_hash(sub_elem->partition_name, + i * num_subparts + j, true)) + goto err; + + } while (++j < num_subparts); + } + } + } while (++i < part_info->num_parts); + + for (i= 0; i < tot_names; i++) + { + PART_NAME_DEF *part_def; + part_def= reinterpret_cast( + my_hash_element(&partition_name_hash, i)); + if (part_def->is_subpart == part_info->is_sub_partitioned()) + { + partition_names[part_def->part_id]= part_def->partition_name; + } + } + partition_name_hash_initialized= true; + + DBUG_RETURN(false); +err: + my_hash_free(&partition_name_hash); + my_free(partition_names); + partition_names= NULL; + + DBUG_RETURN(true); +} + + +/** + Insert a partition name in the partition_name_hash. + + @param name Name of partition + @param part_id Partition id (number) + @param is_subpart Set if the name belongs to a subpartition + + @return Operation status + @retval true Failure + @retval false Success +*/ + +bool Partition_share::insert_partition_name_in_hash(const char *name, + uint part_id, + bool is_subpart) +{ + PART_NAME_DEF *part_def; + uchar *part_name; + uint part_name_length; + DBUG_ENTER("Partition_share::insert_partition_name_in_hash"); + /* + Calculate and store the length here, to avoid doing it when + searching the hash. + */ + part_name_length= static_cast(strlen(name)); + /* + Must use memory that lives as long as table_share. + Freed in the Partition_share destructor. + Since we use my_multi_malloc, then my_free(part_def) will also free + part_name, as a part of my_hash_free. + */ + if (!my_multi_malloc(MY_WME, + &part_def, sizeof(PART_NAME_DEF), + &part_name, part_name_length + 1, + NULL)) + { + DBUG_RETURN(true); + } + memcpy(part_name, name, part_name_length + 1); + part_def->partition_name= part_name; + part_def->length= part_name_length; + part_def->part_id= part_id; + part_def->is_subpart= is_subpart; + if (my_hash_insert(&partition_name_hash, (uchar *) part_def)) + { + my_free(part_def); + DBUG_RETURN(true); + } + DBUG_RETURN(false); +} + + +const char *Partition_share::get_partition_name(size_t part_id) const +{ + if (partition_names == NULL) + { + return NULL; + } + return reinterpret_cast(partition_names[part_id]); +} +/* + Implementation of Partition_helper class. +*/ +Partition_helper::Partition_helper(handler *main_handler) + : + m_handler(main_handler), + m_part_info(), + m_tot_parts(), + m_last_part(), + m_err_rec(), + m_ordered(), + m_ordered_scan_ongoing(), + m_ordered_rec_buffer(), + m_queue() +{} + + +Partition_helper::~Partition_helper() +{ + DBUG_ASSERT(m_ordered_rec_buffer == NULL); + DBUG_ASSERT(m_key_not_found_partitions.bitmap == NULL); +} + + +/** + Set partition info. + + To be called from Partition_handler. + + @param part_info Partition info to use. + @param early True if called when part_info only created and parsed, + but not setup, checked or fixed. + */ +void Partition_helper::set_part_info_low(partition_info *part_info, + bool early) +{ + /* + ha_partition will set m_tot_parts from the .par file during creating + the new handler. + And this call can be earlier than the partition_default_handling(), + so get_tot_partitions() may return zero. + */ + if (m_tot_parts == 0 && + (m_part_info == NULL || !early)) + { + m_tot_parts= part_info->get_tot_partitions(); + } + m_part_info= part_info; + m_is_sub_partitioned= m_part_info->is_sub_partitioned(); +} + +/** + Initialize the partitioning helper for use after the table is opened. + + @param part_share Partitioning share (used for auto increment). + + @return Operation status. + @retval false for success otherwise true. +*/ + +bool Partition_helper::open_partitioning(Partition_share *part_share) +{ + m_table= get_table(); + DBUG_ASSERT(m_part_info == m_table->part_info); + m_part_share= part_share; + m_tot_parts= m_part_info->get_tot_partitions(); + if (bitmap_init(&m_key_not_found_partitions, NULL, m_tot_parts, false)) + { + return true; + } + bitmap_clear_all(&m_key_not_found_partitions); + m_key_not_found= false; + m_is_sub_partitioned= m_part_info->is_sub_partitioned(); + m_auto_increment_lock= false; + m_auto_increment_safe_stmt_log_lock= false; + m_pkey_is_clustered= m_handler->primary_key_is_clustered(); + m_part_spec.start_part= NOT_A_PARTITION_ID; + m_part_spec.end_part= NOT_A_PARTITION_ID; + m_index_scan_type= PARTITION_NO_INDEX_SCAN; + m_start_key.key= NULL; + m_start_key.length= 0; + m_scan_value= 3; + m_reverse_order= false; + m_curr_key_info[0]= NULL; + m_curr_key_info[1]= NULL; + m_curr_key_info[2]= NULL; + m_top_entry= NO_CURRENT_PART_ID; + m_ref_usage= REF_NOT_USED; + m_rec_length= m_table->s->reclength; + return false; +} + + +void Partition_helper::close_partitioning() +{ + bitmap_free(&m_key_not_found_partitions); + DBUG_ASSERT(!m_ordered_rec_buffer); + destroy_record_priority_queue(); +} + +/**************************************************************************** + MODULE change record +****************************************************************************/ + +/** + Insert a row to the partitioned table. + + @param buf The row in MySQL Row Format. + + @return Operation status. + @retval 0 Success + @retval != 0 Error code +*/ + +int Partition_helper::ph_write_row(uchar *buf) +{ + uint32 part_id; + int error; + longlong func_value; + bool have_auto_increment= m_table->next_number_field && + buf == m_table->record[0]; + THD *thd= get_thd(); + sql_mode_t saved_sql_mode= thd->variables.sql_mode; + bool saved_auto_inc_field_not_null= m_table->auto_increment_field_not_null; +#ifndef DBUG_OFF + my_bitmap_map *old_map; +#endif /* DBUG_OFF */ + DBUG_ENTER("Partition_helper::ph_write_row"); + DBUG_ASSERT(buf == m_table->record[0]); + + /* + If we have an auto_increment column and we are writing a changed row + or a new row, then update the auto_increment value in the record. + */ + if (have_auto_increment) + { + error= m_handler->update_auto_increment(); + + /* + If we have failed to set the auto-increment value for this row, + it is highly likely that we will not be able to insert it into + the correct partition. We must check and fail if neccessary. + */ + if (error) + DBUG_RETURN(error); + + /* + Don't allow generation of auto_increment value the partitions handler. + If a partitions handler would change the value, then it might not + match the partition any longer. + This can occur if 'SET INSERT_ID = 0; INSERT (NULL)', + So allow this by adding 'MODE_NO_AUTO_VALUE_ON_ZERO' to sql_mode. + The partitions handler::next_insert_id must always be 0. Otherwise + we need to forward release_auto_increment, or reset it for all + partitions. + */ + if (m_table->next_number_field->val_int() == 0) + { + m_table->auto_increment_field_not_null= TRUE; + thd->variables.sql_mode|= MODE_NO_AUTO_VALUE_ON_ZERO; + } + } + +#ifndef DBUG_OFF + /* Temporary mark the partitioning fields as readable. */ + old_map= dbug_tmp_use_all_columns(m_table, m_table->read_set); +#endif /* DBUG_OFF */ + + error= m_part_info->get_partition_id(m_part_info, &part_id, &func_value); + +#ifndef DBUG_OFF + dbug_tmp_restore_column_map(m_table->read_set, old_map); +#endif /* DBUG_OFF */ + + if (unlikely(error)) + { + m_part_info->err_value= func_value; + goto exit; + } + if (!m_part_info->is_partition_locked(part_id)) + { + DBUG_PRINT("info", ("Write to non-locked partition %u (func_value: %ld)", + part_id, (long) func_value)); + error= HA_ERR_NOT_IN_LOCK_PARTITIONS; + goto exit; + } + m_last_part= part_id; + DBUG_PRINT("info", ("Insert in partition %d", part_id)); + + error= write_row_in_part(part_id, buf); + + if (have_auto_increment && !m_table->s->next_number_keypart) + { + set_auto_increment_if_higher(); + } +exit: + thd->variables.sql_mode= saved_sql_mode; + m_table->auto_increment_field_not_null= saved_auto_inc_field_not_null; + DBUG_RETURN(error); +} + + +/** + Update an existing row in the partitioned table. + + Yes, update_row() does what you expect, it updates a row. old_data will + have the previous row record in it, while new_data will have the newest + data in it. + Keep in mind that the server can do updates based on ordering if an + ORDER BY clause was used. Consecutive ordering is not guaranteed. + + If the new record belongs to a different partition than the old record + then it will be inserted into the new partition and deleted from the old. + + new_data is always record[0] + old_data is always record[1] + + @param old_data The old record in MySQL Row Format. + @param new_data The new record in MySQL Row Format. + + @return Operation status. + @retval 0 Success + @retval != 0 Error code +*/ + +// FIXME: duplicate of ha_partition::update_row() +int Partition_helper::ph_update_row(const uchar *old_data, uchar *new_data) +{ + THD *thd= get_thd(); + uint32 new_part_id, old_part_id; + int error= 0; + longlong func_value; + DBUG_ENTER("Partition_helper::ph_update_row"); + m_err_rec= NULL; + + // Need to read partition-related columns, to locate the row's partition: + DBUG_ASSERT(bitmap_is_subset(&m_part_info->full_part_field_set, + m_table->read_set)); + if ((error= get_parts_for_update(old_data, new_data, m_table->record[0], + m_part_info, &old_part_id, &new_part_id, + &func_value))) + { + m_part_info->err_value= func_value; + goto exit; + } + DBUG_ASSERT(bitmap_is_set(&(m_part_info->read_partitions), old_part_id)); + if (!bitmap_is_set(&(m_part_info->lock_partitions), new_part_id)) + { + error= HA_ERR_NOT_IN_LOCK_PARTITIONS; + goto exit; + } + + /* + The protocol for updating a row is: + 1) position the handler (cursor) on the row to be updated, + either through the last read row (rnd or index) or by rnd_pos. + 2) call update_row with both old and new full records as arguments. + + This means that m_last_part should already be set to actual partition + where the row was read from. And if that is not the same as the + calculated part_id we found a misplaced row, we return an error to + notify the user that something is broken in the row distribution + between partitions! Since we don't check all rows on read, we return an + error instead of correcting m_last_part, to make the user aware of the + problem! + + Notice that HA_READ_BEFORE_WRITE_REMOVAL does not require this protocol, + so this is not supported for this engine. + */ + if (old_part_id != m_last_part) + { + m_err_rec= old_data; + DBUG_RETURN(HA_ERR_ROW_IN_WRONG_PARTITION); + } + + m_last_part= new_part_id; + if (new_part_id == old_part_id) + { + DBUG_PRINT("info", ("Update in partition %d", new_part_id)); + tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */ + error= update_row_in_part(new_part_id, old_data, new_data); + reenable_binlog(thd); + goto exit; + } + else + { + Field *saved_next_number_field= m_table->next_number_field; + /* + Don't allow generation of auto_increment value for update. + table->next_number_field is never set on UPDATE. + But is set for INSERT ... ON DUPLICATE KEY UPDATE, + and since update_row() does not generate or update an auto_inc value, + we cannot have next_number_field set when moving a row + to another partition with write_row(), since that could + generate/update the auto_inc value. + This gives the same behavior for partitioned vs non partitioned tables. + */ + m_table->next_number_field= NULL; + DBUG_PRINT("info", ("Update from partition %d to partition %d", + old_part_id, new_part_id)); + tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */ + error= write_row_in_part(new_part_id, new_data); + reenable_binlog(thd); + m_table->next_number_field= saved_next_number_field; + if (error) + goto exit; + + if (m_part_info->part_type == VERSIONING_PARTITION) + { + uint sub_factor= m_part_info->num_subparts ? m_part_info->num_subparts : 1; + DBUG_ASSERT(m_tot_parts == m_part_info->num_parts * sub_factor); + uint lpart_id= new_part_id / sub_factor; + // lpart_id is VERSIONING partition because new_part_id != old_part_id + m_part_info->vers_update_stats(thd, lpart_id); + } + + tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */ + error= delete_row_in_part(old_part_id, old_data); + reenable_binlog(thd); + if (error) + { + goto exit; + } + } + +exit: + /* + if updating an auto_increment column, update + m_part_share->next_auto_inc_val if needed. + (not to be used if auto_increment on secondary field in a multi-column + index) + mysql_update does not set table->next_number_field, so we use + table->found_next_number_field instead. + Also checking that the field is marked in the write set. + */ + if (m_table->found_next_number_field && + new_data == m_table->record[0] && + !m_table->s->next_number_keypart && + bitmap_is_set(m_table->write_set, + m_table->found_next_number_field->field_index)) + { + set_auto_increment_if_higher(); + } + DBUG_RETURN(error); +} + + +/** + Delete an existing row in the partitioned table. + + This will delete a row. buf will contain a copy of the row to be deleted. + The server will call this right after the current row has been read + (from either a previous rnd_xxx() or index_xxx() call). + If you keep a pointer to the last row or can access a primary key it will + make doing the deletion quite a bit easier. + Keep in mind that the server does no guarentee consecutive deletions. + ORDER BY clauses can be used. + + buf is either record[0] or record[1] + + @param buf The record in MySQL Row Format. + + @return Operation status. + @retval 0 Success + @retval != 0 Error code +*/ + +int Partition_helper::ph_delete_row(const uchar *buf) +{ + int error; + uint part_id; + DBUG_ENTER("Partition_helper::ph_delete_row"); + m_err_rec= NULL; + + DBUG_ASSERT(bitmap_is_subset(&m_part_info->full_part_field_set, + m_table->read_set)); + if ((error= get_part_for_delete(buf, + m_table->record[0], + m_part_info, + &part_id))) + { + DBUG_RETURN(error); + } + if (!m_part_info->is_partition_locked(part_id)) + { + DBUG_RETURN(HA_ERR_NOT_IN_LOCK_PARTITIONS); + } + + /* + The protocol for deleting a row is: + 1) position the handler (cursor) on the row to be deleted, + either through the last read row (rnd or index) or by rnd_pos. + 2) call delete_row with the full record as argument. + + This means that m_last_part should already be set to actual partition + where the row was read from. And if that is not the same as the + calculated part_id we found a misplaced row, we return an error to + notify the user that something is broken in the row distribution + between partitions! Since we don't check all rows on read, we return an + error instead of forwarding the delete to the correct (m_last_part) + partition! + + Notice that HA_READ_BEFORE_WRITE_REMOVAL does not require this protocol, + so this is not supported for this engine. + + TODO: change the assert in InnoDB into an error instead and make this one + an assert instead and remove the get_part_for_delete()! + */ + if (part_id != m_last_part) + { + m_err_rec= buf; + DBUG_RETURN(HA_ERR_ROW_IN_WRONG_PARTITION); + } + /* Should never call delete_row on a partition which is not read */ + DBUG_ASSERT(m_part_info->is_partition_used(part_id)); + + m_last_part= part_id; + error= delete_row_in_part(part_id, buf); + DBUG_RETURN(error); +} + + +/** + Get a range of auto increment values. + + Can only be used if the auto increment field is the first field in an index. + + This method is called by update_auto_increment which in turn is called + by the individual handlers as part of write_row. We use the + part_share->next_auto_inc_val, or search all + partitions for the highest auto_increment_value if not initialized or + if auto_increment field is a secondary part of a key, we must search + every partition when holding a mutex to be sure of correctness. + + @param[in] increment Increment value. + @param[in] nb_desired_values Number of desired values. + @param[out] first_value First auto inc value reserved + or MAX if failure. + @param[out] nb_reserved_values Number of values reserved. +*/ + +void Partition_helper +::get_auto_increment_first_field(ulonglong increment, + ulonglong nb_desired_values, + ulonglong *first_value, + ulonglong *nb_reserved_values) +{ + THD *thd= get_thd(); + DBUG_ENTER("Partition_helper::get_auto_increment_first_field"); + DBUG_PRINT("info", ("inc: %lu desired_values: %lu first_value: %lu", + (ulong) increment, + (ulong) nb_desired_values, + (ulong) *first_value)); + DBUG_ASSERT(increment && nb_desired_values); + /* + next_number_keypart is != 0 if the auto_increment column is a secondary + column in the index (it is allowed in MyISAM) + */ + DBUG_ASSERT(m_table->s->next_number_keypart == 0); + *first_value= 0; + + /* + Get a lock for handling the auto_increment in part_share + for avoiding two concurrent statements getting the same number. + */ + lock_auto_increment(); + + /* Initialize if not already done. */ + if (!m_part_share->auto_inc_initialized) + { + initialize_auto_increment(false); + } + + /* + In a multi-row insert statement like INSERT SELECT and LOAD DATA + where the number of candidate rows to insert is not known in advance + we must hold a lock/mutex for the whole statement if we have statement + based replication. Because the statement-based binary log contains + only the first generated value used by the statement, and slaves assumes + all other generated values used by this statement were consecutive to + this first one, we must exclusively lock the generator until the statement + is done. + */ + int binlog_format= thd_binlog_format(thd); + if (!m_auto_increment_safe_stmt_log_lock && + thd->lex->sql_command != SQLCOM_INSERT && + binlog_format != BINLOG_FORMAT_UNSPEC && + binlog_format != BINLOG_FORMAT_ROW) + { + DBUG_PRINT("info", ("locking auto_increment_safe_stmt_log_lock")); + m_auto_increment_safe_stmt_log_lock= true; + } + + /* this gets corrected (for offset/increment) in update_auto_increment */ + *first_value= m_part_share->next_auto_inc_val; + m_part_share->next_auto_inc_val+= nb_desired_values * increment; + if (m_part_share->next_auto_inc_val < *first_value) + { + /* Overflow, set to max. */ + m_part_share->next_auto_inc_val= ULLONG_MAX; + } + + unlock_auto_increment(); + DBUG_PRINT("info", ("*first_value: %lu", (ulong) *first_value)); + *nb_reserved_values= nb_desired_values; + DBUG_VOID_RETURN; +} + + +inline void Partition_helper::set_auto_increment_if_higher() +{ + Field_num *field= static_cast(m_table->found_next_number_field); + ulonglong nr= (field->unsigned_flag || field->val_int() > 0) + ? field->val_int() : 0; + lock_auto_increment(); + if (!m_part_share->auto_inc_initialized) + { + initialize_auto_increment(false); + } + /* must hold the mutex when looking/changing m_part_share. */ + if (nr >= m_part_share->next_auto_inc_val) + { + m_part_share->next_auto_inc_val= nr + 1; + } + unlock_auto_increment(); + save_auto_increment(nr); +} + + +void Partition_helper::ph_release_auto_increment() +{ + DBUG_ENTER("Partition_helper::ph_release_auto_increment"); + + if (m_table->s->next_number_keypart) + { + release_auto_increment_all_parts(); + } + else if (m_handler->next_insert_id) + { + ulonglong max_reserved= m_handler->auto_inc_interval_for_cur_row.maximum(); + lock_auto_increment(); + m_part_share->release_auto_inc_if_possible(get_thd(), m_table->s, + m_handler->next_insert_id, + max_reserved); + DBUG_PRINT("info", ("part_share->next_auto_inc_val: %lu", + (ulong) m_part_share->next_auto_inc_val)); + + /* Unlock the multi row statement lock taken in get_auto_increment */ + if (m_auto_increment_safe_stmt_log_lock) + { + m_auto_increment_safe_stmt_log_lock= FALSE; + DBUG_PRINT("info", ("unlocking auto_increment_safe_stmt_log_lock")); + } + + unlock_auto_increment(); + } + DBUG_VOID_RETURN; +} + + +/** + Calculate key hash value from an null terminated array of fields. + Support function for KEY partitioning. + + @param field_array An array of the fields in KEY partitioning + + @return hash_value calculated + + @note Uses the hash function on the character set of the field. + Integer and floating point fields use the binary character set by default. +*/ + +uint32 Partition_helper::ph_calculate_key_hash_value(Field **field_array) +{ + ulong nr1= 1; + ulong nr2= 4; + bool use_51_hash; + use_51_hash= MY_TEST((*field_array)->table->part_info->key_algorithm == + partition_info::KEY_ALGORITHM_51); + + do + { + Field *field= *field_array; + if (use_51_hash) + { + switch (field->real_type()) { + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_DOUBLE: + case MYSQL_TYPE_NEWDECIMAL: + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_LONGLONG: + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_YEAR: + case MYSQL_TYPE_NEWDATE: + { + if (field->is_null()) + { + nr1^= (nr1 << 1) | 1; + continue; + } + /* Force this to my_hash_sort_bin, which was used in 5.1! */ + uint len= field->pack_length(); + my_charset_bin.coll->hash_sort(&my_charset_bin, field->ptr, len, + &nr1, &nr2); + /* Done with this field, continue with next one. */ + continue; + } + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_BIT: + /* Not affected, same in 5.1 and 5.5 */ + break; + /* + ENUM/SET uses my_hash_sort_simple in 5.1 (i.e. my_charset_latin1) + and my_hash_sort_bin in 5.5! + */ + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: + { + if (field->is_null()) + { + nr1^= (nr1 << 1) | 1; + continue; + } + /* Force this to my_hash_sort_bin, which was used in 5.1! */ + uint len= field->pack_length(); + my_charset_latin1.coll->hash_sort(&my_charset_latin1, field->ptr, + len, &nr1, &nr2); + continue; + } + /* New types in mysql-5.6. */ + case MYSQL_TYPE_DATETIME2: + case MYSQL_TYPE_TIME2: + case MYSQL_TYPE_TIMESTAMP2: + /* Not affected, 5.6+ only! */ + break; + + /* These types should not be allowed for partitioning! */ + case MYSQL_TYPE_NULL: + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_GEOMETRY: + /* fall through. */ + default: + DBUG_ASSERT(0); // New type? + /* Fall through for default hashing (5.5). */ + } + /* fall through, use collation based hashing. */ + } + field->hash(&nr1, &nr2); + } while (*(++field_array)); + return (uint32) nr1; +} + + +bool Partition_helper::print_partition_error(int error, myf errflag) +{ + THD *thd= get_thd(); + DBUG_ENTER("Partition_helper::print_partition_error"); + + /* Should probably look for my own errors first */ + DBUG_PRINT("enter", ("error: %d", error)); + + if ((error == HA_ERR_NO_PARTITION_FOUND) && + ! (thd->lex->alter_info.flags & Alter_info::ALTER_TRUNCATE_PARTITION)) + { + m_part_info->print_no_partition_found(m_table, errflag); + // print_no_partition_found() reports an error, so we can just return here. + DBUG_RETURN(false); + } + else if (error == HA_ERR_ROW_IN_WRONG_PARTITION) + { + /* + Should only happen on DELETE or UPDATE! + Or in ALTER TABLE REBUILD/REORGANIZE where there are a misplaced + row that needed to move to an old partition (not in the given set). + */ + DBUG_ASSERT(thd_sql_command(thd) == SQLCOM_DELETE || + thd_sql_command(thd) == SQLCOM_DELETE_MULTI || + thd_sql_command(thd) == SQLCOM_UPDATE || + thd_sql_command(thd) == SQLCOM_UPDATE_MULTI || + thd_sql_command(thd) == SQLCOM_ALTER_TABLE); + DBUG_ASSERT(m_err_rec); + if (m_err_rec) + { + size_t max_length; + char buf[MAX_KEY_LENGTH]; + String str(buf,sizeof(buf),system_charset_info); + uint32 part_id; + DBUG_ASSERT(m_last_part < m_tot_parts); + str.length(0); + if (thd_sql_command(thd) == SQLCOM_ALTER_TABLE) + { + str.append("from REBUILD/REORGANIZED partition: "); + str.append_ulonglong(m_last_part); + str.append(" to non included partition (new definition): "); + } + else + { + str.append_ulonglong(m_last_part); + str.append(". Correct is "); + } + if (get_part_for_delete(m_err_rec, + m_table->record[0], + m_part_info, + &part_id)) + { + str.append("?"); + } + else + { + str.append_ulonglong(part_id); + } + append_row_to_str(str, m_err_rec, m_table); + + /* Log this error, so the DBA can notice it and fix it! */ + sql_print_error("Table '%-192s' corrupted: row in wrong partition: %s\n" + "Please REPAIR the table!", + m_table->s->table_name.str, + str.c_ptr_safe()); + + max_length= (MYSQL_ERRMSG_SIZE - strlen(ER(ER_ROW_IN_WRONG_PARTITION))); + if (str.length() >= max_length) + { + str.length(max_length-4); + str.append(STRING_WITH_LEN("...")); + } + my_error(ER_ROW_IN_WRONG_PARTITION, MYF(0), str.c_ptr_safe()); + m_err_rec= NULL; + DBUG_RETURN(false); + } + } + + DBUG_RETURN(true); +} + + +/** + Implement the partition changes defined by ALTER TABLE of partitions. + + Add and copy if needed a number of partitions, during this operation + only read operation is ongoing in the server. This is used by + ADD PARTITION all types as well as by REORGANIZE PARTITION. For + one-phased implementations it is used also by DROP and COALESCE + PARTITIONs. + One-phased implementation needs the new frm file, other handlers will + get zero length and a NULL reference here. + + @param[in] create_info HA_CREATE_INFO object describing all + fields and indexes in table + @param[in] path Complete path of db and table name + @param[out] copied Output parameter where number of copied + records are added + @param[out] deleted Output parameter where number of deleted + records are added + + @return Operation status + @retval 0 Success + @retval != 0 Failure +*/ + +// FIXME: duplicate of ha_partition::change_partitions +int Partition_helper::change_partitions(HA_CREATE_INFO *create_info, + const char *path, + ulonglong * const copied, + ulonglong * const deleted) +{ + List_iterator part_it(m_part_info->partitions); + List_iterator t_it(m_part_info->temp_partitions); + char part_name_buff[FN_REFLEN]; + const char *table_level_data_file_name= create_info->data_file_name; + const char *table_level_index_file_name= create_info->index_file_name; + const char *table_level_tablespace_name= create_info->tablespace; + uint num_parts= m_part_info->partitions.elements; + uint num_subparts= m_part_info->num_subparts; + uint i= 0; + uint num_remain_partitions; + uint num_reorged_parts; + int error= 1; + bool first; + uint temp_partitions= m_part_info->temp_partitions.elements; + THD *thd= get_thd(); + DBUG_ENTER("Partition_helper::change_partitions"); + + /* + Use the read_partitions bitmap for reorganized partitions, + i.e. what to copy. + */ + bitmap_clear_all(&m_part_info->read_partitions); + + /* + Assert that it works without HA_FILE_BASED and lower_case_table_name = 2. + */ + DBUG_ASSERT(!strcmp(path, get_canonical_filename(m_handler, path, + part_name_buff))); + num_reorged_parts= 0; + if (!m_part_info->is_sub_partitioned()) + num_subparts= 1; + + /* + Step 1: + Calculate number of reorganized partitions. + */ + if (temp_partitions) + { + num_reorged_parts= temp_partitions * num_subparts; + } + else + { + do + { + partition_element *part_elem= part_it++; + if (part_elem->part_state == PART_CHANGED || + part_elem->part_state == PART_REORGED_DROPPED) + { + num_reorged_parts+= num_subparts; + } + } while (++i < num_parts); + } + + /* + Step 2: + Calculate number of partitions after change. + */ + num_remain_partitions= 0; + if (temp_partitions) + { + num_remain_partitions= num_parts * num_subparts; + } + else + { + part_it.rewind(); + i= 0; + do + { + partition_element *part_elem= part_it++; + if (part_elem->part_state == PART_NORMAL || + part_elem->part_state == PART_TO_BE_ADDED || + part_elem->part_state == PART_CHANGED) + { + num_remain_partitions+= num_subparts; + } + } while (++i < num_parts); + } + + /* + Step 3: + Set the read_partition bit for all partitions to be copied. + */ + if (num_reorged_parts) + { + i= 0; + first= true; + part_it.rewind(); + do + { + partition_element *part_elem= part_it++; + if (part_elem->part_state == PART_CHANGED || + part_elem->part_state == PART_REORGED_DROPPED) + { + for (uint sp = 0; sp < num_subparts; sp++) + { + bitmap_set_bit(&m_part_info->read_partitions, i * num_subparts + sp); + } + DBUG_ASSERT(first); + } + else if (first && temp_partitions && + part_elem->part_state == PART_TO_BE_ADDED) + { + /* + When doing an ALTER TABLE REORGANIZE PARTITION a number of + partitions is to be reorganized into a set of new partitions. + The reorganized partitions are in this case in the temp_partitions + list. We mark all of them in one batch and thus we only do this + until we find the first partition with state PART_TO_BE_ADDED + since this is where the new partitions go in and where the old + ones used to be. + */ + first= false; + DBUG_ASSERT(((i*num_subparts) + num_reorged_parts) <= m_tot_parts); + for (uint sp = 0; sp < num_reorged_parts; sp++) + { + bitmap_set_bit(&m_part_info->read_partitions, i * num_subparts + sp); + } + } + } while (++i < num_parts); + } + + /* + Step 4: + Create the new partitions and also open, lock and call + external_lock on them (if needed) to prepare them for copy phase + and also for later close calls. + No need to create PART_NORMAL partitions since they must not + be written to! + Only PART_CHANGED and PART_TO_BE_ADDED should be written to! + */ + + error= prepare_for_new_partitions(num_remain_partitions, + num_reorged_parts == 0); + + i= 0; + part_it.rewind(); + do + { + partition_element *part_elem= part_it++; + DBUG_ASSERT(part_elem->part_state >= PART_NORMAL && + part_elem->part_state <= PART_CHANGED); + if (part_elem->part_state == PART_TO_BE_ADDED || + part_elem->part_state == PART_CHANGED) + { + /* + A new partition needs to be created PART_TO_BE_ADDED means an + entirely new partition and PART_CHANGED means a changed partition + that will still exist with either more or less data in it. + */ + uint name_variant= NORMAL_PART_NAME; + if (part_elem->part_state == PART_CHANGED || + (part_elem->part_state == PART_TO_BE_ADDED && temp_partitions)) + name_variant= TEMP_PART_NAME; + if (m_part_info->is_sub_partitioned()) + { + List_iterator sub_it(part_elem->subpartitions); + uint j= 0, part; + do + { + partition_element *sub_elem= sub_it++; + create_subpartition_name(part_name_buff, path, + part_elem->partition_name, + sub_elem->partition_name, + name_variant); + part= i * num_subparts + j; + DBUG_PRINT("info", ("Add subpartition %s", part_name_buff)); + /* + update_create_info was called previously in + mysql_prepare_alter_table. Which may have set data/index_file_name + for the partitions to the full partition name, including + '#P#[#SP#] suffix. Remove that suffix + if it exists. + */ + truncate_partition_filename(sub_elem->data_file_name); + truncate_partition_filename(sub_elem->index_file_name); + /* Notice that sub_elem is already based on part_elem's defaults. */ + error= set_up_table_before_create(thd, + m_table->s, + part_name_buff, + create_info, + sub_elem); + if (error) + { + goto err; + } + if ((error= create_new_partition(m_table, + create_info, + part_name_buff, + part, + sub_elem))) + { + goto err; + } + /* Reset create_info to table level values. */ + create_info->data_file_name= table_level_data_file_name; + create_info->index_file_name= table_level_index_file_name; + create_info->tablespace= table_level_tablespace_name; + } while (++j < num_subparts); + } + else + { + create_partition_name(part_name_buff, path, + part_elem->partition_name, name_variant, + true); + DBUG_PRINT("info", ("Add partition %s", part_name_buff)); + /* See comment in subpartition branch above! */ + truncate_partition_filename(part_elem->data_file_name); + truncate_partition_filename(part_elem->index_file_name); + error= set_up_table_before_create(thd, + m_table->s, + part_name_buff, + create_info, + part_elem); + if (error) + { + goto err; + } + if ((error= create_new_partition(m_table, + create_info, + (const char *)part_name_buff, + i, + part_elem))) + { + goto err; + } + /* Reset create_info to table level values. */ + create_info->data_file_name= table_level_data_file_name; + create_info->index_file_name= table_level_index_file_name; + create_info->tablespace= table_level_tablespace_name; + } + } + } while (++i < num_parts); + + /* + Step 5: + State update to prepare for next write of the frm file. + */ + i= 0; + part_it.rewind(); + do + { + partition_element *part_elem= part_it++; + if (part_elem->part_state == PART_TO_BE_ADDED) + part_elem->part_state= PART_IS_ADDED; + else if (part_elem->part_state == PART_CHANGED) + part_elem->part_state= PART_IS_CHANGED; + else if (part_elem->part_state == PART_REORGED_DROPPED) + part_elem->part_state= PART_TO_BE_DROPPED; + } while (++i < num_parts); + for (i= 0; i < temp_partitions; i++) + { + partition_element *part_elem= t_it++; + DBUG_ASSERT(part_elem->part_state == PART_TO_BE_REORGED); + part_elem->part_state= PART_TO_BE_DROPPED; + } + error= copy_partitions(copied, deleted); +err: + if (error) + { + m_handler->print_error(error, + MYF(error != ER_OUTOFMEMORY ? 0 : ME_FATALERROR)); + } + /* + Close and unlock the new temporary partitions. + They will later be deleted or renamed through the ddl-log. + */ + close_new_partitions(); + DBUG_RETURN(error); +} + + +/** + Copy partitions as part of ALTER TABLE of partitions. + + change_partitions has done all the preparations, now it is time to + actually copy the data from the reorganized partitions to the new + partitions. + + @param[out] copied Number of records copied. + @param[out] deleted Number of records deleted. + + @return Operation status + @retval 0 Success + @retval >0 Error code +*/ + +int Partition_helper::copy_partitions(ulonglong * const copied, + ulonglong * const deleted) +{ + uint new_part= 0; + int result= 0; + longlong func_value; + DBUG_ENTER("Partition_helper::copy_partitions"); + + if (m_part_info->linear_hash_ind) + { + if (m_part_info->part_type == HASH_PARTITION) + set_linear_hash_mask(m_part_info, m_part_info->num_parts); + else + set_linear_hash_mask(m_part_info, m_part_info->num_subparts); + } + + /* + m_part_info->read_partitions bitmap is setup for all the reorganized + partitions to be copied. So we can use the normal handler rnd interface + for reading. + */ + if ((result= m_handler->ha_rnd_init(1))) + { + DBUG_RETURN(result); + } + while (true) + { + if ((result= m_handler->ha_rnd_next(m_table->record[0]))) + { + if (result == HA_ERR_RECORD_DELETED) + continue; //Probably MyISAM + if (result != HA_ERR_END_OF_FILE) + goto error; + /* + End-of-file reached, break out to end the copy process. + */ + break; + } + /* Found record to insert into new handler */ + if (m_part_info->get_partition_id(m_part_info, &new_part, + &func_value)) + { + /* + This record is in the original table but will not be in the new + table since it doesn't fit into any partition any longer due to + changed partitioning ranges or list values. + */ + (*deleted)++; + } + else + { + if ((result= write_row_in_new_part(new_part))) + { + goto error; + } + } + } + m_handler->ha_rnd_end(); + DBUG_RETURN(false); +error: + m_handler->ha_rnd_end(); + DBUG_RETURN(result); +} + + +/** + Check/fix misplaced rows. + + @param part_id Partition to check/fix. + @param repair If true, move misplaced rows to correct partition. + + @return Operation status. + @retval 0 Success + @retval != 0 Error +*/ + +int Partition_helper::check_misplaced_rows(uint read_part_id, bool repair) +{ + int result= 0; + THD *thd= get_thd(); + bool ignore= thd->lex->ignore; + uint32 correct_part_id; + longlong func_value; + ha_rows num_misplaced_rows= 0; + ha_rows num_deleted_rows= 0; + + DBUG_ENTER("Partition_helper::check_misplaced_rows"); + + if (repair) + { + /* We must read the full row, if we need to move it! */ + bitmap_set_all(m_table->read_set); + bitmap_set_all(m_table->write_set); + } + else + { + /* Only need to read the partitioning fields. */ + bitmap_union(m_table->read_set, &m_part_info->full_part_field_set); +#if 0 + /* Fill the base columns of virtual generated columns if necessary */ + for (Field **ptr= m_part_info->full_part_field_array; *ptr; ptr++) + { + if ((*ptr)->is_virtual_gcol()) + m_table->mark_gcol_in_maps(*ptr); + } +#endif + } + + if ((result= rnd_init_in_part(read_part_id, true))) + DBUG_RETURN(result); + + while (true) + { + if ((result= ph_rnd_next_in_part(read_part_id, m_table->record[0]))) + { + if (result == HA_ERR_RECORD_DELETED) + continue; + if (result != HA_ERR_END_OF_FILE) + break; + + if (num_misplaced_rows > 0) + { + if (repair) + { + if (num_deleted_rows > 0) + { + print_admin_msg(thd, MI_MAX_MSG_BUF, "warning", + m_table->s->db.str, m_table->alias, + opt_op_name[REPAIR_PARTS], + "Moved %lld misplaced rows, deleted %lld rows", + num_misplaced_rows - num_deleted_rows, + num_deleted_rows); + } + else + { + print_admin_msg(thd, MI_MAX_MSG_BUF, "warning", + m_table->s->db.str, m_table->alias, + opt_op_name[REPAIR_PARTS], + "Moved %lld misplaced rows", + num_misplaced_rows); + } + } + else + { + print_admin_msg(thd, MI_MAX_MSG_BUF, "error", + m_table->s->db.str, m_table->alias, + opt_op_name[CHECK_PARTS], + "Found %lld misplaced rows in partition %u", + num_misplaced_rows, + read_part_id); + } + } + /* End-of-file reached, all rows are now OK, reset result and break. */ + result= 0; + break; + } + + result= m_part_info->get_partition_id(m_part_info, &correct_part_id, + &func_value); + // TODO: Add code to delete rows not matching any partition. + if (result) + break; + + if (correct_part_id != read_part_id) + { + num_misplaced_rows++; + m_err_rec= NULL; + if (!repair) + { + /* Check. */ + result= HA_ADMIN_NEEDS_UPGRADE; + char buf[MAX_KEY_LENGTH]; + String str(buf,sizeof(buf),system_charset_info); + str.length(0); + append_row_to_str(str, m_err_rec, m_table); + print_admin_msg(thd, MI_MAX_MSG_BUF, "error", + m_table->s->db.str, m_table->alias, + opt_op_name[CHECK_PARTS], + "Found a misplaced row" + " in part %d should be in part %d:\n%s", + read_part_id, + correct_part_id, + str.c_ptr_safe()); + /* Break on first misplaced row, unless ignore is given! */ + if (!ignore) + break; + } + else + { + DBUG_PRINT("info", ("Moving row from partition %d to %d", + read_part_id, correct_part_id)); + + /* + Insert row into correct partition. Notice that there are no commit + for every N row, so the repair will be one large transaction! + */ + if ((result= write_row_in_part(correct_part_id, m_table->record[0]))) + { + /* + We have failed to insert a row, it might have been a duplicate! + */ + char buf[MAX_KEY_LENGTH]; + String str(buf,sizeof(buf),system_charset_info); + str.length(0); + if (result == HA_ERR_FOUND_DUPP_KEY) + { + if (ignore) + { + str.append("Duplicate key found, deleting the record:\n"); + num_deleted_rows++; + } + else + { + str.append("Duplicate key found, " + "please update or delete the record:\n"); + result= HA_ADMIN_CORRUPT; + } + } + append_row_to_str(str, m_err_rec, m_table); + + /* + If the engine supports transactions, the failure will be + rollbacked. + */ + if (!m_handler->has_transactions() || + ignore || result == HA_ADMIN_CORRUPT) + { + /* Log this error, so the DBA can notice it and fix it! */ + sql_print_error("Table '%-192s' failed to move/insert a row" + " from part %d into part %d:\n%s", + m_table->s->table_name.str, + read_part_id, + correct_part_id, + str.c_ptr_safe()); + } + print_admin_msg(thd, MI_MAX_MSG_BUF, "error", + m_table->s->db.str, m_table->alias, + opt_op_name[REPAIR_PARTS], + "Failed to move/insert a row" + " from part %d into part %d:\n%s", + read_part_id, + correct_part_id, + str.c_ptr_safe()); + if (!ignore || result != HA_ERR_FOUND_DUPP_KEY) + break; + } + + /* Delete row from wrong partition. */ + if ((result= delete_row_in_part(read_part_id, m_table->record[0]))) + { + result= HA_ADMIN_CORRUPT; + if (m_handler->has_transactions()) + break; + /* + We have introduced a duplicate, since we failed to remove it + from the wrong partition. + */ + char buf[MAX_KEY_LENGTH]; + String str(buf,sizeof(buf),system_charset_info); + str.length(0); + append_row_to_str(str, m_err_rec, m_table); + + /* Log this error, so the DBA can notice it and fix it! */ + sql_print_error("Table '%-192s': Delete from part %d failed with" + " error %d. But it was already inserted into" + " part %d, when moving the misplaced row!" + "\nPlease manually fix the duplicate row:\n%s", + m_table->s->table_name.str, + read_part_id, + result, + correct_part_id, + str.c_ptr_safe()); + break; + } + } + } + } + + int tmp_result= rnd_end_in_part(read_part_id, true); + DBUG_RETURN(result ? result : tmp_result); +} + +/** + Read next row during full partition scan (scan in random row order). + + This function can evaluate the virtual generated columns. If virtual + generated columns are involved, you should not call rnd_next_in_part + directly but this one. + + @param part_id Partition to read from. + @param[in,out] buf buffer that should be filled with data. + + @return Operation status. + @retval 0 Success + @retval != 0 Error code +*/ + +int Partition_helper::ph_rnd_next_in_part(uint part_id, uchar *buf) +{ + int result= rnd_next_in_part(part_id, buf); + +#if 0 + if (!result && m_table->has_gcol()) + result= update_generated_read_fields(buf, m_table); +#endif + + return result; +} + + +/** Set used partitions bitmap from Alter_info. + + @return false if success else true. +*/ + +bool Partition_helper::set_altered_partitions() +{ + Alter_info *alter_info= &get_thd()->lex->alter_info; + + if ((alter_info->flags & Alter_info::ALTER_ADMIN_PARTITION) == 0 || + (alter_info->flags & Alter_info::ALTER_ALL_PARTITION)) + { + /* + Full table command, not ALTER TABLE t PARTITION . + All partitions are already set, so do nothing. + */ + return false; + } + return m_part_info->set_read_partitions(&alter_info->partition_names); +} + +#if 0 +/** + Print a message row formatted for ANALYZE/CHECK/OPTIMIZE/REPAIR TABLE. + + Modeled after mi_check_print_msg. + + @param thd Thread context. + @param len Needed length for message buffer. + @param msg_type Message type. + @param db_name Database name. + @param table_name Table name. + @param op_name Operation name. + @param fmt Message (in printf format with additional arguments). + + @return Operation status. + @retval false for success else true. +*/ + +bool Partition_helper::print_admin_msg(THD* thd, + uint len, + const char *msg_type, + const char *db_name, + const char *table_name, + const char *op_name, + const char *fmt, + ...) +{ + va_list args; + Protocol *protocol= thd->protocol; + uint length; + size_t msg_length; + char name[NAME_LEN*2+2]; + char *msgbuf; + bool error= true; + + if (!(msgbuf= (char*) my_malloc(len, MYF(0)))) + return true; + va_start(args, fmt); + msg_length= my_vsnprintf(msgbuf, len, fmt, args); + va_end(args); + if (msg_length >= (len - 1)) + goto err; + msgbuf[len - 1] = 0; // healthy paranoia + + if (!thd->protocol->connection_alive()) + { + sql_print_error("%s", msgbuf); + goto err; + } + + length=(uint) (strxmov(name, db_name, ".", table_name,NullS) - name); + /* + TODO: switch from protocol to push_warning here. The main reason we didn't + it yet is parallel repair. Due to following trace: + mi_check_print_msg/push_warning/sql_alloc/my_pthread_getspecific_ptr. + + Also we likely need to lock mutex here (in both cases with protocol and + push_warning). + */ + DBUG_PRINT("info",("print_admin_msg: %s, %s, %s, %s", name, op_name, + msg_type, msgbuf)); + protocol->start_row(); + protocol->store(name, length, system_charset_info); + protocol->store(op_name, system_charset_info); + protocol->store(msg_type, system_charset_info); + protocol->store(msgbuf, msg_length, system_charset_info); + if (protocol->end_row()) + { + sql_print_error("Failed on my_net_write, writing to stderr instead: %s\n", + msgbuf); + goto err; + } + error= false; +err: + my_free(msgbuf); + return error; +} +#endif + + +/** + Set table->read_set taking partitioning expressions into account. + + @param[in] rnd_init True if called from rnd_init (else index_init). +*/ + +inline +void Partition_helper::set_partition_read_set() +{ + /* + For operations that may need to change data, we may need to extend + read_set. + */ + if (m_handler->get_lock_type() == F_WRLCK) + { + /* + If write_set contains any of the fields used in partition and + subpartition expression, we need to set all bits in read_set because + the row may need to be inserted in a different [sub]partition. In + other words update_row() can be converted into write_row(), which + requires a complete record. + */ + if (bitmap_is_overlapping(&m_part_info->full_part_field_set, + m_table->write_set)) + { + bitmap_set_all(m_table->read_set); + } + else + { + /* + Some handlers only read fields as specified by the bitmap for the + read set. For partitioned handlers we always require that the + fields of the partition functions are read such that we can + calculate the partition id to place updated and deleted records. + */ + bitmap_union(m_table->read_set, &m_part_info->full_part_field_set); + } + // Mark virtual generated columns writable + for (Field **vf= m_table->vfield; vf && *vf; vf++) + { + if (bitmap_is_set(m_table->read_set, (*vf)->field_index)) + bitmap_set_bit(m_table->write_set, (*vf)->field_index); + } + } +} + + +/**************************************************************************** + MODULE full table scan +****************************************************************************/ + +/** + Initialize engine for random reads. + + rnd_init() is called when the server wants the storage engine to do a + table scan or when the server wants to access data through rnd_pos. + + When scan is used we will scan one handler partition at a time. + When preparing for rnd_pos we will initialize all handler partitions. + No extra cache handling is needed when scanning is not performed. + + Before initializing we will call rnd_end to ensure that we clean up from + any previous incarnation of a table scan. + + @param scan false for initialize for random reads through rnd_pos() + true for initialize for random scan through rnd_next(). + + @return Operation status. + @retval 0 Success + @retval != 0 Error code +*/ + +int Partition_helper::ph_rnd_init(bool scan) +{ + int error; + uint i= 0; + uint part_id; + DBUG_ENTER("Partition_helper::ph_rnd_init"); + + set_partition_read_set(); + + /* Now we see what the index of our first important partition is */ + DBUG_PRINT("info", ("m_part_info->read_partitions: 0x%lx", + (long) m_part_info->read_partitions.bitmap)); + part_id= m_part_info->get_first_used_partition(); + DBUG_PRINT("info", ("m_part_spec.start_part %d", part_id)); + + if (MY_BIT_NONE == part_id) + { + error= 0; + goto err1; + } + + DBUG_PRINT("info", ("rnd_init on partition %d", part_id)); + if (scan) + { + /* A scan can be restarted without rnd_end() in between! */ + if (m_scan_value == 1 && m_part_spec.start_part != NOT_A_PARTITION_ID) + { + /* End previous scan on partition before restart. */ + if ((error= rnd_end_in_part(m_part_spec.start_part, scan))) + { + DBUG_RETURN(error); + } + } + m_scan_value= 1; + if ((error= rnd_init_in_part(part_id, scan))) + goto err; + } + else + { + m_scan_value= 0; + for (i= part_id; + i < MY_BIT_NONE; + i= m_part_info->get_next_used_partition(i)) + { + if ((error= rnd_init_in_part(i, scan))) + goto err; + } + } + m_part_spec.start_part= part_id; + m_part_spec.end_part= m_tot_parts - 1; + DBUG_PRINT("info", ("m_scan_value=%d", m_scan_value)); + DBUG_RETURN(0); + +err: + /* Call rnd_end for all previously initialized partitions. */ + for (; + part_id < i; + part_id= m_part_info->get_next_used_partition(part_id)) + { + rnd_end_in_part(part_id, scan); + } +err1: + m_scan_value= 2; + m_part_spec.start_part= NO_CURRENT_PART_ID; + DBUG_RETURN(error); +} + + +/** + End of a table scan. + + @return Operation status. + @retval 0 Success + @retval != 0 Error code +*/ + +int Partition_helper::ph_rnd_end() +{ + int error= 0; + DBUG_ENTER("Partition_helper::ph_rnd_end"); + switch (m_scan_value) { + case 3: // Error + DBUG_ASSERT(0); + /* fall through. */ + case 2: // Error + break; + case 1: + if (NO_CURRENT_PART_ID != m_part_spec.start_part) // Table scan + { + error= rnd_end_in_part(m_part_spec.start_part, true); + } + break; + case 0: + uint i; + for (i= m_part_info->get_first_used_partition(); + i < MY_BIT_NONE; + i= m_part_info->get_next_used_partition(i)) + { + int part_error; + part_error= rnd_end_in_part(i, false); + if (part_error && !error) { + error= part_error; + } + } + break; + } + m_scan_value= 3; + m_part_spec.start_part= NO_CURRENT_PART_ID; + DBUG_RETURN(error); +} + + +/** + Read next row during full table scan (scan in random row order). + + This is called for each row of the table scan. When you run out of records + you should return HA_ERR_END_OF_FILE. + The Field structure for the table is the key to getting data into buf + in a manner that will allow the server to understand it. + + @param[out] buf buffer that should be filled with data. + + @return Operation status. + @retval 0 Success + @retval != 0 Error code +*/ + +int Partition_helper::ph_rnd_next(uchar *buf) +{ + int result= HA_ERR_END_OF_FILE; + uint part_id= m_part_spec.start_part; + DBUG_ENTER("Partition_helper::ph_rnd_next"); + + if (NO_CURRENT_PART_ID == part_id) + { + /* + The original set of partitions to scan was empty and thus we report + the result here. + */ + goto end; + } + + DBUG_ASSERT(m_scan_value == 1); + + while (TRUE) + { + result= rnd_next_in_part(part_id, buf); + if (!result) + { + m_last_part= part_id; + m_part_spec.start_part= part_id; + m_table->status= 0; + DBUG_RETURN(0); + } + + /* + if we get here, then the current partition ha_rnd_next returned failure + */ + if (result == HA_ERR_RECORD_DELETED) + continue; // Probably MyISAM + + if (result != HA_ERR_END_OF_FILE) + goto end_dont_reset_start_part; // Return error + + /* End current partition */ + DBUG_PRINT("info", ("rnd_end on partition %d", part_id)); + if ((result= rnd_end_in_part(part_id, true))) + break; + + /* Shift to next partition */ + part_id= m_part_info->get_next_used_partition(part_id); + if (part_id >= m_tot_parts) + { + result= HA_ERR_END_OF_FILE; + break; + } + m_last_part= part_id; + m_part_spec.start_part= part_id; + DBUG_PRINT("info", ("rnd_init on partition %d", part_id)); + if ((result= rnd_init_in_part(part_id, true))) + break; + } + +end: + m_part_spec.start_part= NO_CURRENT_PART_ID; +end_dont_reset_start_part: + m_table->status= STATUS_NOT_FOUND; + DBUG_RETURN(result); +} + + +/** + Save position of current row. + + position() is called after each call to rnd_next() if the data needs + to be ordered or accessed later. + + The server uses ref to store data. ref_length in the above case is + the size needed to store current_position. ref is just a byte array + that the server will maintain. If you are using offsets to mark rows, then + current_position should be the offset. If it is a primary key like in + InnoDB, then it needs to be a primary key. + + @param record Current record in MySQL Row Format. +*/ + +void Partition_helper::ph_position(const uchar *record) +{ + DBUG_ASSERT(m_part_info->is_partition_used(m_last_part)); + DBUG_ENTER("Partition_helper::ph_position"); + DBUG_PRINT("info", ("record: %p", record)); + DBUG_DUMP("record", record, m_rec_length); + + /* + If m_ref_usage is set, then the ref is already stored in the + priority queue (m_queue) when doing ordered scans. + */ + if (m_ref_usage != REF_NOT_USED && m_ordered_scan_ongoing) + { + DBUG_ASSERT(!m_queue->empty()); + DBUG_ASSERT(m_ordered_rec_buffer); + DBUG_ASSERT(!m_curr_key_info[1]); + DBUG_ASSERT(uint2korr(m_queue->top()) == m_last_part); + /* We already have the ref and part id. */ + memcpy(m_handler->ref, m_queue->top(), m_handler->ref_length); + } + else + { + DBUG_PRINT("info", ("m_last_part: %u", m_last_part)); + int2store(m_handler->ref, m_last_part); + position_in_last_part(m_handler->ref + PARTITION_BYTES_IN_POS, record); + } + DBUG_DUMP("ref_out", m_handler->ref, m_handler->ref_length); + + DBUG_VOID_RETURN; +} + + +/** + Read row using position. + + This is like rnd_next, but you are given a position to use to determine + the row. The position will be pointing to data of length handler::ref_length + that handler::ref was set by position(record). Tables clustered on primary + key usually use the full primary key as reference (like InnoDB). Heap based + tables usually returns offset in heap file (like MyISAM). + + @param[out] buf buffer that should be filled with record in MySQL format. + @param[in] pos position given as handler::ref when position() was called. + + @return Operation status. + @retval 0 Success + @retval != 0 Error code +*/ + +int Partition_helper::ph_rnd_pos(uchar *buf, uchar *pos) +{ + uint part_id; + DBUG_ENTER("Partition_helper::ph_rnd_pos"); + + part_id= uint2korr(pos); + DBUG_ASSERT(part_id < m_tot_parts); + DBUG_ASSERT(m_part_info->is_partition_used(part_id)); + m_last_part= part_id; + DBUG_RETURN(rnd_pos_in_part(part_id, buf, (pos + PARTITION_BYTES_IN_POS))); +} + + +/** + Read row using position using given record to find. + + This works as position()+rnd_pos() functions, but does some extra work, + calculating m_last_part - the partition to where the 'record' should go. + + Only useful when position is based on primary key + (HA_PRIMARY_KEY_REQUIRED_FOR_POSITION). + + @param record Current record in MySQL Row Format. + + @return Operation status. + @retval 0 Success + @retval != 0 Error code +*/ + +int Partition_helper::ph_rnd_pos_by_record(uchar *record) +{ + DBUG_ENTER("Partition_helper::ph_rnd_pos_by_record"); + + DBUG_ASSERT(m_handler->ha_table_flags() & + HA_PRIMARY_KEY_REQUIRED_FOR_POSITION); + /* TODO: Support HA_READ_BEFORE_WRITE_REMOVAL */ + /* Set m_last_part correctly. */ + if (unlikely(get_part_for_delete(record, + m_table->record[0], + m_part_info, + &m_last_part))) + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + + DBUG_RETURN(rnd_pos_by_record_in_last_part(record)); +} + + +/**************************************************************************** + MODULE index scan +****************************************************************************/ +/* + Positions an index cursor to the index specified in the handle. Fetches the + row if available. If the key value is null, begin at the first key of the + index. + + There are loads of optimizations possible here for the partition handler. + The same optimizations can also be checked for full table scan although + only through conditions and not from index ranges. + Phase one optimizations: + Check if the fields of the partition function are bound. If so only use + the single partition it becomes bound to. + Phase two optimizations: + If it can be deducted through range or list partitioning that only a + subset of the partitions are used, then only use those partitions. +*/ + +/** + Setup the ordered record buffer and the priority queue. + + Call destroy_record_priority_queue() to deallocate or clean-up + from failure. + + @return false on success, else true. +*/ + +int Partition_helper::init_record_priority_queue() +{ + uint used_parts= m_part_info->num_partitions_used(); + DBUG_ENTER("Partition_helper::init_record_priority_queue"); + DBUG_ASSERT(!m_ordered_rec_buffer); + DBUG_ASSERT(!m_queue); + /* Initialize the priority queue. */ + // TODO: Create test to see the cost of allocating when needed vs + // allocate once and keep between statements. Also test on NUMA + // machines to see the difference (I guess that allocating when needed + // will allocate on 'correct' NUMA node and be faster.) + if (!m_queue) + { + m_queue= new (std::nothrow) Prio_queue(Key_rec_less(m_curr_key_info)); + if (!m_queue) + { + DBUG_RETURN(HA_ERR_OUT_OF_MEM); + } + } + /* Initialize the ordered record buffer. */ + if (!m_ordered_rec_buffer) + { + uint alloc_len; + /* + Allocate record buffer for each used partition. + If PK is clustered index, it is either the primary sort key or is + added as secondary sort. So we only need to allocate for part id + and a full record per partition. + Otherwise if the clustered index was generated, we might need to + do a secondary sort by rowid (handler::ref) and must allocate for + ref (includes part id) and full record per partition. We don't + know yet if we need to do secondary sort by rowid, so we must + allocate space for it. + TODO: enhance ha_index_init() for HA_EXTRA_SECONDARY_SORT_ROWID to + avoid allocating space for handler::ref when not needed. + When enhancing ha_index_init() care must be taken on ph_position(), + so InnoDB's row_id is correctly handled (taken from m_last_part). + */ + if (m_pkey_is_clustered && m_table->s->primary_key != MAX_KEY) + { + m_rec_offset= PARTITION_BYTES_IN_POS; + m_ref_usage= REF_NOT_USED; + } + else + { + m_rec_offset= m_handler->ref_length; + m_ref_usage= REF_STORED_IN_PQ; + } + alloc_len= used_parts * (m_rec_offset + m_rec_length); + /* Allocate a key for temporary use when setting up the scan. */ + alloc_len+= m_table->s->max_key_length; + + m_ordered_rec_buffer= static_cast( + my_malloc(alloc_len, + MYF(MY_WME))); + if (!m_ordered_rec_buffer) + { + DBUG_RETURN(HA_ERR_OUT_OF_MEM); + } + + /* + We set-up one record per partition and each record has 2 bytes in + front where the partition id is written. This is used by ordered + index_read. + If we need to also sort by rowid (handler::ref), then m_curr_key_info[1] + is NULL and we add the rowid before the record. + We also set-up a reference to the first record for temporary use in + setting up the scan. + */ + char *ptr= (char*) m_ordered_rec_buffer; + uint i; + for (i= m_part_info->get_first_used_partition(); + i < MY_BIT_NONE; + i= m_part_info->get_next_used_partition(i)) + { + DBUG_PRINT("info", ("init rec-buf for part %u", i)); + int2store(ptr, i); + ptr+= m_rec_offset + m_rec_length; + } + m_start_key.key= (const uchar*)ptr; + /* + Initialize priority queue, initialized to reading forward. + Start by only sort by KEY, HA_EXTRA_SECONDARY_SORT_ROWID + will be given if we should sort by handler::ref too. + */ + m_queue->m_rec_offset= m_rec_offset; + if (m_queue->reserve(used_parts)) + { + DBUG_RETURN(HA_ERR_OUT_OF_MEM); + } + } + DBUG_RETURN(init_record_priority_queue_for_parts(used_parts)); +} + + +/** + Destroy the ordered record buffer and the priority queue. +*/ + +void Partition_helper::destroy_record_priority_queue() +{ + DBUG_ENTER("Partition_helper::destroy_record_priority_queue"); + if (m_ordered_rec_buffer) + { + my_free(m_ordered_rec_buffer); + m_ordered_rec_buffer= NULL; + } + if (m_queue) + { + m_queue->clear(); + delete m_queue; + m_queue= NULL; + } + m_ref_usage= REF_NOT_USED; + m_ordered_scan_ongoing= false; + DBUG_VOID_RETURN; +} + + +/** + Common setup for index_init. + + Set up variables and initialize the record priority queue. + + @param inx Index to be used. + @param sorted True if the rows must be returned in index order. + + @return Operation status. + @retval 0 Success + @retval != 0 Error code +*/ + +int Partition_helper::ph_index_init_setup(uint inx, bool sorted) +{ + DBUG_ENTER("Partition_helper:ph_:index_init_setup"); + + DBUG_ASSERT(inx != MAX_KEY); + DBUG_PRINT("info", ("inx %u sorted %u", inx, sorted)); + m_part_spec.start_part= NO_CURRENT_PART_ID; + m_start_key.length= 0; + m_ordered= sorted; + m_ref_usage= REF_NOT_USED; + m_curr_key_info[0]= m_table->key_info+inx; + m_curr_key_info[1]= NULL; + /* + There are two cases where it is not enough to only sort on the key: + 1) For clustered indexes, the optimizer assumes that all keys + have the rest of the PK columns appended to the KEY, so it will + sort by PK as secondary sort key. + 2) Rowid-Order-Retrieval access methods, like index_merge_intersect + and index_merge_union. These methods requires the index to be sorted + on rowid (handler::ref) as secondary sort key. + */ + if (m_pkey_is_clustered && m_table->s->primary_key != MAX_KEY && + inx != m_table->s->primary_key) + { + /* + if PK is clustered, then the key cmp must use the pk to + differentiate between equal key in given index. + */ + DBUG_PRINT("info", ("Clustered pk, using pk as secondary cmp")); + m_curr_key_info[1]= m_table->key_info+m_table->s->primary_key; + } + + /* + Some handlers only read fields as specified by the bitmap for the + read set. For partitioned handlers we always require that the + fields of the partition functions are read such that we can + calculate the partition id to place updated and deleted records. + */ + if (m_handler->get_lock_type() == F_WRLCK) + bitmap_union(m_table->read_set, &m_part_info->full_part_field_set); + + DBUG_RETURN(0); +} + + +/** + Initialize handler before start of index scan. + + index_init is always called before starting index scans (except when + starting through index_read_idx and using read_range variants). + + @param inx Index number. + @param sorted Is rows to be returned in sorted order. + + @return Operation status + @retval 0 Success + @retval != 0 Error code +*/ + +int Partition_helper::ph_index_init(uint inx, bool sorted) +{ + int error; + uint part_id= m_part_info->get_first_used_partition(); + DBUG_ENTER("Partition_helper::ph_index_init"); + m_handler->active_index= inx; + + if (part_id == MY_BIT_NONE) + { + DBUG_RETURN(0); + } + + if ((error= ph_index_init_setup(inx, sorted))) + { + DBUG_RETURN(error); + } + if ((error= init_record_priority_queue())) + { + destroy_record_priority_queue(); + DBUG_RETURN(error); + } + + for (/* part_id already set. */; + part_id < MY_BIT_NONE; + part_id= m_part_info->get_next_used_partition(part_id)) + { + if ((error= index_init_in_part(part_id, inx, sorted))) + goto err; + + DBUG_EXECUTE_IF("partition_fail_index_init", { + part_id++; + error= HA_ERR_NO_PARTITION_FOUND; + goto err; + }); + } +err: + if (error) + { + /* End the previously initialized indexes. */ + uint j; + for (j= m_part_info->get_first_used_partition(); + j < part_id; + j= m_part_info->get_next_used_partition(j)) + { + (void) index_end_in_part(j); + } + destroy_record_priority_queue(); + } + DBUG_RETURN(error); +} + + +/** + End of index scan. + + index_end is called at the end of an index scan to clean up any + things needed to clean up. + + @return Operation status. + @retval 0 Success + @retval != 0 Error code +*/ + +int Partition_helper::ph_index_end() +{ + int error= 0; + uint i; + DBUG_ENTER("Partition_helper::ph_index_end"); + + m_part_spec.start_part= NO_CURRENT_PART_ID; + m_ref_usage= REF_NOT_USED; + for (i= m_part_info->get_first_used_partition(); + i < MY_BIT_NONE; + i= m_part_info->get_next_used_partition(i)) + { + int tmp; + if ((tmp= index_end_in_part(i))) + error= tmp; + } + destroy_record_priority_queue(); + m_handler->active_index= MAX_KEY; + DBUG_RETURN(error); +} + + +/** + Read one record in an index scan and start an index scan. + + index_read_map starts a new index scan using a start key. The MySQL Server + will check the end key on its own. Thus to function properly the + partitioned handler need to ensure that it delivers records in the sort + order of the MySQL Server. + index_read_map can be restarted without calling index_end on the previous + index scan and without calling index_init. In this case the index_read_map + is on the same index as the previous index_scan. This is particularly + used in conjunction with multi read ranges. + + @param[out] buf Read row in MySQL Row Format + @param[in] key Key parts in consecutive order + @param[in] keypart_map Which part of key is used + @param[in] find_flag What type of key condition is used + + @return Operation status. + @retval 0 Success + @retval != 0 Error code +*/ + +int Partition_helper::ph_index_read_map(uchar *buf, + const uchar *key, + key_part_map keypart_map, + enum ha_rkey_function find_flag) +{ + DBUG_ENTER("Partition_handler::ph_index_read_map"); + m_handler->end_range= NULL; + m_index_scan_type= PARTITION_INDEX_READ; + m_start_key.key= key; + m_start_key.keypart_map= keypart_map; + m_start_key.flag= find_flag; + DBUG_RETURN(common_index_read(buf, true)); +} + + +/** + Common routine for a number of index_read variants. + + @param[out] buf Buffer where the record should be returned. + @param[in] have_start_key TRUE <=> the left endpoint is available, i.e. + we're in index_read call or in read_range_first + call and the range has left endpoint. + FALSE <=> there is no left endpoint (we're in + read_range_first() call and the range has no left + endpoint). + + @return Operation status + @retval 0 OK + @retval HA_ERR_END_OF_FILE Whole index scanned, without finding the record. + @retval HA_ERR_KEY_NOT_FOUND Record not found, but index cursor positioned. + @retval other Error code. + + @details + Start scanning the range (when invoked from read_range_first()) or doing + an index lookup (when invoked from index_read_XXX): + - If possible, perform partition selection + - Find the set of partitions we're going to use + - Depending on whether we need ordering: + NO: Get the first record from first used partition (see + handle_unordered_scan_next_partition) + YES: Fill the priority queue and get the record that is the first in + the ordering +*/ + +int Partition_helper::common_index_read(uchar *buf, bool have_start_key) +{ + int error; + m_reverse_order= false; + DBUG_ENTER("Partition_helper::common_index_read"); + + DBUG_PRINT("info", ("m_ordered %u m_ordered_scan_ong %u", + m_ordered, m_ordered_scan_ongoing)); + + if (have_start_key) + { + m_start_key.length= calculate_key_len(m_table, + m_handler->active_index, + NULL, + m_start_key.keypart_map); + DBUG_PRINT("info", ("have_start_key map %lu find_flag %u len %u", + m_start_key.keypart_map, m_start_key.flag, + m_start_key.length)); + DBUG_ASSERT(m_start_key.length); + } + if ((error= partition_scan_set_up(buf, have_start_key))) + { + DBUG_RETURN(error); + } + + if (have_start_key && + (m_start_key.flag == HA_READ_KEY_OR_PREV || + m_start_key.flag == HA_READ_PREFIX_LAST || + m_start_key.flag == HA_READ_PREFIX_LAST_OR_PREV || + m_start_key.flag == HA_READ_BEFORE_KEY)) + { + m_reverse_order= true; + m_ordered_scan_ongoing= true; + } + DBUG_PRINT("info", ("m_ordered %u m_o_scan_ong %u have_start_key %u", + m_ordered, m_ordered_scan_ongoing, have_start_key)); + if (!m_ordered_scan_ongoing) + { + /* + We use unordered index scan when read_range is used and flag + is set to not use ordered. + We also use an unordered index scan when the number of partitions to + scan is only one. + The unordered index scan will use the partition set created. + */ + DBUG_PRINT("info", ("doing unordered scan")); + error= handle_unordered_scan_next_partition(buf); + } + else + { + /* + In all other cases we will use the ordered index scan. This will use + the partition set created by the get_partition_set method. + */ + error= handle_ordered_index_scan(buf); + } + DBUG_RETURN(error); +} + + +/** + Start an index scan from leftmost record and return first record. + + index_first() asks for the first key in the index. + This is similar to index_read except that there is no start key since + the scan starts from the leftmost entry and proceeds forward with + index_next. + + @param[out] buf Read row in MySQL Row Format. + + @return Operation status. + @retval 0 Success + @retval != 0 Error code +*/ + +int Partition_helper::ph_index_first(uchar *buf) +{ + DBUG_ENTER("Partition_helper::ph_index_first"); + + m_handler->end_range= NULL; + m_index_scan_type= PARTITION_INDEX_FIRST; + m_reverse_order= false; + DBUG_RETURN(common_first_last(buf)); +} + + +/** + Start an index scan from rightmost record and return first record. + + index_last() asks for the last key in the index. + This is similar to index_read except that there is no start key since + the scan starts from the rightmost entry and proceeds forward with + index_prev. + + @param[out] buf Read row in MySQL Row Format. + + @return Operation status. + @retval 0 Success + @retval != 0 Error code +*/ + +int Partition_helper::ph_index_last(uchar *buf) +{ + DBUG_ENTER("Partition_helper::ph_index_last"); + + m_index_scan_type= PARTITION_INDEX_LAST; + m_reverse_order= true; + DBUG_RETURN(common_first_last(buf)); +} + + +/** + Common routine for index_first/index_last. + + @param[out] buf Read row in MySQL Row Format. + + @return Operation status. + @retval 0 Success + @retval != 0 Error code +*/ + +int Partition_helper::common_first_last(uchar *buf) +{ + int error; + DBUG_ENTER("Partition_helper::common_first_last"); + + if ((error= partition_scan_set_up(buf, false))) + { + DBUG_RETURN(error); + } + if (!m_ordered_scan_ongoing && + m_index_scan_type != PARTITION_INDEX_LAST) + { + DBUG_RETURN(handle_unordered_scan_next_partition(buf)); + } + DBUG_RETURN(handle_ordered_index_scan(buf)); +} + + +/** + Read last using key. + + This is used in join_read_last_key to optimize away an ORDER BY. + Can only be used on indexes supporting HA_READ_ORDER. + + @param[out] buf Read row in MySQL Row Format + @param[in] key Key + @param[in] keypart_map Which part of key is used + + @return Operation status. + @retval 0 Success + @retval != 0 Error code +*/ + +int Partition_helper::ph_index_read_last_map(uchar *buf, + const uchar *key, + key_part_map keypart_map) +{ + DBUG_ENTER("Partition_helper::ph_index_read_last_map"); + + m_ordered= true; // Safety measure + m_handler->end_range= NULL; + m_index_scan_type= PARTITION_INDEX_READ_LAST; + m_start_key.key= key; + m_start_key.keypart_map= keypart_map; + m_start_key.flag= HA_READ_PREFIX_LAST; + DBUG_RETURN(common_index_read(buf, true)); +} + + +/** + Read index by key and keymap. + + Positions an index cursor to the index specified. + Fetches the row if available. If the key value is null, + begin at first key of the index. + + Optimization of the default implementation to take advantage of dynamic + partition pruning. + + @param[out] buf Read row in MySQL Row Format + @param[in] index Index to read from + @param[in] key Key + @param[in] keypart_map Which part of key is used + @param[in] find_flag Direction/how to search. + + @return Operation status. + @retval 0 Success + @retval != 0 Error code +*/ +int Partition_helper::ph_index_read_idx_map(uchar *buf, + uint index, + const uchar *key, + key_part_map keypart_map, + enum ha_rkey_function find_flag) +{ + int error= HA_ERR_KEY_NOT_FOUND; + DBUG_ENTER("Partition_helper::ph_index_read_idx_map"); + + if (find_flag == HA_READ_KEY_EXACT) + { + uint part; + m_start_key.key= key; + m_start_key.keypart_map= keypart_map; + m_start_key.flag= find_flag; + m_start_key.length= calculate_key_len(m_table, + index, + NULL, + m_start_key.keypart_map); + + get_partition_set(m_table, buf, index, &m_start_key, &m_part_spec); + + /* + We have either found exactly 1 partition + (in which case start_part == end_part) + or no matching partitions (start_part > end_part) + */ + DBUG_ASSERT(m_part_spec.start_part >= m_part_spec.end_part); + /* The start part is must be marked as used. */ + DBUG_ASSERT(m_part_spec.start_part > m_part_spec.end_part || + m_part_info->is_partition_used(m_part_spec.start_part)); + + for (part= m_part_spec.start_part; + part <= m_part_spec.end_part; + part= m_part_info->get_next_used_partition(part)) + { + error= index_read_idx_map_in_part(part, + buf, + index, + key, + keypart_map, + find_flag); + if (error != HA_ERR_KEY_NOT_FOUND && + error != HA_ERR_END_OF_FILE) + { + break; + } + } + if (part <= m_part_spec.end_part) + { + m_last_part= part; + } + } + else + { + /* + If not only used with HA_READ_KEY_EXACT, we should investigate if + possible to optimize for other find_flag's as well. + */ + DBUG_ASSERT(0); + error= HA_ERR_INTERNAL_ERROR; + } + DBUG_RETURN(error); +} + + +/** + Read next record in a forward index scan. + + Used to read forward through the index (left to right, low to high). + + @param[out] buf Read row in MySQL Row Format. + + @return Operation status. + @retval 0 Success + @retval != 0 Error code +*/ + +int Partition_helper::ph_index_next(uchar *buf) +{ + DBUG_ENTER("Partition_helper::ph_index_next"); + + /* + TODO(low priority): + If we want partition to work with the HANDLER commands, we + must be able to do index_last() -> index_prev() -> index_next() + and if direction changes, we must step back those partitions in + the record queue so we don't return a value from the wrong direction. + */ + DBUG_ASSERT(m_index_scan_type != PARTITION_INDEX_LAST || + m_table->open_by_handler); + if (!m_ordered_scan_ongoing) + { + DBUG_RETURN(handle_unordered_next(buf, false)); + } + DBUG_RETURN(handle_ordered_next(buf, false)); +} + + +/** + Read next same record. + + This routine is used to read the next but only if the key is the same + as supplied in the call. + + @param[out] buf Read row in MySQL Row Format. + @param[in] key Key. + @param[in] keylen Length of key. + + @return Operation status. + @retval 0 Success + @retval != 0 Error code +*/ + +int Partition_helper::ph_index_next_same(uchar *buf, const uchar *key, uint keylen) +{ + DBUG_ENTER("Partition_helper::ph_index_next_same"); + + DBUG_ASSERT(keylen == m_start_key.length); + DBUG_ASSERT(m_index_scan_type != PARTITION_INDEX_LAST); + if (!m_ordered_scan_ongoing) + DBUG_RETURN(handle_unordered_next(buf, true)); + DBUG_RETURN(handle_ordered_next(buf, true)); +} + + +/** + Read next record when performing index scan backwards. + + Used to read backwards through the index (right to left, high to low). + + @param[out] buf Read row in MySQL Row Format. + + @return Operation status. + @retval 0 Success + @retval != 0 Error code +*/ + +int Partition_helper::ph_index_prev(uchar *buf) +{ + DBUG_ENTER("Partition_helper::ph_index_prev"); + + /* TODO: read comment in index_next */ + DBUG_ASSERT(m_index_scan_type != PARTITION_INDEX_FIRST || + m_table->open_by_handler); + DBUG_RETURN(handle_ordered_prev(buf)); +} + + +/** + Start a read of one range with start and end key. + + We re-implement read_range_first since we don't want the compare_key + check at the end. This is already performed in the partition handler. + read_range_next is very much different due to that we need to scan + all underlying handlers. + + @param start_key Specification of start key. + @param end_key Specification of end key. + @param eq_range_arg Is it equal range. + @param sorted Should records be returned in sorted order. + + @return Operation status. + @retval 0 Success + @retval != 0 Error code +*/ + +int Partition_helper::ph_read_range_first(const key_range *start_key, + const key_range *end_key, + bool eq_range_arg, + bool sorted) +{ + int error= HA_ERR_END_OF_FILE; + bool have_start_key= (start_key != NULL); + uint part_id= m_part_info->get_first_used_partition(); + DBUG_ENTER("Partition_helper::ph_read_range_first"); + + if (part_id == MY_BIT_NONE) + { + /* No partition to scan. */ + m_table->status= STATUS_NOT_FOUND; + DBUG_RETURN(error); + } + + m_ordered= sorted; + set_eq_range(eq_range_arg); + m_handler->set_end_range(end_key); + + set_range_key_part(m_curr_key_info[0]->key_part); + if (have_start_key) + m_start_key= *start_key; + else + m_start_key.key= NULL; + + m_index_scan_type= PARTITION_READ_RANGE; + error= common_index_read(m_table->record[0], have_start_key); + DBUG_RETURN(error); +} + + +/** + Read next record in read of a range with start and end key. + + @return Operation status. + @retval 0 Success + @retval != 0 Error code +*/ + +int Partition_helper::ph_read_range_next() +{ + DBUG_ENTER("Partition_helper::ph_read_range_next"); + + if (m_ordered_scan_ongoing) + { + DBUG_RETURN(handle_ordered_next(m_table->record[0], get_eq_range())); + } + DBUG_RETURN(handle_unordered_next(m_table->record[0], get_eq_range())); +} + + +/** + Common routine to set up index scans. + + Find out which partitions we'll need to read when scanning the specified + range. + + If we need to scan only one partition, set m_ordered_scan_ongoing=FALSE + as we will not need to do merge ordering. + + @param buf Buffer to later return record in (this function + needs it to calculate partitioning function values) + + @param idx_read_flag TRUE <=> m_start_key has range start endpoint which + probably can be used to determine the set of + partitions to scan. + FALSE <=> there is no start endpoint. + + @return Operation status. + @retval 0 Success + @retval !=0 Error code +*/ + +int Partition_helper::partition_scan_set_up(uchar * buf, bool idx_read_flag) +{ + DBUG_ENTER("Partition_helper::partition_scan_set_up"); + + if (idx_read_flag) + get_partition_set(m_table, + buf, + m_handler->active_index, + &m_start_key, + &m_part_spec); + else + { + // TODO: set to get_first_used_part() instead! + m_part_spec.start_part= 0; + // TODO: Implement bitmap_get_last_set() and use that here! + m_part_spec.end_part= m_tot_parts - 1; + } + if (m_part_spec.start_part > m_part_spec.end_part) + { + /* + We discovered a partition set but the set was empty so we report + key not found. + */ + DBUG_PRINT("info", ("scan with no partition to scan")); + m_table->status= STATUS_NOT_FOUND; + DBUG_RETURN(HA_ERR_END_OF_FILE); + } + if (m_part_spec.start_part == m_part_spec.end_part) + { + /* + We discovered a single partition to scan, this never needs to be + performed using the ordered index scan. + */ + DBUG_PRINT("info", ("index scan using the single partition %d", + m_part_spec.start_part)); + m_ordered_scan_ongoing= FALSE; + } + else + { + /* + Set m_ordered_scan_ongoing according how the scan should be done + Only exact partitions are discovered atm by get_partition_set. + Verify this, also bitmap must have at least one bit set otherwise + the result from this table is the empty set. + */ + uint start_part= m_part_info->get_first_used_partition(); + if (start_part == MY_BIT_NONE) + { + DBUG_PRINT("info", ("scan with no partition to scan")); + m_table->status= STATUS_NOT_FOUND; + DBUG_RETURN(HA_ERR_END_OF_FILE); + } + if (start_part > m_part_spec.start_part) + m_part_spec.start_part= start_part; + m_ordered_scan_ongoing= m_ordered; + } + DBUG_ASSERT(m_part_spec.start_part < m_tot_parts); + DBUG_ASSERT(m_part_spec.end_part < m_tot_parts); + DBUG_RETURN(0); +} + + +/** + Common routine to handle index_next with unordered results. + + These routines are used to scan partitions without considering order. + This is performed in two situations. + 1) In read_multi_range this is the normal case + 2) When performing any type of index_read, index_first, index_last where + all fields in the partition function is bound. In this case the index + scan is performed on only one partition and thus it isn't necessary to + perform any sort. + + @param[out] buf Read row in MySQL Row Format. + @param[in] next_same Called from index_next_same. + + @return Operation status. + @retval HA_ERR_END_OF_FILE End of scan + @retval 0 Success + @retval other Error code +*/ + +int Partition_helper::handle_unordered_next(uchar *buf, bool is_next_same) +{ + int error; + DBUG_ENTER("Partition_helper::handle_unordered_next"); + + if (m_part_spec.start_part >= m_tot_parts) + { + /* Should only happen with SQL HANDLER! */ + DBUG_ASSERT(m_table->open_by_handler); + DBUG_RETURN(HA_ERR_END_OF_FILE); + } + + /* + We should consider if this should be split into three functions as + partition_read_range is_next_same are always local constants + */ + + if (m_index_scan_type == PARTITION_READ_RANGE) + { + DBUG_ASSERT(buf == m_table->record[0]); + error= read_range_next_in_part(m_part_spec.start_part, NULL); + } + else if (is_next_same) + { + error= index_next_same_in_part(m_part_spec.start_part, + buf, + m_start_key.key, + m_start_key.length); + } + else + { + error= index_next_in_part(m_part_spec.start_part, buf); + } + + if (error == HA_ERR_END_OF_FILE) + { + m_part_spec.start_part++; // Start using next part + error= handle_unordered_scan_next_partition(buf); + } + else + { + m_last_part= m_part_spec.start_part; + } + DBUG_RETURN(error); +} + + +/** + Handle index_next when changing to new partition. + + This routine is used to start the index scan on the next partition. + Both initial start and after completing scan on one partition. + + @param[out] buf Read row in MySQL Row Format + + @return Operation status. + @retval HA_ERR_END_OF_FILE End of scan + @retval 0 Success + @retval other Error code +*/ + +int Partition_helper::handle_unordered_scan_next_partition(uchar * buf) +{ + uint i= m_part_spec.start_part; + int saved_error= HA_ERR_END_OF_FILE; + DBUG_ENTER("Partition_helper::handle_unordered_scan_next_partition"); + + if (i) + i= m_part_info->get_next_used_partition(i - 1); + else + i= m_part_info->get_first_used_partition(); + + for (; + i <= m_part_spec.end_part; + i= m_part_info->get_next_used_partition(i)) + { + int error; + m_part_spec.start_part= i; + switch (m_index_scan_type) { + case PARTITION_READ_RANGE: + DBUG_ASSERT(buf == m_table->record[0]); + DBUG_PRINT("info", ("read_range_first on partition %d", i)); + error= read_range_first_in_part(i, + NULL, + m_start_key.key? &m_start_key: NULL, + m_handler->end_range, + get_eq_range(), + false); + break; + case PARTITION_INDEX_READ: + DBUG_PRINT("info", ("index_read on partition %d", i)); + error= index_read_map_in_part(i, + buf, + m_start_key.key, + m_start_key.keypart_map, + m_start_key.flag); + break; + case PARTITION_INDEX_FIRST: + DBUG_PRINT("info", ("index_first on partition %d", i)); + error= index_first_in_part(i, buf); + break; + case PARTITION_INDEX_FIRST_UNORDERED: + /* When is this ever used? */ + DBUG_ASSERT(0); + /* + We perform a scan without sorting and this means that we + should not use the index_first since not all handlers + support it and it is also unnecessary to restrict sort + order. + */ + DBUG_PRINT("info", ("read_range_first on partition %d", i)); + DBUG_ASSERT(buf == m_table->record[0]); + error= read_range_first_in_part(i, + NULL, + 0, + m_handler->end_range, + get_eq_range(), + 0); + break; + default: + DBUG_ASSERT(0); + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + } + if (!error) + { + m_last_part= i; + DBUG_RETURN(0); + } + if ((error != HA_ERR_END_OF_FILE) && (error != HA_ERR_KEY_NOT_FOUND)) + DBUG_RETURN(error); + + /* + If HA_ERR_KEY_NOT_FOUND, we must return that error instead of + HA_ERR_END_OF_FILE, to be able to continue search. + */ + if (saved_error != HA_ERR_KEY_NOT_FOUND) + saved_error= error; + DBUG_PRINT("info", ("END_OF_FILE/KEY_NOT_FOUND on partition %d", i)); + } + if (saved_error == HA_ERR_END_OF_FILE) + m_part_spec.start_part= NO_CURRENT_PART_ID; + DBUG_RETURN(saved_error); +} + + +/** + Common routine to start index scan with ordered results. + + @param[out] buf Read row in MySQL Row Format + + @return Operation status + @retval HA_ERR_END_OF_FILE End of scan + @retval HA_ERR_KEY_NOT_FOUND End of scan + @retval 0 Success + @retval other Error code + + @details + This part contains the logic to handle index scans that require ordered + output. This includes all except those started by read_range_first with + the flag ordered set to FALSE. Thus most direct index_read and all + index_first and index_last. + + We implement ordering by keeping one record plus a key buffer for each + partition. Every time a new entry is requested we will fetch a new + entry from the partition that is currently not filled with an entry. + Then the entry is put into its proper sort position. + + Returning a record is done by getting the top record, copying the + record to the request buffer and setting the partition as empty on + entries. +*/ + +int Partition_helper::handle_ordered_index_scan(uchar *buf) +{ + uint i; + std::vector parts; + bool found= FALSE; + uchar *part_rec_buf_ptr= m_ordered_rec_buffer; + int saved_error= HA_ERR_END_OF_FILE; + DBUG_ENTER("Partition_helper::handle_ordered_index_scan"); + DBUG_ASSERT(part_rec_buf_ptr); + + if (m_key_not_found) + { + m_key_not_found= false; + bitmap_clear_all(&m_key_not_found_partitions); + DBUG_PRINT("info", ("Cleared m_key_not_found_partitions")); + } + m_top_entry= NO_CURRENT_PART_ID; + m_queue->clear(); + parts.reserve(m_queue->capacity()); + DBUG_ASSERT(m_part_info->is_partition_used(m_part_spec.start_part)); + + /* + Position part_rec_buf_ptr to point to the first used partition >= + start_part. There may be partitions marked by used_partitions, + but is before start_part. These partitions has allocated record buffers + but is dynamically pruned, so those buffers must be skipped. + */ + for (i= m_part_info->get_first_used_partition(); + i < m_part_spec.start_part; + i= m_part_info->get_next_used_partition(i)) + { + part_rec_buf_ptr+= m_rec_offset + m_rec_length; + } + DBUG_PRINT("info", ("m_part_spec.start_part %u first_used_part %u", + m_part_spec.start_part, i)); + for (/* continue from above */ ; + i <= m_part_spec.end_part; + i= m_part_info->get_next_used_partition(i)) + { + DBUG_PRINT("info", ("reading from part %u (scan_type: %u inx: %u)", + i, m_index_scan_type, m_handler->active_index)); + DBUG_ASSERT(i == uint2korr(part_rec_buf_ptr)); + uchar *rec_buf_ptr= part_rec_buf_ptr + m_rec_offset; + uchar *read_buf; + int error; + DBUG_PRINT("info", ("part %u, scan_type %d", i, m_index_scan_type)); + + /* ICP relies on Item evaluation, which expects the row in record[0]. */ + if (m_handler->pushed_idx_cond) + read_buf= m_table->record[0]; + else + read_buf= rec_buf_ptr; + + switch (m_index_scan_type) { + case PARTITION_INDEX_READ: + error= index_read_map_in_part(i, + read_buf, + m_start_key.key, + m_start_key.keypart_map, + m_start_key.flag); + break; + case PARTITION_INDEX_FIRST: + error= index_first_in_part(i, read_buf); + break; + case PARTITION_INDEX_LAST: + error= index_last_in_part(i, read_buf); + break; + case PARTITION_INDEX_READ_LAST: + error= index_read_last_map_in_part(i, + read_buf, + m_start_key.key, + m_start_key.keypart_map); + break; + case PARTITION_READ_RANGE: + { + /* + To enable optimization in derived engines, we provide a read buffer + pointer if we want to read into something different than table->record[0] + (which read_range_* always uses). + */ + error= read_range_first_in_part(i, + read_buf == m_table->record[0] + ? NULL : read_buf, + m_start_key.key ? &m_start_key : NULL, + m_handler->end_range, + get_eq_range(), + true); + break; + } + default: + DBUG_ASSERT(false); + DBUG_RETURN(HA_ERR_END_OF_FILE); + } + DBUG_PRINT("info", ("error %d from partition %u", error, i)); + /* When using ICP, copy record[0] to the priority queue for sorting. */ + if (m_handler->pushed_idx_cond) + memcpy(rec_buf_ptr, read_buf, m_rec_length); + if (!error) + { + found= true; + if (m_ref_usage != REF_NOT_USED) + { + /* position_in_last_part needs m_last_part set. */ + m_last_part= i; + position_in_last_part(part_rec_buf_ptr + PARTITION_BYTES_IN_POS, + rec_buf_ptr); + } + /* + Save for later insertion in queue; + */ + parts.push_back(part_rec_buf_ptr); + DBUG_DUMP("row", read_buf, m_rec_length); + } + else if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) + { + DBUG_RETURN(error); + } + else if (error == HA_ERR_KEY_NOT_FOUND) + { + DBUG_PRINT("info", ("HA_ERR_KEY_NOT_FOUND from partition %u", i)); + bitmap_set_bit(&m_key_not_found_partitions, i); + m_key_not_found= true; + saved_error= error; + } + part_rec_buf_ptr+= m_rec_offset + m_rec_length; + } + if (found) + { + /* + We found at least one partition with data, now sort all entries and + after that read the first entry and copy it to the buffer to return in. + */ + m_queue->m_max_at_top= m_reverse_order; + m_queue->m_keys= m_curr_key_info; + DBUG_ASSERT(m_queue->empty()); + /* + If PK, we should not sort by rowid, since that is already done + through the KEY setup. + */ + DBUG_ASSERT(!m_curr_key_info[1] || m_ref_usage == REF_NOT_USED); + m_queue->assign(parts); + return_top_record(buf); + m_table->status= 0; + DBUG_PRINT("info", ("Record returned from partition %d", m_top_entry)); + DBUG_RETURN(0); + } + DBUG_RETURN(saved_error); +} + + +/** + Return the top record in sort order. + + @param[out] buf Row returned in MySQL Row Format. +*/ + +void Partition_helper::return_top_record(uchar *buf) +{ + uint part_id; + uchar *key_buffer= m_queue->top(); + uchar *rec_buffer= key_buffer + m_rec_offset; + + part_id= uint2korr(key_buffer); + copy_cached_row(buf, rec_buffer); + DBUG_PRINT("info", ("from part_id %u", part_id)); + DBUG_DUMP("returned_row", buf, m_table->s->reclength); + m_last_part= part_id; + m_top_entry= part_id; +} + + +/** + Add index_next/prev results from partitions without exact match. + + If there where any partitions that returned HA_ERR_KEY_NOT_FOUND when + ha_index_read_map was done, those partitions must be included in the + following index_next/prev call. +*/ + +int Partition_helper::handle_ordered_index_scan_key_not_found() +{ + int error; + uint i; + size_t old_elements= m_queue->size(); + uchar *part_buf= m_ordered_rec_buffer; + uchar *curr_rec_buf= NULL; + DBUG_ENTER("Partition_helper::handle_ordered_index_scan_key_not_found"); + DBUG_ASSERT(m_key_not_found); + DBUG_ASSERT(part_buf); + /* + Loop over all used partitions to get the correct offset + into m_ordered_rec_buffer. + */ + for (i= m_part_info->get_first_used_partition(); + i < MY_BIT_NONE; + i= m_part_info->get_next_used_partition(i)) + { + if (bitmap_is_set(&m_key_not_found_partitions, i)) + { + /* + This partition is used and did return HA_ERR_KEY_NOT_FOUND + in index_read_map. + */ + uchar *read_buf; + curr_rec_buf= part_buf + m_rec_offset; + /* ICP relies on Item evaluation, which expects the row in record[0]. */ + if (m_handler->pushed_idx_cond) + read_buf= m_table->record[0]; + else + read_buf= curr_rec_buf; + + if (m_reverse_order) + error= index_prev_in_part(i, read_buf); + else + error= index_next_in_part(i, read_buf); + /* HA_ERR_KEY_NOT_FOUND is not allowed from index_next! */ + DBUG_ASSERT(error != HA_ERR_KEY_NOT_FOUND); + DBUG_PRINT("info", ("Filling from partition %u reverse %u error %d", + i, m_reverse_order, error)); + if (!error) + { + /* When using ICP, copy record[0] to the priority queue for sorting. */ + if (m_handler->pushed_idx_cond) + memcpy(curr_rec_buf, read_buf, m_rec_length); + if (m_ref_usage != REF_NOT_USED) + { + /* position_in_last_part needs m_last_part set. */ + m_last_part= i; + position_in_last_part(part_buf + PARTITION_BYTES_IN_POS, + curr_rec_buf); + } + m_queue->push(part_buf); + } + else if (error != HA_ERR_END_OF_FILE && error != HA_ERR_KEY_NOT_FOUND) + DBUG_RETURN(error); + } + part_buf+= m_rec_offset + m_rec_length; + } + DBUG_ASSERT(curr_rec_buf); + bitmap_clear_all(&m_key_not_found_partitions); + m_key_not_found= false; + + if (m_queue->size() > old_elements) + { + /* Update m_top_entry, which may have changed. */ + uchar *key_buffer= m_queue->top(); + m_top_entry= uint2korr(key_buffer); + } + DBUG_RETURN(0); +} + + +/** + Common routine to handle index_next with ordered results. + + @param[out] buf Read row in MySQL Row Format. + @param[in] next_same Called from index_next_same. + + @return Operation status. + @retval HA_ERR_END_OF_FILE End of scan + @retval 0 Success + @retval other Error code +*/ + +int Partition_helper::handle_ordered_next(uchar *buf, bool is_next_same) +{ + int error; + uint part_id= m_top_entry; + uchar *rec_buf= m_queue->empty() ? NULL : m_queue->top() + m_rec_offset; + uchar *read_buf; + DBUG_ENTER("Partition_helper::handle_ordered_next"); + + if (m_reverse_order) + { + /* + TODO: To support change of direction (index_prev -> index_next, + index_read_map(HA_READ_KEY_EXACT) -> index_prev etc.) + We would need to: + - Step back all cursors we have a buffered row from a previous next/prev + call (i.e. for all partitions we previously called index_prev, we must + call index_next and skip that row. + - empty the priority queue and initialize it again with reverse ordering. + */ + DBUG_ASSERT(m_table->open_by_handler); + DBUG_RETURN(HA_ERR_WRONG_COMMAND); + } + + if (m_key_not_found) + { + if (is_next_same) + { + /* Only rows which match the key. */ + m_key_not_found= false; + bitmap_clear_all(&m_key_not_found_partitions); + } + else + { + /* There are partitions not included in the index record queue. */ + size_t old_elements= m_queue->size(); + if ((error= handle_ordered_index_scan_key_not_found())) + DBUG_RETURN(error); + /* + If the queue top changed, i.e. one of the partitions that gave + HA_ERR_KEY_NOT_FOUND in index_read_map found the next record, + return it. + Otherwise replace the old with a call to index_next (fall through). + */ + if (old_elements != m_queue->size() && part_id != m_top_entry) + { + return_top_record(buf); + DBUG_PRINT("info", ("Returning row from part %u (prev KEY_NOT_FOUND)", + m_top_entry)); + DBUG_RETURN(0); + } + } + } + if (part_id >= m_tot_parts) + DBUG_RETURN(HA_ERR_END_OF_FILE); + + DBUG_PRINT("info", ("next row from part %u (inx %u)", + part_id, m_handler->active_index)); + + /* Assert that buffer for fetch is not NULL */ + DBUG_ASSERT(rec_buf); + + /* ICP relies on Item evaluation, which expects the row in record[0]. */ + if (m_handler->pushed_idx_cond) + read_buf= m_table->record[0]; + else + read_buf= rec_buf; + + + if (m_index_scan_type == PARTITION_READ_RANGE) + { + error= read_range_next_in_part(part_id, + read_buf == m_table->record[0] + ? NULL : read_buf); + } + else if (!is_next_same) + error= index_next_in_part(part_id, read_buf); + else + error= index_next_same_in_part(part_id, + read_buf, + m_start_key.key, + m_start_key.length); + if (error) + { + if (error == HA_ERR_END_OF_FILE) + { + /* Return next buffered row */ + if (!m_queue->empty()) + m_queue->pop(); + if (m_queue->empty()) + { + /* + If priority queue is empty, we have finished fetching rows from all + partitions. Reset the value of next partition to NONE. This would + imply HA_ERR_END_OF_FILE for all future calls. + */ + m_top_entry= NO_CURRENT_PART_ID; + } + else + { + return_top_record(buf); + DBUG_PRINT("info", ("Record returned from partition %u (2)", + m_top_entry)); + m_table->status= 0; + error= 0; + } + } + DBUG_RETURN(error); + } + /* When using ICP, copy record[0] to the priority queue for sorting. */ + if (m_handler->pushed_idx_cond) + memcpy(rec_buf, read_buf, m_rec_length); + if (m_ref_usage != REF_NOT_USED) + { + /* position_in_last_part needs m_last_part set. */ + m_last_part= part_id; + position_in_last_part(rec_buf - m_rec_offset + PARTITION_BYTES_IN_POS, + rec_buf); + } + DBUG_DUMP("rec_buf", rec_buf, m_rec_length); + m_queue->update_top(); + return_top_record(buf); + DBUG_PRINT("info", ("Record returned from partition %u", m_top_entry)); + DBUG_RETURN(0); +} + + +/** + Common routine to handle index_prev with ordered results. + + @param[out] buf Read row in MySQL Row Format. + + @return Operation status. + @retval HA_ERR_END_OF_FILE End of scan + @retval 0 Success + @retval other Error code +*/ + +int Partition_helper::handle_ordered_prev(uchar *buf) +{ + int error; + uint part_id= m_top_entry; + uchar *rec_buf= m_queue->empty() ? NULL : m_queue->top() + m_rec_offset; + uchar *read_buf; + DBUG_ENTER("Partition_helper::handle_ordered_prev"); + + if (!m_reverse_order) + { + /* TODO: See comment in handle_ordered_next(). */ + DBUG_ASSERT(m_table->open_by_handler); + DBUG_RETURN(HA_ERR_WRONG_COMMAND); + } + + if (m_key_not_found) + { + /* There are partitions not included in the index record queue. */ + size_t old_elements= m_queue->size(); + if ((error= handle_ordered_index_scan_key_not_found())) + DBUG_RETURN(error); + if (old_elements != m_queue->size() && part_id != m_top_entry) + { + /* + Should only be possible for when HA_READ_KEY_EXACT was previously used, + which is not supported to have a subsequent call for PREV. + I.e. HA_READ_KEY_EXACT is considered to not have reverse order! + */ + DBUG_ASSERT(0); + /* + If the queue top changed, i.e. one of the partitions that gave + HA_ERR_KEY_NOT_FOUND in index_read_map found the next record, + return it. + Otherwise replace the old with a call to index_next (fall through). + */ + return_top_record(buf); + DBUG_RETURN(0); + } + } + + if (part_id >= m_tot_parts) + { + /* This should never happen, except for SQL HANDLER calls! */ + DBUG_ASSERT(m_table->open_by_handler); + DBUG_RETURN(HA_ERR_END_OF_FILE); + } + + /* Assert that buffer for fetch is not NULL */ + DBUG_ASSERT(rec_buf); + + /* ICP relies on Item evaluation, which expects the row in record[0]. */ + if (m_handler->pushed_idx_cond) + read_buf= m_table->record[0]; + else + read_buf= rec_buf; + + if ((error= index_prev_in_part(part_id, read_buf))) + { + if (error == HA_ERR_END_OF_FILE) + { + if (!m_queue->empty()) + m_queue->pop(); + if (m_queue->empty()) + { + /* + If priority queue is empty, we have finished fetching rows from all + partitions. Reset the value of next partition to NONE. This would + imply HA_ERR_END_OF_FILE for all future calls. + */ + m_top_entry= NO_CURRENT_PART_ID; + } + else + { + return_top_record(buf); + DBUG_PRINT("info", ("Record returned from partition %d (2)", + m_top_entry)); + error= 0; + m_table->status= 0; + } + } + DBUG_RETURN(error); + } + /* When using ICP, copy record[0] to the priority queue for sorting. */ + if (m_handler->pushed_idx_cond) + memcpy(rec_buf, read_buf, m_rec_length); + + if (m_ref_usage != REF_NOT_USED) + { + /* position_in_last_part needs m_last_part set. */ + m_last_part= part_id; + position_in_last_part(rec_buf - m_rec_offset + PARTITION_BYTES_IN_POS, + rec_buf); + } + m_queue->update_top(); + return_top_record(buf); + DBUG_PRINT("info", ("Record returned from partition %d", m_top_entry)); + DBUG_RETURN(0); +} + +/** + Get statistics from a specific partition. + + @param[out] stat_info Area to report values into. + @param[out] check_sum Check sum of partition. + @param[in] part_id Partition to report from. +*/ +void +Partition_helper::get_dynamic_partition_info_low(PARTITION_STATS *stat_info, + ha_checksum *check_sum, + uint part_id) +{ + ha_statistics *part_stat= &m_handler->stats; + DBUG_ASSERT(bitmap_is_set(&m_part_info->read_partitions, part_id)); + DBUG_ASSERT(bitmap_is_subset(&m_part_info->read_partitions, + &m_part_info->lock_partitions)); + DBUG_ASSERT(bitmap_is_subset(&m_part_info->lock_partitions, + &m_part_info->read_partitions)); + bitmap_clear_all(&m_part_info->read_partitions); + bitmap_set_bit(&m_part_info->read_partitions, part_id); + m_handler->info(HA_STATUS_TIME | + HA_STATUS_VARIABLE | + HA_STATUS_VARIABLE_EXTRA | + HA_STATUS_NO_LOCK); + stat_info->records= part_stat->records; + stat_info->mean_rec_length= part_stat->mean_rec_length; + stat_info->data_file_length= part_stat->data_file_length; + stat_info->max_data_file_length= part_stat->max_data_file_length; + stat_info->index_file_length= part_stat->index_file_length; + stat_info->delete_length= part_stat->delete_length; + stat_info->create_time= part_stat->create_time; + stat_info->update_time= part_stat->update_time; + stat_info->check_time= part_stat->check_time; + if (get_thd()->variables.old_mode ? + m_handler->ha_table_flags() & HA_HAS_OLD_CHECKSUM : + m_handler->ha_table_flags() & HA_HAS_NEW_CHECKSUM) + { + *check_sum= checksum_in_part(part_id); + } + bitmap_copy(&m_part_info->read_partitions, &m_part_info->lock_partitions); +} + + +/** + Get checksum for table. + + @return Checksum or 0 if not supported, which also may be a correct checksum!. +*/ + +ha_checksum Partition_helper::ph_checksum() const +{ + ha_checksum sum= 0; + if (get_thd()->variables.old_mode ? + m_handler->ha_table_flags() & HA_HAS_OLD_CHECKSUM : + m_handler->ha_table_flags() & HA_HAS_NEW_CHECKSUM) + { + for (uint i= 0; i < m_tot_parts; i++) + { + sum+= checksum_in_part(i); + } + } + return sum; +} diff --git a/sql/partitioning/partition_handler.h b/sql/partitioning/partition_handler.h new file mode 100644 index 00000000000..cf4e1dcb24b --- /dev/null +++ b/sql/partitioning/partition_handler.h @@ -0,0 +1,1113 @@ +#ifndef PARTITION_HANDLER_INCLUDED +#define PARTITION_HANDLER_INCLUDED + +/* + Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 of + the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "my_global.h" // uint etc. +#include "my_base.h" // ha_rows. +#include "handler.h" // Handler_share +#include "sql_partition.h" // part_id_range +#include "mysqld_error.h" // ER_ILLEGAL_HA +#include "priority_queue.h" +#include "key.h" // key_rec_cmp +#include "ha_partition.h" +#include + +#define PARTITION_BYTES_IN_POS 2 + +/* forward declarations */ +typedef struct st_mem_root MEM_ROOT; + +static const uint NO_CURRENT_PART_ID= UINT_MAX32; + +/** + bits in Partition_handler::alter_flags(): + + HA_PARTITION_FUNCTION_SUPPORTED indicates that the function is + supported at all. + HA_FAST_CHANGE_PARTITION means that optimized variants of the changes + exists but they are not necessarily done online. + + HA_ONLINE_DOUBLE_WRITE means that the handler supports writing to both + the new partition and to the old partitions when updating through the + old partitioning schema while performing a change of the partitioning. + This means that we can support updating of the table while performing + the copy phase of the change. For no lock at all also a double write + from new to old must exist and this is not required when this flag is + set. + This is actually removed even before it was introduced the first time. + The new idea is that handlers will handle the lock level already in + store_lock for ALTER TABLE partitions. + TODO: Implement this via the alter-inplace api. +*/ + +enum enum_part_operation { + OPTIMIZE_PARTS= 0, + ANALYZE_PARTS, + CHECK_PARTS, + REPAIR_PARTS, + ASSIGN_KEYCACHE_PARTS, + PRELOAD_KEYS_PARTS +}; + + +/** + Initialize partitioning (currently only PSI keys). +*/ +void partitioning_init(); + + +/** + Class for partitioning specific operations. + + Returned from handler::get_partition_handler(). +*/ +class Partition_handler :public Sql_alloc +{ +public: + Partition_handler() {} + ~Partition_handler() {} + + bool init(uint num_parts); + + /** + Get dynamic table information from partition. + + @param[out] stat_info Statistics struct to fill in. + @param[out] check_sum Check sum value to fill in if supported. + @param[in] part_id Partition to report for. + + @note stat_info and check_sum are initialized by caller. + check_sum is only expected to be updated if HA_HAS_CHECKSUM. + */ + virtual void get_dynamic_partition_info(PARTITION_STATS *stat_info, + uint part_id) = 0; + + /** + Get default number of partitions. + + Used during creating a partitioned table. + + @param info Create info. + @return Number of default partitions. + */ + virtual int get_default_num_partitions(HA_CREATE_INFO *info) { return 1;} + /** + Setup auto partitioning. + + Called for engines with HA_USE_AUTO_PARTITION to setup the partition info + object + + @param[in,out] part_info Partition object to setup. + */ + virtual void set_auto_partitions(partition_info *part_info) { return; } + /** + Get number of partitions for table in SE + + @param name normalized path(same as open) to the table + + @param[out] num_parts Number of partitions + + @retval false for success + @retval true for failure, for example table didn't exist in engine + */ + virtual bool get_num_parts(const char *name, + uint *num_parts) + { + *num_parts= 0; + return false; + } + /** + Set the partition info object to be used by the handler. + + @param part_info Partition info to be used by the handler. + @param early True if called when part_info only created and parsed, + but not setup, checked or fixed. + */ + virtual void set_part_info(partition_info *part_info) = 0; + /** + Initialize partition. + + @param mem_root Memory root for memory allocations. + + @return Operation status + @retval false Success. + @retval true Failure. + */ + virtual bool initialize_partition(MEM_ROOT *mem_root) {return false;} + + + /** + Alter flags. + + Given a set of alter table flags, return which is supported. + + @param flags Alter table operation flags. + + @return Supported alter table flags. + */ + virtual uint alter_flags(uint flags) const + { return 0; } + +private: + /** + Truncate partition. + + Low-level primitive for handler, implementing + Partition_handler::truncate_partition(). + + @return Operation status + @retval 0 Success. + @retval != 0 Error code. + */ + virtual int truncate_partition_low() + { return HA_ERR_WRONG_COMMAND; } + /** + Truncate partition. + + Low-level primitive for handler, implementing + Partition_handler::change_partitions(). + + @param[in] create_info Table create info. + @param[in] path Path including table name. + @param[out] copied Number of rows copied. + @param[out] deleted Number of rows deleted. + + @return Operation status + @retval 0 Success. + @retval != 0 Error code. + */ + virtual int change_partitions_low(HA_CREATE_INFO *create_info, + const char *path, + ulonglong * const copied, + ulonglong * const deleted) + { + my_error(ER_ILLEGAL_HA, MYF(0), create_info->alias); + return HA_ERR_WRONG_COMMAND; + } + /** + Return the table handler. + + For some partitioning specific functions it is still needed to access + the handler directly for transaction handling (mark_trx_read_write()) + and to assert correct locking. + + @return handler or NULL if not supported. + */ + virtual handler *get_handler() + { return NULL; } +}; + + +/// Maps compare function to strict weak ordering required by Priority_queue. +struct Key_rec_less +{ + typedef int (*key_compare_fun)(void*, uchar *, uchar *); + + explicit Key_rec_less(KEY **keys) + : m_keys(keys), m_fun(key_rec_cmp), m_max_at_top(false) + { + } + + bool operator()(uchar *first, uchar *second) + { + const int cmpval= + (*m_fun)(m_keys, first + m_rec_offset, second + m_rec_offset); + return m_max_at_top ? cmpval < 0 : cmpval > 0; + } + + KEY **m_keys; + key_compare_fun m_fun; + uint m_rec_offset; + bool m_max_at_top; +}; + + +/** + Partition_helper is a helper class that implements most generic partitioning + functionality such as: + table scan, index scan (both ordered and non-ordered), + insert (write_row()), delete and update. + And includes ALTER TABLE ... ADD/COALESCE/DROP/REORGANIZE/... PARTITION + support. + It also implements a cache for the auto increment value and check/repair for + rows in wrong partition. + + How to use it: + Inherit it and implement: + - *_in_part() functions for row operations. + - prepare_for_new_partitions(), create_new_partition(), close_new_partitions() + write_row_in_new_part() for handling 'fast' alter partition. +*/ +class Partition_helper : public Sql_alloc +{ + typedef Priority_queue, Key_rec_less> Prio_queue; +public: + Partition_helper(handler *main_handler); + ~Partition_helper(); + + /** + Set partition info. + + To be called from Partition_handler. + + @param part_info Partition info to use. + @param early True if called when part_info only created and parsed, + but not setup, checked or fixed. + */ + virtual void set_part_info_low(partition_info *part_info, bool early); + /** + Initialize variables used before the table is opened. + + @param mem_root Memory root to allocate things from (not yet used). + + @return Operation status. + @retval false success. + @retval true failure. + */ + inline bool init_partitioning(MEM_ROOT *mem_root) + { +#ifndef DBUG_OFF + m_key_not_found_partitions.bitmap= NULL; +#endif + return false; + } + + + /** + INSERT/UPDATE/DELETE functions. + @see handler.h + @{ + */ + + /** + Insert a row to the partitioned table. + + @param buf The row in MySQL Row Format. + + @return Operation status. + @retval 0 Success + @retval != 0 Error code + */ + int ph_write_row(uchar *buf); + /** + Update an existing row in the partitioned table. + + Yes, update_row() does what you expect, it updates a row. old_data will + have the previous row record in it, while new_data will have the newest + data in it. + Keep in mind that the server can do updates based on ordering if an + ORDER BY clause was used. Consecutive ordering is not guaranteed. + + If the new record belongs to a different partition than the old record + then it will be inserted into the new partition and deleted from the old. + + new_data is always record[0] + old_data is always record[1] + + @param old_data The old record in MySQL Row Format. + @param new_data The new record in MySQL Row Format. + + @return Operation status. + @retval 0 Success + @retval != 0 Error code + */ + int ph_update_row(const uchar *old_data, uchar *new_data); + /** + Delete an existing row in the partitioned table. + + This will delete a row. buf will contain a copy of the row to be deleted. + The server will call this right after the current row has been read + (from either a previous rnd_xxx() or index_xxx() call). + If you keep a pointer to the last row or can access a primary key it will + make doing the deletion quite a bit easier. + Keep in mind that the server does no guarantee consecutive deletions. + ORDER BY clauses can be used. + + buf is either record[0] or record[1] + + @param buf The record in MySQL Row Format. + + @return Operation status. + @retval 0 Success + @retval != 0 Error code + */ + int ph_delete_row(const uchar *buf); + + /** @} */ + + /** Release unused auto increment values. */ + void ph_release_auto_increment(); + /** + Calculate key hash value from an null terminated array of fields. + Support function for KEY partitioning. + + @param field_array An array of the fields in KEY partitioning + + @return hash_value calculated + + @note Uses the hash function on the character set of the field. + Integer and floating point fields use the binary character set by default. + */ + static uint32 ph_calculate_key_hash_value(Field **field_array); + /** Get checksum for table. + @return Checksum or 0 if not supported (which also may be a correct checksum!). + */ + ha_checksum ph_checksum() const; + + /** + MODULE full table scan + + This module is used for the most basic access method for any table + handler. This is to fetch all data through a full table scan. No + indexes are needed to implement this part. + It contains one method to start the scan (rnd_init) that can also be + called multiple times (typical in a nested loop join). Then proceeding + to the next record (rnd_next) and closing the scan (rnd_end). + To remember a record for later access there is a method (position) + and there is a method used to retrieve the record based on the stored + position. + The position can be a file position, a primary key, a ROWID dependent + on the handler below. + + unlike index_init(), rnd_init() can be called two times + without rnd_end() in between (it only makes sense if scan=1). + then the second call should prepare for the new table scan + (e.g if rnd_init allocates the cursor, second call should + position it to the start of the table, no need to deallocate + and allocate it again. + @see handler.h + @{ + */ + + int ph_rnd_init(bool scan); + int ph_rnd_end(); + int ph_rnd_next(uchar *buf); + void ph_position(const uchar *record); + int ph_rnd_pos(uchar *buf, uchar *pos); + int ph_rnd_pos_by_record(uchar *record); + + /** @} */ + + /** + MODULE index scan + + This part of the handler interface is used to perform access through + indexes. The interface is defined as a scan interface but the handler + can also use key lookup if the index is a unique index or a primary + key index. + Index scans are mostly useful for SELECT queries but are an important + part also of UPDATE, DELETE, REPLACE and CREATE TABLE table AS SELECT + and so forth. + Naturally an index is needed for an index scan and indexes can either + be ordered, hash based. Some ordered indexes can return data in order + but not necessarily all of them. + There are many flags that define the behavior of indexes in the + various handlers. These methods are found in the optimizer module. + ------------------------------------------------------------------------- + + index_read is called to start a scan of an index. The find_flag defines + the semantics of the scan. These flags are defined in + include/my_base.h + index_read_idx is the same but also initializes index before calling doing + the same thing as index_read. Thus it is similar to index_init followed + by index_read. This is also how we implement it. + + index_read/index_read_idx does also return the first row. Thus for + key lookups, the index_read will be the only call to the handler in + the index scan. + + index_init initializes an index before using it and index_end does + any end processing needed. + @{ + */ + + int ph_index_init_setup(uint key_nr, bool sorted); + int ph_index_init(uint key_nr, bool sorted); + int ph_index_end(); + /* + These methods are used to jump to next or previous entry in the index + scan. There are also methods to jump to first and last entry. + */ + int ph_index_first(uchar *buf); + int ph_index_last(uchar *buf); + int ph_index_next(uchar *buf); + int ph_index_next_same(uchar *buf, const uchar *key, uint keylen); + int ph_index_prev(uchar *buf); + int ph_index_read_map(uchar *buf, + const uchar *key, + key_part_map keypart_map, + enum ha_rkey_function find_flag); + int ph_index_read_last_map(uchar *buf, + const uchar *key, + key_part_map keypart_map); + int ph_index_read_idx_map(uchar *buf, + uint index, + const uchar *key, + key_part_map keypart_map, + enum ha_rkey_function find_flag); + int ph_read_range_first(const key_range *start_key, + const key_range *end_key, + bool eq_range_arg, + bool sorted); + int ph_read_range_next(); + /** @} */ + + /** + Functions matching Partition_handler API. + @{ + */ + + /** + Get statistics from a specific partition. + @param[out] stat_info Area to report values into. + @param[out] check_sum Check sum of partition. + @param[in] part_id Partition to report from. + */ + virtual void get_dynamic_partition_info_low(PARTITION_STATS *stat_info, + ha_checksum *check_sum, + uint part_id); + + /** + Implement the partition changes defined by ALTER TABLE of partitions. + + Add and copy if needed a number of partitions, during this operation + only read operation is ongoing in the server. This is used by + ADD PARTITION all types as well as by REORGANIZE PARTITION. For + one-phased implementations it is used also by DROP and COALESCE + PARTITIONs. + One-phased implementation needs the new frm file, other handlers will + get zero length and a NULL reference here. + + @param[in] create_info HA_CREATE_INFO object describing all + fields and indexes in table + @param[in] path Complete path of db and table name + @param[out] copied Output parameter where number of copied + records are added + @param[out] deleted Output parameter where number of deleted + records are added + + @return Operation status + @retval 0 Success + @retval != 0 Failure + */ + int change_partitions(HA_CREATE_INFO *create_info, + const char *path, + ulonglong * const copied, + ulonglong * const deleted); + /** @} */ + +protected: + /* Common helper functions to be used by inheriting engines. */ + + /* + open/close functions. + */ + + /** + Set m_part_share, Allocate internal bitmaps etc. used by open tables. + + @param mem_root Memory root to allocate things from (not yet used). + + @return Operation status. + @retval false success. + @retval true failure. + */ + bool open_partitioning(Partition_share *part_share); + /** + Close partitioning for a table. + + Frees memory and release other resources. + */ + void close_partitioning(); + + /** + Lock auto increment value if needed. + */ + inline void lock_auto_increment() + { + /* lock already taken */ + if (m_auto_increment_safe_stmt_log_lock) + return; + DBUG_ASSERT(!m_auto_increment_lock); + if(m_table->s->tmp_table == NO_TMP_TABLE) + { + m_auto_increment_lock= true; + m_part_share->lock_auto_inc(); + } + } + /** + unlock auto increment. + */ + inline void unlock_auto_increment() + { + /* + If m_auto_increment_safe_stmt_log_lock is true, we have to keep the lock. + It will be set to false and thus unlocked at the end of the statement by + ha_partition::release_auto_increment. + */ + if(m_auto_increment_lock && !m_auto_increment_safe_stmt_log_lock) + { + m_part_share->unlock_auto_inc(); + m_auto_increment_lock= false; + } + } + /** + Get auto increment. + + Only to be used for auto increment values that are the first field in + an unique index. + + @param[in] increment Increment between generated numbers. + @param[in] nb_desired_values Number of values requested. + @param[out] first_value First reserved value (ULLONG_MAX on error). + @param[out] nb_reserved_values Number of values reserved. + */ + void get_auto_increment_first_field(ulonglong increment, + ulonglong nb_desired_values, + ulonglong *first_value, + ulonglong *nb_reserved_values); + + /** + Initialize the record priority queue used for sorted index scans. + @return Operation status. + @retval 0 Success. + @retval != 0 Error code. + */ + int init_record_priority_queue(); + /** + Destroy the record priority queue used for sorted index scans. + */ + void destroy_record_priority_queue(); + /* + Administrative support functions. + */ + + /** Print partitioning specific error. + @param error Error code. + @param errflag Error flag. + @return false if error is printed else true. + */ + bool print_partition_error(int error, myf errflag); +#if 0 + /** + Print a message row formatted for ANALYZE/CHECK/OPTIMIZE/REPAIR TABLE. + + Modeled after mi_check_print_msg. + + @param thd Thread context. + @param len Needed length for message buffer. + @param msg_type Message type. + @param db_name Database name. + @param table_name Table name. + @param op_name Operation name. + @param fmt Message (in printf format with additional arguments). + + @return Operation status. + @retval false for success else true. + */ + bool print_admin_msg(THD *thd, + uint len, + const char *msg_type, + const char *db_name, + const char *table_name, + const char *op_name, + const char *fmt, + ...); +#endif + /** + Check/fix misplaced rows. + + @param part_id Partition to check/fix. + @param repair If true, move misplaced rows to correct partition. + + @return Operation status. + @retval 0 Success + @retval != 0 Error + */ + int check_misplaced_rows(uint part_id, bool repair); + /** + Set used partitions bitmap from Alter_info. + + @return false if success else true. + */ + bool set_altered_partitions(); + +private: + enum partition_index_scan_type + { + PARTITION_INDEX_READ= 1, + PARTITION_INDEX_FIRST, + PARTITION_INDEX_FIRST_UNORDERED, + PARTITION_INDEX_LAST, + PARTITION_INDEX_READ_LAST, + PARTITION_READ_RANGE, + PARTITION_NO_INDEX_SCAN + }; + + /** handler to use (ha_partition, ha_innopart etc.) */ + handler *m_handler; + /** Convenience pointer to table from m_handler (i.e. m_handler->table). */ + TABLE *m_table; + + /* + Access methods to protected areas in handler to avoid adding + friend class Partition_helper in class handler. + */ + virtual THD *get_thd() const = 0; + virtual TABLE *get_table() const = 0; + virtual bool get_eq_range() const = 0; + virtual void set_eq_range(bool eq_range) = 0; + virtual void set_range_key_part(KEY_PART_INFO *key_part) = 0; + + /* + Implementation of per partition operation by instantiated engine. + These must be implemented in the 'real' partition_helper subclass. + */ + + /** + Write a row in the specified partition. + + @see handler::write_row(). + + @param part_id Partition to write to. + @param buf Buffer with data to write. + + @return Operation status. + @retval 0 Success. + @retval != 0 Error code. + */ + virtual int write_row_in_part(uint part_id, uchar *buf) = 0; + /** + Update a row in the specified partition. + + @see handler::update_row(). + + @param part_id Partition to update in. + @param old_data Buffer containing old row. + @param new_data Buffer containing new row. + + @return Operation status. + @retval 0 Success. + @retval != 0 Error code. + */ + virtual int update_row_in_part(uint new_part_id, + const uchar *old_data, + uchar *new_data) = 0; + /** + Delete an existing row in the specified partition. + + @see handler::delete_row(). + + @param part_id Partition to delete from. + @param buf Buffer containing row to delete. + + @return Operation status. + @retval 0 Success. + @retval != 0 Error code. + */ + virtual int delete_row_in_part(uint part_id, const uchar *buf) = 0; + /** + Initialize the shared auto increment value. + + @param no_lock If HA_STATUS_NO_LOCK should be used in info(HA_STATUS_AUTO). + + Also sets stats.auto_increment_value. + */ + virtual int initialize_auto_increment(bool no_lock) = 0; + /** Release auto_increment in all underlying partitions. */ + virtual void release_auto_increment_all_parts() {} + /** Save or persist the current max auto increment. */ + virtual void save_auto_increment(ulonglong nr) {} + /** + Per partition equivalent of rnd_* and index_* functions. + + @see class handler. + */ + virtual int rnd_init_in_part(uint part_id, bool table_scan) = 0; + int ph_rnd_next_in_part(uint part_id, uchar *buf); + virtual int rnd_next_in_part(uint part_id, uchar *buf) = 0; + virtual int rnd_end_in_part(uint part_id, bool scan) = 0; + virtual void position_in_last_part(uchar *ref, const uchar *row) = 0; + /* If ph_rnd_pos is used then this needs to be implemented! */ + virtual int rnd_pos_in_part(uint part_id, uchar *buf, uchar *pos) + { DBUG_ASSERT(0); return HA_ERR_WRONG_COMMAND; } + virtual int rnd_pos_by_record_in_last_part(uchar *row) + { + /* + Not much overhead to use default function. This avoids out-of-sync code. + */ + return m_handler->rnd_pos_by_record(row); + } + virtual int index_init_in_part(uint part, uint keynr, bool sorted) + { DBUG_ASSERT(0); return HA_ERR_WRONG_COMMAND; } + virtual int index_end_in_part(uint part) + { DBUG_ASSERT(0); return HA_ERR_WRONG_COMMAND; } + virtual int index_first_in_part(uint part, uchar *buf) = 0; + virtual int index_last_in_part(uint part, uchar *buf) = 0; + virtual int index_prev_in_part(uint part, uchar *buf) = 0; + virtual int index_next_in_part(uint part, uchar *buf) = 0; + virtual int index_next_same_in_part(uint part, + uchar *buf, + const uchar *key, + uint length) = 0; + virtual int index_read_map_in_part(uint part, + uchar *buf, + const uchar *key, + key_part_map keypart_map, + enum ha_rkey_function find_flag) = 0; + virtual int index_read_last_map_in_part(uint part, + uchar *buf, + const uchar *key, + key_part_map keypart_map) = 0; + /** + Do read_range_first in the specified partition. + If buf is set, then copy the result there instead of table->record[0]. + */ + virtual int read_range_first_in_part(uint part, + uchar *buf, + const key_range *start_key, + const key_range *end_key, + bool eq_range, + bool sorted) = 0; + /** + Do read_range_next in the specified partition. + If buf is set, then copy the result there instead of table->record[0]. + */ + virtual int read_range_next_in_part(uint part, uchar *buf) = 0; + virtual int index_read_idx_map_in_part(uint part, + uchar *buf, + uint index, + const uchar *key, + key_part_map keypart_map, + enum ha_rkey_function find_flag) = 0; + /** + Initialize engine specific resources for the record priority queue + used duing ordered index reads for multiple partitions. + + @param used_parts Number of partitions used in query + (number of set bits in m_part_info->read_partitions). + + @return Operation status. + @retval 0 Success. + @retval != 0 Error code. + */ + virtual int init_record_priority_queue_for_parts(uint used_parts) + { + return 0; + } + /** + Destroy and release engine specific resources used by the record + priority queue. + */ + virtual void destroy_record_priority_queue_for_parts() {} + /** + Checksum for a partition. + + @param part_id Partition to checksum. + */ + virtual ha_checksum checksum_in_part(uint part_id) const + { DBUG_ASSERT(0); return 0; } + /** + Copy a cached row. + + Used when copying a row from the record priority queue to the return buffer. + For some engines, like InnoDB, only marked columns must be copied, + to preserve non-read columns. + + @param[out] to_rec Buffer to copy to. + @param[in] from_rec Buffer to copy from. + */ + virtual void copy_cached_row(uchar *to_rec, const uchar *from_rec) + { memcpy(to_rec, from_rec, m_rec_length); } + /** + Prepare for creating new partitions during ALTER TABLE ... PARTITION. + @param num_partitions Number of new partitions to be created. + @param only_create True if only creating the partition + (no open/lock is needed). + + @return Operation status. + @retval 0 Success. + @retval != 0 Error code. + */ + virtual int prepare_for_new_partitions(uint num_partitions, + bool only_create) = 0; + /** + Create a new partition to be filled during ALTER TABLE ... PARTITION. + @param table Table to create the partition in. + @param create_info Table/partition specific create info. + @param part_name Partition name. + @param new_part_id Partition id in new table. + @param part_elem Partition element. + + @return Operation status. + @retval 0 Success. + @retval != 0 Error code. + */ + virtual int create_new_partition(TABLE *table, + HA_CREATE_INFO *create_info, + const char *part_name, + uint new_part_id, + partition_element *part_elem) = 0; + /** + Close and finalize new partitions. + */ + virtual void close_new_partitions() = 0; + /** + write row to new partition. + @param new_part New partition to write to. + + @return Operation status. + @retval 0 Success. + @retval != 0 Error code. + */ + virtual int write_row_in_new_part(uint new_part) = 0; + + /* Internal helper functions*/ + /** + Update auto increment value if current row contains a higher value. + */ + inline void set_auto_increment_if_higher(); + /** + Common routine to set up index scans. + + Find out which partitions we'll need to read when scanning the specified + range. + + If we need to scan only one partition, set m_ordered_scan_ongoing=FALSE + as we will not need to do merge ordering. + + @param buf Buffer to later return record in (this function + needs it to calculate partitioning function values) + + @param idx_read_flag True <=> m_start_key has range start endpoint which + probably can be used to determine the set of + partitions to scan. + False <=> there is no start endpoint. + + @return Operation status. + @retval 0 Success + @retval !=0 Error code + */ + int partition_scan_set_up(uchar *buf, bool idx_read_flag); + /** + Common routine to handle index_next with unordered results. + + These routines are used to scan partitions without considering order. + This is performed in two situations. + 1) In read_multi_range this is the normal case + 2) When performing any type of index_read, index_first, index_last where + all fields in the partition function is bound. In this case the index + scan is performed on only one partition and thus it isn't necessary to + perform any sort. + + @param[out] buf Read row in MySQL Row Format. + @param[in] next_same Called from index_next_same. + + @return Operation status. + @retval HA_ERR_END_OF_FILE End of scan + @retval 0 Success + @retval other Error code + */ + int handle_unordered_next(uchar *buf, bool is_next_same); + /** + Handle index_next when changing to new partition. + + This routine is used to start the index scan on the next partition. + Both initial start and after completing scan on one partition. + + @param[out] buf Read row in MySQL Row Format + + @return Operation status. + @retval HA_ERR_END_OF_FILE End of scan + @retval 0 Success + @retval other Error code + */ + int handle_unordered_scan_next_partition(uchar *buf); + /** + Common routine to start index scan with ordered results. + + @param[out] buf Read row in MySQL Row Format + + @return Operation status + @retval HA_ERR_END_OF_FILE End of scan + @retval HA_ERR_KEY_NOT_FOUND End of scan + @retval 0 Success + @retval other Error code + */ + int handle_ordered_index_scan(uchar *buf); + /** + Add index_next/prev results from partitions without exact match. + + If there where any partitions that returned HA_ERR_KEY_NOT_FOUND when + ha_index_read_map was done, those partitions must be included in the + following index_next/prev call. + + @return Operation status + @retval HA_ERR_END_OF_FILE End of scan + @retval 0 Success + @retval other Error code + */ + int handle_ordered_index_scan_key_not_found(); + /** + Common routine to handle index_prev with ordered results. + + @param[out] buf Read row in MySQL Row Format. + + @return Operation status. + @retval HA_ERR_END_OF_FILE End of scan + @retval 0 Success + @retval other Error code + */ + int handle_ordered_prev(uchar *buf); + /** + Common routine to handle index_next with ordered results. + + @param[out] buf Read row in MySQL Row Format. + @param[in] next_same Called from index_next_same. + + @return Operation status. + @retval HA_ERR_END_OF_FILE End of scan + @retval 0 Success + @retval other Error code + */ + int handle_ordered_next(uchar *buf, bool is_next_same); + /** + Common routine for a number of index_read variants. + + @param[out] buf Buffer where the record should be returned. + @param[in] have_start_key TRUE <=> the left endpoint is available, i.e. + we're in index_read call or in read_range_first + call and the range has left endpoint. + FALSE <=> there is no left endpoint (we're in + read_range_first() call and the range has no + left endpoint). + + @return Operation status + @retval 0 OK + @retval HA_ERR_END_OF_FILE Whole index scanned, without finding the record. + @retval HA_ERR_KEY_NOT_FOUND Record not found, but index cursor positioned. + @retval other Error code. + */ + int common_index_read(uchar *buf, bool have_start_key); + /** + Common routine for index_first/index_last. + + @param[out] buf Read row in MySQL Row Format. + + @return Operation status. + @retval 0 Success + @retval != 0 Error code + */ + int common_first_last(uchar *buf); + /** + Return the top record in sort order. + + @param[out] buf Row returned in MySQL Row Format. + */ + void return_top_record(uchar *buf); + /** + Copy partitions as part of ALTER TABLE of partitions. + + change_partitions has done all the preparations, now it is time to + actually copy the data from the reorganized partitions to the new + partitions. + + @param[out] copied Number of records copied. + @param[out] deleted Number of records deleted. + + @return Operation status + @retval 0 Success + @retval >0 Error code + */ + virtual int copy_partitions(ulonglong * const copied, + ulonglong * const deleted); + + /** + Set table->read_set taking partitioning expressions into account. + */ + void set_partition_read_set(); + + /* + These could be private as well, + but easier to expose them to derived classes to use. + */ +protected: + /** All internal partitioning data! @{ */ + /** Tables partitioning info (same as table->part_info) */ + partition_info *m_part_info; + /** Is primary key clustered. */ + bool m_pkey_is_clustered; + /** Cached value of m_part_info->is_sub_partitioned(). */ + bool m_is_sub_partitioned; + /** Partition share for auto_inc handling. */ + Partition_share *m_part_share; + /** Total number of partitions. */ + uint m_tot_parts; + uint m_last_part; // Last accessed partition. + const uchar *m_err_rec; // record which gave error. + bool m_auto_increment_safe_stmt_log_lock; + bool m_auto_increment_lock; + part_id_range m_part_spec; // Which parts to scan + uint m_scan_value; // Value passed in rnd_init + // call + key_range m_start_key; // index read key range + enum partition_index_scan_type m_index_scan_type;// What type of index + // scan + uint m_rec_length; // Local copy of record length + + bool m_ordered; // Ordered/Unordered index scan. + bool m_ordered_scan_ongoing; // Ordered index scan ongoing. + bool m_reverse_order; // Scanning in reverse order (prev). + /** Row and key buffer for ordered index scan. */ + uchar *m_ordered_rec_buffer; + /** Prio queue used by sorted read. */ + Prio_queue *m_queue; + /** Which partition is to deliver next result. */ + uint m_top_entry; + /** Offset in m_ordered_rec_buffer from part buffer to its record buffer. */ + uint m_rec_offset; + /** + Current index used for sorting. + If clustered PK exists, then it will be used as secondary index to + sort on if the first is equal in key_rec_cmp. + So if clustered pk: m_curr_key_info[0]= current index and + m_curr_key_info[1]= pk and [2]= NULL. + Otherwise [0]= current index, [1]= NULL, and we will + sort by rowid as secondary sort key if equal first key. + */ + KEY *m_curr_key_info[3]; + enum enum_using_ref { + /** handler::ref is not copied to the PQ. */ + REF_NOT_USED= 0, + /** + handler::ref is copied to the PQ but does not need to be used in sorting. + */ + REF_STORED_IN_PQ, + /** handler::ref is copied to the PQ and must be used during sorting. */ + REF_USED_FOR_SORT}; + /** How handler::ref is used in the priority queue. */ + enum_using_ref m_ref_usage; + /** Set if previous index_* call returned HA_ERR_KEY_NOT_FOUND. */ + bool m_key_not_found; + /** Partitions that returned HA_ERR_KEY_NOT_FOUND. */ + MY_BITMAP m_key_not_found_partitions; + /** @} */ +}; +#endif /* PARTITION_HANDLER_INCLUDED */ diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index b30240f64c3..0aeaa058cf9 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7523,8 +7523,17 @@ WARN_VERS_PARAMETERS WARN_VERS_PART_ROTATION eng "Switching from partition %`s to %`s" +WARN_VERS_TRX_MISSING + eng "VTQ missing transaction ID %lu" + +WARN_VERS_PART_NON_HISTORICAL + eng "Partition %`s contains non-historical data" + ER_VERS_NOT_ALLOWED eng "%`s is not allowed for versioned table" ER_VERS_WRONG_QUERY_TYPE eng "%`s works only with %`s query type" + +ER_WRONG_TABLESPACE_NAME 42000 + eng "Incorrect tablespace name `%-.192s`" diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index b358fe3386e..caca441e5e4 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -67,6 +67,7 @@ #include "opt_range.h" // store_key_image_to_rec #include "sql_alter.h" // Alter_table_ctx #include "sql_select.h" +#include "sql_tablespace.h" // check_tablespace_name #include using std::max; @@ -3458,7 +3459,10 @@ int vers_get_partition_id(partition_info *part_info, { table->s->busy_rotation= true; mysql_mutex_unlock(&table->s->LOCK_rotation); - if (part_info->vers_limit_exceed() || part_info->vers_interval_exceed(sys_trx_end->get_timestamp())) + // transaction is not yet pushed to VTQ, so we use now-time + my_time_t end_ts= sys_trx_end->table->versioned_by_engine() ? + my_time(0) : sys_trx_end->get_timestamp(); + if (part_info->vers_limit_exceed() || part_info->vers_interval_exceed(end_ts)) { part_info->vers_part_rotate(thd); } @@ -7388,6 +7392,39 @@ err: } #endif + +/* + Prepare for calling val_int on partition function by setting fields to + point to the record where the values of the PF-fields are stored. + + SYNOPSIS + set_field_ptr() + ptr Array of fields to change ptr + new_buf New record pointer + old_buf Old record pointer + + DESCRIPTION + Set ptr in field objects of field array to refer to new_buf record + instead of previously old_buf. Used before calling val_int and after + it is used to restore pointers to table->record[0]. + This routine is placed outside of partition code since it can be useful + also for other programs. +*/ + +void set_field_ptr(Field **ptr, const uchar *new_buf, + const uchar *old_buf) +{ + my_ptrdiff_t diff= (new_buf - old_buf); + DBUG_ENTER("set_field_ptr"); + + do + { + (*ptr)->move_field_offset(diff); + } while (*(++ptr)); + DBUG_VOID_RETURN; +} + + /* Prepare for calling val_int on partition function by setting fields to point to the record where the values of the PF-fields are stored. @@ -7426,6 +7463,61 @@ void set_key_field_ptr(KEY *key_info, const uchar *new_buf, } +/** + Append all fields in read_set to string + + @param[in,out] str String to append to. + @param[in] row Row to append. + @param[in] table Table containing read_set and fields for the row. +*/ +void append_row_to_str(String &str, const uchar *row, TABLE *table) +{ + Field **fields, **field_ptr; + const uchar *rec; + uint num_fields= bitmap_bits_set(table->read_set); + uint curr_field_index= 0; + bool is_rec0= !row || row == table->record[0]; + if (!row) + rec= table->record[0]; + else + rec= row; + + /* Create a new array of all read fields. */ + fields= (Field**) my_malloc(sizeof(void*) * (num_fields + 1), + MYF(0)); + if (!fields) + return; + fields[num_fields]= NULL; + for (field_ptr= table->field; + *field_ptr; + field_ptr++) + { + if (!bitmap_is_set(table->read_set, (*field_ptr)->field_index)) + continue; + fields[curr_field_index++]= *field_ptr; + } + + + if (!is_rec0) + set_field_ptr(fields, rec, table->record[0]); + + for (field_ptr= fields; + *field_ptr; + field_ptr++) + { + Field *field= *field_ptr; + str.append(" "); + str.append(field->field_name); + str.append(":"); + field_unpack(&str, field, rec, 0, false); + } + + if (!is_rec0) + set_field_ptr(fields, table->record[0], rec); + my_free(fields); +} + + /* SYNOPSIS mem_alloc_error() @@ -8595,4 +8687,52 @@ uint get_partition_field_store_length(Field *field) store_length+= HA_KEY_BLOB_LENGTH; return store_length; } + +// FIXME: duplicate of ha_partition::set_up_table_before_create +bool set_up_table_before_create(THD *thd, + TABLE_SHARE *share, + const char *partition_name_with_path, + HA_CREATE_INFO *info, + partition_element *part_elem) +{ + bool error= false; + const char *partition_name; + DBUG_ENTER("set_up_table_before_create"); + + DBUG_ASSERT(part_elem); + + if (!part_elem) + DBUG_RETURN(true); + share->max_rows= part_elem->part_max_rows; + share->min_rows= part_elem->part_min_rows; + partition_name= strrchr(partition_name_with_path, FN_LIBCHAR); + if ((part_elem->index_file_name && + (error= append_file_to_dir(thd, + const_cast(&part_elem->index_file_name), + partition_name+1))) || + (part_elem->data_file_name && + (error= append_file_to_dir(thd, + const_cast(&part_elem->data_file_name), + partition_name+1)))) + { + DBUG_RETURN(error); + } + if (part_elem->index_file_name != NULL) + { + info->index_file_name= part_elem->index_file_name; + } + if (part_elem->data_file_name != NULL) + { + info->data_file_name= part_elem->data_file_name; + } + if (part_elem->tablespace_name != NULL) + { + if (check_tablespace_name(part_elem->tablespace_name) != IDENT_NAME_OK) + { + DBUG_RETURN(true); + } + info->tablespace= part_elem->tablespace_name; + } + DBUG_RETURN(error); +} #endif diff --git a/sql/sql_partition.h b/sql/sql_partition.h index c2665a8366b..aef4a6ce5e1 100644 --- a/sql/sql_partition.h +++ b/sql/sql_partition.h @@ -40,6 +40,7 @@ typedef struct st_key_range key_range; #define HA_CAN_UPDATE_PARTITION_KEY (1 << 1) #define HA_CAN_PARTITION_UNIQUE (1 << 2) #define HA_USE_AUTO_PARTITION (1 << 3) +#define HA_ONLY_VERS_PARTITION (1 << 4) #define NORMAL_PART_NAME 0 #define TEMP_PART_NAME 1 @@ -127,6 +128,14 @@ uint32 get_partition_id_range_for_endpoint(partition_info *part_info, bool check_part_func_fields(Field **ptr, bool ok_with_charsets); bool field_is_partition_charset(Field *field); Item* convert_charset_partition_constant(Item *item, CHARSET_INFO *cs); +/** + Append all fields in read_set to string + + @param[in,out] str String to append to. + @param[in] row Row to append. + @param[in] table Table containing read_set and fields for the row. +*/ +void append_row_to_str(String &str, const uchar *row, TABLE *table); void mem_alloc_error(size_t size); void truncate_partition_filename(char *path); @@ -291,6 +300,31 @@ void create_subpartition_name(char *out, const char *in1, void set_key_field_ptr(KEY *key_info, const uchar *new_buf, const uchar *old_buf); +/** Set up table for creating a partition. +Copy info from partition to the table share so the created partition +has the correct info. + @param thd THD object + @param share Table share to be updated. + @param info Create info to be updated. + @param part_elem partition_element containing the info. + + @return status + @retval TRUE Error + @retval FALSE Success + + @details + Set up + 1) Comment on partition + 2) MAX_ROWS, MIN_ROWS on partition + 3) Index file name on partition + 4) Data file name on partition +*/ +bool set_up_table_before_create(THD *thd, + TABLE_SHARE *share, + const char *partition_name_with_path, + HA_CREATE_INFO *info, + partition_element *part_elem); + extern const LEX_STRING partition_keywords[]; #endif /* SQL_PARTITION_INCLUDED */ diff --git a/sql/sql_table.cc b/sql/sql_table.cc index b5cf35ed17c..3a921e0dc79 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4492,7 +4492,10 @@ handler *mysql_create_frm_image(THD *thd, part_info->part_info_string= part_syntax_buf; part_info->part_info_len= syntax_len; if ((!(engine_type->partition_flags && - engine_type->partition_flags() & HA_CAN_PARTITION)) || + ((engine_type->partition_flags() & HA_CAN_PARTITION) || + (part_info->part_type == VERSIONING_PARTITION && + engine_type->partition_flags() & HA_ONLY_VERS_PARTITION)) + )) || create_info->db_type == partition_hton) { /* diff --git a/sql/sql_tablespace.cc b/sql/sql_tablespace.cc index 8b9e14e5a18..318be320640 100644 --- a/sql/sql_tablespace.cc +++ b/sql/sql_tablespace.cc @@ -22,6 +22,70 @@ #include "sql_table.h" // write_bin_log #include "sql_class.h" // THD +/** + Check if tablespace name is valid + + @param tablespace_name Name of the tablespace + + @note Tablespace names are not reflected in the file system, so + character case conversion or consideration is not relevant. + + @note Checking for path characters or ending space is not done. + The only checks are for identifier length, both in terms of + number of characters and number of bytes. + + @retval IDENT_NAME_OK Identifier name is ok (Success) + @retval IDENT_NAME_WRONG Identifier name is wrong, if length == 0 +* (ER_WRONG_TABLESPACE_NAME) + @retval IDENT_NAME_TOO_LONG Identifier name is too long if it is greater + than 64 characters (ER_TOO_LONG_IDENT) + + @note In case of IDENT_NAME_TOO_LONG or IDENT_NAME_WRONG, the function + reports an error (using my_error()). +*/ + +enum_ident_name_check check_tablespace_name(const char *tablespace_name) +{ + size_t name_length= 0; //< Length as number of bytes + size_t name_length_symbols= 0; //< Length as number of symbols + + // Name must be != NULL and length must be > 0 + if (!tablespace_name || (name_length= strlen(tablespace_name)) == 0) + { + my_error(ER_WRONG_TABLESPACE_NAME, MYF(0), tablespace_name); + return IDENT_NAME_WRONG; + } + + // If we do not have too many bytes, we must check the number of symbols, + // provided the system character set may use more than one byte per symbol. + if (name_length <= NAME_LEN && use_mb(system_charset_info)) + { + const char *name= tablespace_name; //< The actual tablespace name + const char *end= name + name_length; //< Pointer to first byte after name + + // Loop over all symbols as long as we don't have too many already + while (name != end && name_length_symbols <= NAME_CHAR_LEN) + { + int len= my_ismbchar(system_charset_info, name, end); + if (len) + name += len; + else + name++; + + name_length_symbols++; + } + } + + if (name_length_symbols > NAME_CHAR_LEN || name_length > NAME_LEN) + { + my_error(ER_TOO_LONG_IDENT, MYF(0), tablespace_name); + return IDENT_NAME_TOO_LONG; + } + + return IDENT_NAME_OK; +} + + int mysql_alter_tablespace(THD *thd, st_alter_tablespace *ts_info) { int error= HA_ADMIN_NOT_IMPLEMENTED; diff --git a/sql/sql_tablespace.h b/sql/sql_tablespace.h index ae77d15cbcb..b97c64f7965 100644 --- a/sql/sql_tablespace.h +++ b/sql/sql_tablespace.h @@ -19,6 +19,41 @@ class THD; class st_alter_tablespace; +/** + Enumerate possible status of a identifier name while determining + its validity +*/ +enum enum_ident_name_check +{ + IDENT_NAME_OK, + IDENT_NAME_WRONG, + IDENT_NAME_TOO_LONG +}; + +/** + Check if tablespace name is valid + + @param tablespace_name Name of the tablespace + + @note Tablespace names are not reflected in the file system, so + character case conversion or consideration is not relevant. + + @note Checking for path characters or ending space is not done. + The only checks are for identifier length, both in terms of + number of characters and number of bytes. + + @retval IDENT_NAME_OK Identifier name is ok (Success) + @retval IDENT_NAME_WRONG Identifier name is wrong, if length == 0 + (ER_WRONG_TABLESPACE_NAME) + @retval IDENT_NAME_TOO_LONG Identifier name is too long if it is greater + than 64 characters (ER_TOO_LONG_IDENT) + + @note In case of IDENT_NAME_TOO_LONG or IDENT_NAME_WRONG, the function + reports an error (using my_error()). +*/ + +enum_ident_name_check check_tablespace_name(const char *tablespace_name); + int mysql_alter_tablespace(THD* thd, st_alter_tablespace *ts_info); #endif /* SQL_TABLESPACE_INCLUDED */ diff --git a/sql/table.cc b/sql/table.cc index 354658ba476..b256b3e91b6 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -3261,6 +3261,20 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, } outparam->part_info->is_auto_partitioned= share->auto_partitioned; DBUG_PRINT("info", ("autopartitioned: %u", share->auto_partitioned)); + if (outparam->part_info->part_type == VERSIONING_PARTITION && + share->db_type()->vers_upgrade_handler) + { + outparam->file= share->db_type()->vers_upgrade_handler( + outparam->file, &outparam->mem_root); + if (!outparam->file) + { + thd->stmt_arena= backup_stmt_arena_ptr; + thd->restore_active_arena(&part_func_arena, &backup_arena); + my_error(ER_OUTOFMEMORY, MYF(0), 4095); + error_reported= TRUE; + goto err; + } + } /* We should perform the fix_partition_func in either local or caller's arena depending on work_part_info_used value. diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt index 1ecf80bb92d..dfcd348690b 100644 --- a/storage/innobase/CMakeLists.txt +++ b/storage/innobase/CMakeLists.txt @@ -74,7 +74,7 @@ SET(INNOBASE_SOURCES gis/gis0sea.cc fts/fts0plugin.cc handler/ha_innodb.cc -# handler/ha_innopart.cc + handler/ha_innopart.cc handler/handler0alter.cc handler/i_s.cc ibuf/ibuf0ibuf.cc diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 60e34103d76..e96d9c52909 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -147,10 +147,7 @@ TABLE *open_purge_table(THD *thd, const char *db, size_t dblen, #include /* for ha_innopart, Native InnoDB Partitioning. */ -/* JAN: TODO: MySQL 5.7 Native InnoDB Partitioning */ -#ifdef HAVE_HA_INNOPART_H #include "ha_innopart.h" -#endif #include #include @@ -1622,6 +1619,22 @@ innobase_create_handler( return(new (mem_root) ha_innobase(hton, table)); } +static +handler* +innobase_upgrade_handler( + handler* hnd, + MEM_ROOT* mem_root) +{ + ha_innopart* file = new (mem_root) ha_innopart( + static_cast(hnd)); + if (file && file->init_partitioning(mem_root)) + { + delete file; + return(NULL); + } + return file; +} + /* General functions */ /** Check that a page_size is correct for InnoDB. @@ -3737,10 +3750,7 @@ innobase_init_abort() /** Return partitioning flags. */ static uint innobase_partition_flags() { - /* JAN: TODO: MYSQL 5.7 - return(HA_CAN_EXCHANGE_PARTITION | HA_CANNOT_PARTITION_FK); - */ - return (0); + return(HA_ONLY_VERS_PARTITION); } /** Deprecation message about InnoDB file format related parameters */ @@ -3893,6 +3903,7 @@ innobase_init( innobase_hton->vers_query_trx_id = vtq_query_trx_id; innobase_hton->vers_query_commit_ts = vtq_query_commit_ts; innobase_hton->vers_trx_sees = vtq_trx_sees; + innobase_hton->vers_upgrade_handler = innobase_upgrade_handler; innodb_remember_check_sysvar_funcs(); @@ -8522,6 +8533,7 @@ ha_innobase::write_row( trx_t* trx = thd_to_trx(m_user_thd); TrxInInnoDB trx_in_innodb(trx); + ins_mode_t vers_set_fields; if (trx_in_innodb.is_aborted()) { @@ -8722,8 +8734,14 @@ no_commit: innobase_srv_conc_enter_innodb(m_prebuilt); + vers_set_fields = table->versioned() && + (sql_command != SQLCOM_DELETE || + (m_int_table_flags & HA_INNOPART_DISABLED_TABLE_FLAGS)) ? + ROW_INS_VERSIONED : + ROW_INS_NORMAL; + /* Step-5: Execute insert graph that will result in actual insert. */ - error = row_insert_for_mysql((byte*) record, m_prebuilt); + error = row_insert_for_mysql((byte*) record, m_prebuilt, vers_set_fields); DEBUG_SYNC(m_user_thd, "ib_after_row_insert"); @@ -9499,6 +9517,7 @@ ha_innobase::update_row( upd_t* uvect = row_get_prebuilt_update_vector(m_prebuilt); ib_uint64_t autoinc; + bool vers_set_fields; /* Build an update vector from the modified fields in the rows (uses m_upd_buf of the handle) */ @@ -9524,11 +9543,14 @@ ha_innobase::update_row( innobase_srv_conc_enter_innodb(m_prebuilt); - error = row_update_for_mysql((byte*) old_row, m_prebuilt); + vers_set_fields = m_prebuilt->upd_node->versioned && + (m_int_table_flags & HA_INNOPART_DISABLED_TABLE_FLAGS); - if (error == DB_SUCCESS && m_prebuilt->upd_node->versioned) { + error = row_update_for_mysql((byte*) old_row, m_prebuilt, vers_set_fields); + + if (error == DB_SUCCESS && vers_set_fields) { if (trx->id != static_cast(table->vers_start_field()->val_int())) - error = row_insert_for_mysql((byte*) old_row, m_prebuilt, true); + error = row_insert_for_mysql((byte*) old_row, m_prebuilt, ROW_INS_HISTORICAL); } if (error == DB_SUCCESS && autoinc) { @@ -9644,11 +9666,13 @@ ha_innobase::delete_row( innobase_srv_conc_enter_innodb(m_prebuilt); - bool delete_history_row = - table->versioned() && !table->vers_end_field()->is_max(); + bool vers_set_fields = + table->versioned() && + (m_int_table_flags & HA_INNOPART_DISABLED_TABLE_FLAGS) && + table->vers_end_field()->is_max(); error = row_update_for_mysql( - (byte *)record, m_prebuilt, delete_history_row); + (byte *)record, m_prebuilt, vers_set_fields); innobase_srv_conc_exit_innodb(m_prebuilt); @@ -14276,16 +14300,14 @@ These errors will abort the current query: case HA_ERR_QUERY_INTERRUPTED: For other error codes, the server will fall back to counting records. */ -#ifdef MYSQL_57_SELECT_COUNT_OPTIMIZATION -int -ha_innobase::records( -/*==================*/ - ha_rows* num_rows) /*!< out: number of rows */ +ha_rows +ha_innobase::records_new() /*!< out: number of rows */ { DBUG_ENTER("ha_innobase::records()"); dberr_t ret; ulint n_rows = 0; /* Record count in this view */ + ha_rows num_rows; update_thd(); @@ -14296,8 +14318,8 @@ ha_innobase::records( ER_TABLESPACE_DISCARDED, table->s->table_name.str); - *num_rows = HA_POS_ERROR; - DBUG_RETURN(HA_ERR_NO_SUCH_TABLE); + num_rows = HA_POS_ERROR; + DBUG_RETURN(num_rows); } else if (m_prebuilt->table->ibd_file_missing) { ib_senderrf( @@ -14305,8 +14327,8 @@ ha_innobase::records( ER_TABLESPACE_MISSING, table->s->table_name.str); - *num_rows = HA_POS_ERROR; - DBUG_RETURN(HA_ERR_TABLESPACE_MISSING); + num_rows = HA_POS_ERROR; + DBUG_RETURN(num_rows); } else if (m_prebuilt->table->corrupted) { ib_errf(m_user_thd, IB_LOG_LEVEL_WARN, @@ -14314,8 +14336,8 @@ ha_innobase::records( "Table '%s' is corrupt.", table->s->table_name.str); - *num_rows = HA_POS_ERROR; - DBUG_RETURN(HA_ERR_INDEX_CORRUPT); + num_rows = HA_POS_ERROR; + DBUG_RETURN(num_rows); } TrxInInnoDB trx_in_innodb(m_prebuilt->trx); @@ -14330,8 +14352,8 @@ ha_innobase::records( m_prebuilt->trx, index); if (!m_prebuilt->index_usable) { - *num_rows = HA_POS_ERROR; - DBUG_RETURN(HA_ERR_TABLE_DEF_CHANGED); + num_rows = HA_POS_ERROR; + DBUG_RETURN(num_rows); } /* (Re)Build the m_prebuilt->mysql_template if it is null to use @@ -14350,30 +14372,29 @@ ha_innobase::records( case DB_DEADLOCK: case DB_LOCK_TABLE_FULL: case DB_LOCK_WAIT_TIMEOUT: - *num_rows = HA_POS_ERROR; - DBUG_RETURN(convert_error_code_to_mysql(ret, 0, m_user_thd)); + num_rows = HA_POS_ERROR; + DBUG_RETURN(num_rows); case DB_INTERRUPTED: - *num_rows = HA_POS_ERROR; - DBUG_RETURN(HA_ERR_QUERY_INTERRUPTED); + num_rows = HA_POS_ERROR; + DBUG_RETURN(num_rows); default: /* No other error besides the three below is returned from row_scan_index_for_mysql(). Make a debug catch. */ - *num_rows = HA_POS_ERROR; + num_rows = HA_POS_ERROR; ut_ad(0); - DBUG_RETURN(-1); + DBUG_RETURN(num_rows); } m_prebuilt->trx->op_info = ""; if (thd_killed(m_user_thd)) { - *num_rows = HA_POS_ERROR; - DBUG_RETURN(HA_ERR_QUERY_INTERRUPTED); + num_rows = HA_POS_ERROR; + DBUG_RETURN(num_rows); } - *num_rows= n_rows; - DBUG_RETURN(0); + num_rows= n_rows; + DBUG_RETURN(num_rows); } -#endif /* MYSQL_57_SELECT_COUNT_OPTIMIZATION */ /*********************************************************************//** Estimates the number of index records in a range. diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index 463717ee6b2..f4600a6415b 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -220,7 +220,7 @@ public: ha_rows estimate_rows_upper_bound(); // JAN: TODO: MySQL 5.7 - // int records(ha_rows* num_rows); + ha_rows records_new(); // FIXME: rename to records(), fix main.bug39022 void update_create_info(HA_CREATE_INFO* create_info); @@ -454,7 +454,7 @@ protected: void reset_template(); protected: - inline void update_thd(THD* thd); + void update_thd(THD* thd); void update_thd(); int general_fetch(uchar* buf, uint direction, uint match_mode); diff --git a/storage/innobase/handler/ha_innopart.cc b/storage/innobase/handler/ha_innopart.cc index 7abc1f29b60..38af9e44de9 100644 --- a/storage/innobase/handler/ha_innopart.cc +++ b/storage/innobase/handler/ha_innopart.cc @@ -54,6 +54,21 @@ Created Nov 22, 2013 Mattias Jonsson */ #include "partition_info.h" #include "key.h" +/********************************************************************//** +Get the upper limit of the MySQL integral and floating-point type. +@return maximum allowed value for the field */ +UNIV_INTERN +ulonglong +innobase_get_int_col_max_value( +/*===========================*/ + const Field* field); /*!< in: MySQL field */ + +static +void set_my_errno(int err) +{ + errno = err; +} + #define INSIDE_HA_INNOPART_CC /* To be backwards compatible we also fold partition separator on windows. */ @@ -242,7 +257,7 @@ Ha_innopart_share::set_v_templ( innobase_build_v_templ( table, ib_table, m_table_parts[i]->vc_templ, - NULL, true, name); + NULL, true); } } } @@ -814,6 +829,25 @@ ha_innopart::ha_innopart( m_share = NULL; } +ha_innopart::ha_innopart( + ha_innobase* innobase) + : + ha_innobase(*innobase), + Partition_helper(this), + m_ins_node_parts(), + m_upd_node_parts(), + m_blob_heap_parts(), + m_trx_id_parts(), + m_row_read_type_parts(), + m_sql_stat_start_parts(), + m_pcur(), + m_clust_pcur(), + m_new_partitions() +{ + m_int_table_flags &= ~(HA_INNOPART_DISABLED_TABLE_FLAGS); + m_share = NULL; +} + /** Destruct ha_innopart handler. */ ha_innopart::~ha_innopart() {} @@ -845,7 +879,7 @@ ha_innopart::initialize_auto_increment( #ifndef DBUG_OFF if (table_share->tmp_table == NO_TMP_TABLE) { - mysql_mutex_assert_owner(m_part_share->auto_inc_mutex); + mysql_mutex_assert_owner(&m_part_share->auto_inc_mutex); } #endif @@ -882,7 +916,7 @@ ha_innopart::initialize_auto_increment( my_error(ER_AUTOINC_READ_FAILED, MYF(0)); error = HA_ERR_AUTOINC_READ_FAILED; } else { - ib_uint64_t col_max_value = field->get_max_int_value(); + ib_uint64_t col_max_value = innobase_get_int_col_max_value(field); update_thd(ha_thd()); @@ -911,7 +945,6 @@ ha_innopart::initialize_auto_increment( } } -done: m_part_share->next_auto_inc_val = auto_inc; m_part_share->auto_inc_initialized = true; return(error); @@ -973,12 +1006,7 @@ share_error: || m_part_share->populate_partition_name_hash(m_part_info)) { goto share_error; } - if (m_part_share->auto_inc_mutex == NULL - && table->found_next_number_field != NULL) { - if (m_part_share->init_auto_inc_mutex(table_share)) { - goto share_error; - } - } + unlock_shared_ha_data(); /* Will be allocated if it is needed in ::update_row(). */ @@ -1098,7 +1126,7 @@ share_error: by printing a warning in addition to log a message in the errorlog. */ - push_warning_printf(thd, Sql_condition::SL_WARNING, + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_NO_SUCH_INDEX, "Table %s has a" " primary key in InnoDB data" @@ -1173,7 +1201,7 @@ share_error: by printing a warning in addition to log a message in the errorlog. */ - push_warning_printf(thd, Sql_condition::SL_WARNING, + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_NO_SUCH_INDEX, "InnoDB: Table %s has no" " primary key in InnoDB data" @@ -1288,7 +1316,7 @@ share_error: } info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST); - DBUG_RETURN(0); + DBUG_RETURN(init_record_priority_queue_for_parts(m_tot_parts)); } /** Get a cloned ha_innopart handler. @@ -1304,7 +1332,7 @@ ha_innopart::clone( DBUG_ENTER("ha_innopart::clone"); - new_handler = dynamic_cast(handler::clone(name, + new_handler = static_cast(handler::clone(name, mem_root)); if (new_handler != NULL) { ut_ad(new_handler->m_prebuilt != NULL); @@ -1381,6 +1409,8 @@ ha_innopart::close() innobase_release_temporary_latches(ht, thd); } + destroy_record_priority_queue_for_parts(); + ut_ad(m_pcur_parts == NULL); ut_ad(m_clust_pcur_parts == NULL); close_partitioning(); @@ -1838,18 +1868,18 @@ ha_innopart::print_error( /** Can error be ignored. @param[in] error Error code to check. @return true if ignorable else false. */ -bool -ha_innopart::is_ignorable_error( - int error) -{ - if (ha_innobase::is_ignorable_error(error) - || error == HA_ERR_NO_PARTITION_FOUND - || error == HA_ERR_NOT_IN_LOCK_PARTITIONS) { - - return(true); - } - return(false); -} +// bool +// ha_innopart::is_ignorable_error( +// int error) +// { +// if (ha_innobase::is_ignorable_error(error) +// || error == HA_ERR_NO_PARTITION_FOUND +// || error == HA_ERR_NOT_IN_LOCK_PARTITIONS) { +// +// return(true); +// } +// return(false); +// } /** Get the index for the current partition @param[in] keynr MySQL index number. @@ -1960,7 +1990,7 @@ ha_innopart::change_active_index( m_prebuilt->index->table->name.m_name); push_warning_printf( - m_user_thd, Sql_condition::SL_WARNING, + m_user_thd, Sql_condition::WARN_LEVEL_WARN, HA_ERR_INDEX_CORRUPT, "InnoDB: Index %s for table %s is" " marked as corrupted" @@ -1969,7 +1999,7 @@ ha_innopart::change_active_index( DBUG_RETURN(HA_ERR_INDEX_CORRUPT); } else { push_warning_printf( - m_user_thd, Sql_condition::SL_WARNING, + m_user_thd, Sql_condition::WARN_LEVEL_WARN, HA_ERR_TABLE_DEF_CHANGED, "InnoDB: insufficient history for index %u", keynr); @@ -2901,28 +2931,6 @@ int ha_innopart::extra( enum ha_extra_function operation) { - if (operation == HA_EXTRA_SECONDARY_SORT_ROWID) { - /* index_init(sorted=true) must have been called! */ - ut_ad(m_ordered); - ut_ad(m_ordered_rec_buffer != NULL); - /* No index_read call must have been done! */ - ut_ad(m_queue->empty()); - - /* If not PK is set as secondary sort, do secondary sort by - rowid/ref. */ - - ut_ad(m_curr_key_info[1] != NULL - || m_prebuilt->clust_index_was_generated != 0 - || m_curr_key_info[0] - == table->key_info + table->s->primary_key); - - if (m_curr_key_info[1] == NULL - && m_prebuilt->clust_index_was_generated) { - m_ref_usage = Partition_helper::REF_USED_FOR_SORT; - m_queue->m_fun = key_and_rowid_cmp; - } - return(0); - } return(ha_innobase::extra(operation)); } @@ -3007,17 +3015,15 @@ ha_innopart::truncate() /** Total number of rows in all used partitions. Returns the exact number of records that this client can see using this handler object. -@param[out] num_rows Number of rows. -@return 0 or error number. */ -int -ha_innopart::records( - ha_rows* num_rows) +@return Number of rows. */ +ha_rows +ha_innopart::records() { + ha_rows num_rows; ha_rows n_rows; - int err; DBUG_ENTER("ha_innopart::records()"); - *num_rows = 0; + num_rows = 0; /* The index scan is probably so expensive, so the overhead of the rest of the function is neglectable for each partition. @@ -3028,15 +3034,44 @@ ha_innopart::records( i = m_part_info->get_next_used_partition(i)) { set_partition(i); - err = ha_innobase::records(&n_rows); + n_rows = ha_innobase::records(); update_partition(i); - if (err != 0) { - *num_rows = HA_POS_ERROR; - DBUG_RETURN(err); + if (n_rows == HA_POS_ERROR) { + DBUG_RETURN(HA_POS_ERROR); } - *num_rows += n_rows; + num_rows += n_rows; } - DBUG_RETURN(0); + DBUG_RETURN(num_rows); +} + +ha_rows +ha_innopart::part_recs_slow(void *_part_elem) +{ + partition_element *part_elem= reinterpret_cast(_part_elem); + DBUG_ASSERT(m_part_info); + uint32 sub_factor= m_part_info->num_subparts ? m_part_info->num_subparts : 1; + uint32 part_id= part_elem->id * sub_factor; + uint32 part_id_end= part_id + sub_factor; + DBUG_ASSERT(part_id_end <= m_tot_parts); + ha_rows part_recs= 0; + uint last_part = m_last_part; + for (; part_id < part_id_end; ++part_id) + { + DBUG_ASSERT(bitmap_is_set(&(m_part_info->read_partitions), part_id)); + set_partition(part_id); + ha_rows n = ha_innobase::records_new(); + update_partition(part_id); + if (n == HA_POS_ERROR) { + return HA_POS_ERROR; + } + part_recs += n; + } + if (m_last_part != last_part) + { + set_partition(last_part); + update_partition(last_part); + } + return part_recs; } /** Estimates the number of index records in a range. @@ -3098,14 +3133,14 @@ ha_innopart::records_in_range( goto func_exit; } - heap = mem_heap_create(2 * (key->actual_key_parts * sizeof(dfield_t) + heap = mem_heap_create(2 * (key->user_defined_key_parts * sizeof(dfield_t) + sizeof(dtuple_t))); - range_start = dtuple_create(heap, key->actual_key_parts); - dict_index_copy_types(range_start, index, key->actual_key_parts); + range_start = dtuple_create(heap, key->user_defined_key_parts); + dict_index_copy_types(range_start, index, key->user_defined_key_parts); - range_end = dtuple_create(heap, key->actual_key_parts); - dict_index_copy_types(range_end, index, key->actual_key_parts); + range_end = dtuple_create(heap, key->user_defined_key_parts); + dict_index_copy_types(range_end, index, key->user_defined_key_parts); row_sel_convert_mysql_key_to_innobase( range_start, @@ -3361,8 +3396,7 @@ ha_innopart::info_low( DBUG_RETURN(error); } } - set_if_bigger(stats.update_time, - (ulong) ib_table->update_time); + set_if_bigger(stats.update_time, ib_table->update_time); } if (is_analyze || innobase_stats_on_metadata) { @@ -3437,7 +3471,7 @@ ha_innopart::info_low( push_warning_printf( thd, - Sql_condition::SL_WARNING, + Sql_condition::WARN_LEVEL_WARN, ER_CANT_GET_STAT, "InnoDB: Trying to get the" " free space for partition %s" @@ -3613,7 +3647,7 @@ ha_innopart::info_low( KEY* key = &table->key_info[i]; for (j = 0; - j < key->actual_key_parts; + j < key->user_defined_key_parts; j++) { if ((key->flags & HA_FULLTEXT) != 0) { @@ -3638,32 +3672,6 @@ ha_innopart::info_low( break; } - /* innodb_rec_per_key() will use - index->stat_n_diff_key_vals[] and the value we - pass index->table->stat_n_rows. Both are - calculated by ANALYZE and by the background - stats gathering thread (which kicks in when too - much of the table has been changed). In - addition table->stat_n_rows is adjusted with - each DML (e.g. ++ on row insert). Those - adjustments are not MVCC'ed and not even - reversed on rollback. So, - index->stat_n_diff_key_vals[] and - index->table->stat_n_rows could have been - calculated at different time. This is - acceptable. */ - const rec_per_key_t rec_per_key = - innodb_rec_per_key( - index, j, - max_rows); - - key->set_records_per_key(j, rec_per_key); - - /* The code below is legacy and should be - removed together with this comment once we - are sure the new floating point rec_per_key, - set via set_records_per_key(), works fine. */ - ulong rec_per_key_int = static_cast( innodb_rec_per_key(index, j, max_rows)); @@ -3851,7 +3859,7 @@ ha_innopart::repair( /* TODO: enable this warning to be clear about what is repaired. Currently disabled to generate smaller test diffs. */ #ifdef ADD_WARNING_FOR_REPAIR_ONLY_PARTITION - push_warning_printf(thd, Sql_condition::SL_WARNING, + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_ILLEGAL_HA, "Only moving rows from wrong partition to correct" " partition is supported," diff --git a/storage/innobase/handler/ha_innopart.h b/storage/innobase/handler/ha_innopart.h index 5f3f8eaa318..ab445cf25ca 100644 --- a/storage/innobase/handler/ha_innopart.h +++ b/storage/innobase/handler/ha_innopart.h @@ -23,6 +23,7 @@ this program; if not, write to the Free Software Foundation, Inc., #define ha_innopart_h #include "partitioning/partition_handler.h" +#include "ha_partition.h" /* Forward declarations */ class Altered_partitions; @@ -185,14 +186,16 @@ truncate_partition. InnoDB specific functions related to partitioning is implemented here. */ class ha_innopart: public ha_innobase, - public Partition_helper, - public Partition_handler + public Partition_helper { public: ha_innopart( handlerton* hton, TABLE_SHARE* table_arg); + ha_innopart( + ha_innobase* innobase); + ~ha_innopart(); /** Clone this handler, used when needing more than one cursor @@ -218,7 +221,7 @@ public: register_query_cache_table( THD* thd, char* table_key, - size_t key_length, + uint key_length, qc_engine_callback* call_back, ulonglong* engine_data) { @@ -350,9 +353,9 @@ public: int error, myf errflag); - bool - is_ignorable_error( - int error); +// bool +// is_ignorable_error( +// int error); int start_stmt( @@ -506,7 +509,7 @@ public: ft_init_ext_with_hints( uint inx, String* key, - Ft_hints* hints) + void* hints) { ut_ad(0); return(NULL); @@ -596,13 +599,13 @@ public: /** See Partition_handler. */ void get_dynamic_partition_info( - ha_statistics* stat_info, - ha_checksum* check_sum, + PARTITION_STATS* stat_info, uint part_id) { + ha_checksum check_sum; Partition_helper::get_dynamic_partition_info_low( stat_info, - check_sum, + &check_sum, part_id); } @@ -614,18 +617,11 @@ public: | HA_FAST_CHANGE_PARTITION); } - Partition_handler* - get_partition_handler() - { - return(static_cast(this)); - } - void set_part_info( - partition_info* part_info, - bool early) + partition_info* part_info) { - Partition_helper::set_part_info_low(part_info, early); + Partition_helper::set_part_info_low(part_info, false); } void @@ -752,10 +748,16 @@ private: /** Update active partition. Copies needed info from m_prebuilt into the partition specific memory. @param[in] part_id Partition to set as active. */ - void + virtual void update_partition( uint part_id); + virtual handler* part_handler(uint32 part_id) + { + set_partition(part_id); + return this; + } + /** Helpers needed by Partition_helper, @see partition_handler.h @{ */ /** Set the autoinc column max value. @@ -1132,6 +1134,20 @@ private: delete_row( const uchar* record) { + ut_a(table); + if (table->versioned() && table->vers_end_field()->is_max()) { + int err = rnd_pos_by_record(const_cast(record)); + if (err) + return err; + trx_t* trx = thd_to_trx(ha_thd()); + if (!trx->id) + trx_start_if_not_started_xa(trx, true); + ut_a(table->record[0] == record); + store_record(table, record[1]); + ut_a(trx->id); + table->vers_end_field()->store(trx->id, true); + return Partition_helper::ph_update_row(table->record[1], table->record[0]); + } return(Partition_helper::ph_delete_row(record)); } /** @} */ @@ -1162,6 +1178,148 @@ private: deleted)); } +public: + /** + Truncate partitions. + + Truncate all partitions matching table->part_info->read_partitions. + Handler level wrapper for truncating partitions, will ensure that + mark_trx_read_write() is called and also checks locking assertions. + + @return Operation status. + @retval 0 Success. + @retval != 0 Error code. + */ + int truncate_partition() + { + handler *file= get_handler(); + if (!file) + { + return HA_ERR_WRONG_COMMAND; + } + DBUG_ASSERT(file->get_table_share()->tmp_table != NO_TMP_TABLE || + file->get_lock_type() == F_WRLCK); + file->mark_trx_read_write(); + return truncate_partition_low(); + } + /** + Change partitions. + + Change partitions according to their partition_element::part_state set up + in prep_alter_part_table(). Will create new partitions and copy requested + partitions there. Also updating part_state to reflect current state. + + Handler level wrapper for changing partitions. + This is the reason for having Partition_handler a friend class of handler, + mark_trx_read_write() is called and also checks locking assertions. + to ensure that mark_trx_read_write() is called and checking the asserts. + + @param[in] create_info Table create info. + @param[in] path Path including table name. + @param[out] copied Number of rows copied. + @param[out] deleted Number of rows deleted. + */ + int change_partitions(HA_CREATE_INFO *create_info, + const char *path, + ulonglong * const copied, + ulonglong * const deleted, + const uchar *pack_frm_data, + size_t pack_frm_len) + { + handler *file= get_handler(); + if (!file) + { + my_error(ER_ILLEGAL_HA, MYF(0), create_info->alias); + return HA_ERR_WRONG_COMMAND; + } + DBUG_ASSERT(file->get_table_share()->tmp_table != NO_TMP_TABLE || + file->get_lock_type() != F_UNLCK); + file->mark_trx_read_write(); + return change_partitions_low(create_info, path, copied, deleted); + } + + // FIXME: duplicate of ha_partition::drop_partitions + int drop_partitions(const char *path) + { + List_iterator part_it(m_part_info->partitions); + char part_name_buff[FN_REFLEN]; + uint num_parts= m_part_info->partitions.elements; + uint num_subparts= m_part_info->num_subparts; + uint i= 0; + uint name_variant; + int ret_error; + int error= 0; + DBUG_ENTER("ha_partition::drop_partitions"); + + /* + Assert that it works without HA_FILE_BASED and lower_case_table_name = 2. + We use m_file[0] as long as all partitions have the same storage engine. + */ + DBUG_ASSERT(!strcmp(path, get_canonical_filename(this, path, + part_name_buff))); + do + { + partition_element *part_elem= part_it++; + if (part_elem->part_state == PART_TO_BE_DROPPED) + { + handler *file = this; + /* + This part is to be dropped, meaning the part or all its subparts. + */ + name_variant= NORMAL_PART_NAME; + if (m_is_sub_partitioned) + { + List_iterator sub_it(part_elem->subpartitions); + uint j= 0/*, part*/; + do + { + partition_element *sub_elem= sub_it++; + //part= i * num_subparts + j; + create_subpartition_name(part_name_buff, path, + part_elem->partition_name, + sub_elem->partition_name, name_variant); + // set_partition(part); + DBUG_PRINT("info", ("Drop subpartition %s", part_name_buff)); + if ((ret_error= file->ha_delete_table(part_name_buff))) + error= ret_error; + if (deactivate_ddl_log_entry(sub_elem->log_entry->entry_pos)) + error= 1; + // update_partition(part); + } while (++j < num_subparts); + } + else + { + create_partition_name(part_name_buff, path, + part_elem->partition_name, name_variant, + TRUE); + // set_partition(i); + DBUG_PRINT("info", ("Drop partition %s", part_name_buff)); + if ((ret_error= file->ha_delete_table(part_name_buff))) + error= ret_error; + if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos)) + error= 1; + // update_partition(i); + } + if (part_elem->part_state == PART_IS_CHANGED) + part_elem->part_state= PART_NORMAL; + else + part_elem->part_state= PART_IS_DROPPED; + } + } while (++i < num_parts); + (void) sync_ddl_log(); + DBUG_RETURN(error); + } + + int rename_partitions(const char *path) + { + return 0; + } + + virtual ha_rows + part_recs_slow(void *_part_elem); + + +private: /** Access methods to protected areas in handler to avoid adding friend class Partition_helper in class handler. @see partition_handler.h @{ */ @@ -1221,9 +1379,8 @@ protected: uchar* record, uchar* pos); - int - records( - ha_rows* num_rows); + ha_rows + records(); int index_next( diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 672c3672c7c..a2af99f2369 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -64,10 +64,9 @@ static const char *MSG_UNSUPPORTED_ALTER_ONLINE_ON_VIRTUAL_COLUMN= "combined with other ALTER TABLE actions"; /* For supporting Native InnoDB Partitioning. */ -/* JAN: TODO: MySQL 5.7 #include "partition_info.h" #include "ha_innopart.h" -*/ + /** Operations for creating secondary indexes (no rebuild needed) */ static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_ONLINE_CREATE = Alter_inplace_info::ADD_INDEX @@ -9230,9 +9229,6 @@ ha_innopart::prepare_inplace_alter_table( ctx_parts->prebuilt_array[i] = tmp_prebuilt; } - const char* save_tablespace = - ha_alter_info->create_info->tablespace; - const char* save_data_file_name = ha_alter_info->create_info->data_file_name; @@ -9242,15 +9238,6 @@ ha_innopart::prepare_inplace_alter_table( ha_alter_info->handler_ctx = ctx_parts->ctx_array[i]; set_partition(i); - /* Set the tablespace and data_file_name value of the - alter_info to the tablespace value and data_file_name - value that was existing for the partition originally, - so that for ALTER TABLE the tablespace clause in create - option is ignored for existing partitions, and later - set it back to its old value */ - - ha_alter_info->create_info->tablespace = - m_prebuilt->table->tablespace; ha_alter_info->create_info->data_file_name = m_prebuilt->table->data_dir_path; @@ -9266,7 +9253,6 @@ ha_innopart::prepare_inplace_alter_table( m_prebuilt_ptr = &m_prebuilt; ha_alter_info->handler_ctx = ctx_parts; ha_alter_info->group_commit_ctx = ctx_parts->ctx_array; - ha_alter_info->create_info->tablespace = save_tablespace; ha_alter_info->create_info->data_file_name = save_data_file_name; DBUG_RETURN(res); } diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h index 6992f4a6689..8b2987f4402 100644 --- a/storage/innobase/include/ha_prototypes.h +++ b/storage/innobase/include/ha_prototypes.h @@ -40,13 +40,14 @@ class THD; // JAN: TODO missing features: #undef MYSQL_57_SELECT_COUNT_OPTIMIZATION #undef MYSQL_FT_INIT_EXT -#undef MYSQL_INNODB_PARTITIONING #undef MYSQL_PFS #undef MYSQL_RENAME_INDEX #undef MYSQL_REPLACE_TRX_IN_THD #undef MYSQL_SPATIAL_INDEX #undef MYSQL_STORE_FTS_DOC_ID +#define MYSQL_INNODB_PARTITIONING + /*******************************************************************//** Formats the raw data in "data" (in InnoDB on-disk format) that is of type DATA_(CHAR|VARCHAR|MYSQL|VARMYSQL) using "charset_coll" and writes diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index 922236283ea..58dc7f13d7d 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -234,6 +234,15 @@ row_lock_table_for_mysql( (ignored if table==NULL) */ MY_ATTRIBUTE((nonnull(1))); +/* System Versioning: row_insert_for_mysql() modes */ +enum ins_mode_t { + ROW_INS_NORMAL = 0, + // insert versioned row: sys_trx_start = TRX_ID, sys_trx_end = MAX + ROW_INS_VERSIONED, + // insert historical row: sys_trx_end = TRX_ID + ROW_INS_HISTORICAL +}; + /** Does an insert for MySQL. @param[in] mysql_rec row in the MySQL format @param[in,out] prebuilt prebuilt struct in MySQL handle @@ -242,9 +251,7 @@ dberr_t row_insert_for_mysql( const byte* mysql_rec, row_prebuilt_t* prebuilt, - bool historical - /*!< in: System Versioning, row is */ - = false) /* historical */ + ins_mode_t ins_mode) MY_ATTRIBUTE((warn_unused_result)); /*********************************************************************//** @@ -281,7 +288,7 @@ dberr_t row_update_for_mysql( const byte* mysql_rec, row_prebuilt_t* prebuilt, - bool delete_history_row = false) + bool vers_set_fields) MY_ATTRIBUTE((warn_unused_result)); /** This can only be used when srv_locks_unsafe_for_binlog is TRUE or this diff --git a/storage/innobase/include/sync0policy.h b/storage/innobase/include/sync0policy.h index 410e46f9c68..2860aa066f9 100644 --- a/storage/innobase/include/sync0policy.h +++ b/storage/innobase/include/sync0policy.h @@ -59,7 +59,11 @@ public: @param[in] id ID of the latch to track */ Context(latch_id_t id) : - latch_t(id) + latch_t(id), + m_mutex(), + m_filename(), + m_line(), + m_thread_id(os_thread_id_t(ULINT_UNDEFINED)) { /* No op */ } diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index fceaf65c407..ce1a0dda7b2 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -1407,7 +1407,7 @@ dberr_t row_insert_for_mysql( const byte* mysql_rec, row_prebuilt_t* prebuilt, - bool historical) + ins_mode_t ins_mode) { trx_savept_t savept; que_thr_t* thr; @@ -1487,14 +1487,15 @@ row_insert_for_mysql( row_mysql_convert_row_to_innobase(node->row, prebuilt, mysql_rec, &blob_heap); - if (DICT_TF2_FLAG_IS_SET(node->table, DICT_TF2_VERSIONED)) { + if (ins_mode != ROW_INS_NORMAL) + { ut_ad(table->vers_row_start != table->vers_row_end); /* Return back modified fields into mysql_rec, so that upper logic may benefit from it (f.ex. 'on duplicate key'). */ const mysql_row_templ_t* t = &prebuilt->mysql_template[table->vers_row_end]; ut_ad(t->mysql_col_len == 8); - if (historical) { + if (ins_mode == ROW_INS_HISTORICAL) { set_tuple_col_8(node->row, table->vers_row_end, trx->id, node->entry_sys_heap); int8store(&mysql_rec[t->mysql_col_offset], trx->id); } @@ -1860,7 +1861,7 @@ dberr_t row_update_for_mysql_using_upd_graph( const byte* mysql_rec, row_prebuilt_t* prebuilt, - bool delete_history_row) + bool vers_set_fields) { trx_savept_t savept; dberr_t err; @@ -1993,8 +1994,7 @@ row_update_for_mysql_using_upd_graph( thr->fk_cascade_depth = 0; run_again: - if (DICT_TF2_FLAG_IS_SET(node->table, DICT_TF2_VERSIONED) && - (node->is_delete || node->versioned) && !delete_history_row) + if (vers_set_fields) { /* System Versioning: modify update vector to set sys_trx_start (or sys_trx_end in case of DELETE) @@ -2130,6 +2130,8 @@ run_again: cascade_upd_nodes->pop_front(); thr->fk_cascade_depth++; prebuilt->m_mysql_table = NULL; + vers_set_fields = DICT_TF2_FLAG_IS_SET(node->table, DICT_TF2_VERSIONED) + && (node->is_delete || node->versioned); goto run_again; } @@ -2259,11 +2261,11 @@ dberr_t row_update_for_mysql( const byte* mysql_rec, row_prebuilt_t* prebuilt, - bool delete_history_row) + bool vers_set_fields) { ut_a(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW); return (row_update_for_mysql_using_upd_graph( - mysql_rec, prebuilt, delete_history_row)); + mysql_rec, prebuilt, vers_set_fields)); } /** This can only be used when srv_locks_unsafe_for_binlog is TRUE or this -- cgit v1.2.1 From b8bfc06b26dc47ff42a671fdd7f62b75152f7570 Mon Sep 17 00:00:00 2001 From: kevg Date: Mon, 27 Feb 2017 16:31:37 +0300 Subject: SQL, Tests: temporal_current_timestamp for setting default AS OF timestamp [closes #117] --- mysql-test/suite/versioning/r/variables.result | 38 ++++++++++++++++++++++++++ mysql-test/suite/versioning/t/variables.test | 28 +++++++++++++++++++ sql/mysqld.cc | 3 ++ sql/mysqld.h | 1 + sql/sql_select.cc | 23 ++++++++++++++++ sql/sys_vars.cc | 5 ++++ 6 files changed, 98 insertions(+) create mode 100644 mysql-test/suite/versioning/r/variables.result create mode 100644 mysql-test/suite/versioning/t/variables.test diff --git a/mysql-test/suite/versioning/r/variables.result b/mysql-test/suite/versioning/r/variables.result new file mode 100644 index 00000000000..c0d15cbf1e8 --- /dev/null +++ b/mysql-test/suite/versioning/r/variables.result @@ -0,0 +1,38 @@ +create table t (a int) with system versioning; +insert into t values (1); +update t set a=2; +select * from t; +a +2 +show variables where Variable_name like "temporal_current_timestamp%"; +Variable_name Value +temporal_current_timestamp now +set global temporal_current_timestamp = '2031-1-1 0:0:0'; +select * from t; +a +2 +set global temporal_current_timestamp = '2011-1-1 0:0:0'; +select * from t; +a +set global temporal_current_timestamp = 'all'; +select * from t; +a +2 +1 +show variables where Variable_name like "temporal_current_timestamp%"; +Variable_name Value +temporal_current_timestamp all +create view vt as select * from t; +select * from t; +a +2 +1 +drop view vt; +select * from (select * from t) as tt; +a +2 +1 +set session temporal_current_timestamp = 'now'; +ERROR HY000: Variable 'temporal_current_timestamp' is a GLOBAL variable and should be set with SET GLOBAL +drop table t; +set global temporal_current_timestamp = 'now'; diff --git a/mysql-test/suite/versioning/t/variables.test b/mysql-test/suite/versioning/t/variables.test new file mode 100644 index 00000000000..7b7b458f642 --- /dev/null +++ b/mysql-test/suite/versioning/t/variables.test @@ -0,0 +1,28 @@ +create table t (a int) with system versioning; +insert into t values (1); +update t set a=2; + +select * from t; +show variables where Variable_name like "temporal_current_timestamp%"; + +set global temporal_current_timestamp = '2031-1-1 0:0:0'; +select * from t; + +set global temporal_current_timestamp = '2011-1-1 0:0:0'; +select * from t; + +set global temporal_current_timestamp = 'all'; +select * from t; +show variables where Variable_name like "temporal_current_timestamp%"; + +create view vt as select * from t; +select * from t; +drop view vt; + +select * from (select * from t) as tt; + +--error ER_GLOBAL_VARIABLE +set session temporal_current_timestamp = 'now'; + +drop table t; +set global temporal_current_timestamp = 'now'; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 5196ec41c11..b7eccea80c6 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -781,6 +781,9 @@ char *relay_log_info_file, *report_user, *report_password, *report_host; char *opt_relay_logname = 0, *opt_relaylog_index_name=0; char *opt_logname, *opt_slow_logname, *opt_bin_logname; +/* System Versioning */ +char *temporal_current_timestamp; + /* Static variables */ static volatile sig_atomic_t kill_in_progress; diff --git a/sql/mysqld.h b/sql/mysqld.h index 46382396a5a..ece0992dd82 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -175,6 +175,7 @@ extern char *opt_backup_history_logname, *opt_backup_progress_logname, *opt_backup_settings_name; extern const char *log_output_str; extern const char *log_backup_output_str; +extern char *temporal_current_timestamp; extern char *mysql_home_ptr, *pidfile_name_ptr; extern MYSQL_PLUGIN_IMPORT char glob_hostname[FN_REFLEN]; extern char mysql_home[FN_REFLEN]; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 2ba2f2e7234..3d5f158df36 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -62,6 +62,7 @@ #include #include #include +#include "sys_vars_shared.h" /* A key part number that means we're using a fulltext scan. @@ -775,6 +776,28 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, DBUG_RETURN(-1); } + if (vers_conditions.type == FOR_SYSTEM_TIME_UNSPECIFIED) + { + const char var[]= "temporal_current_timestamp"; + sys_var *sv= intern_find_sys_var(var, sizeof(var) - 1); + DBUG_ASSERT(sv); + const char *data= *(char **)sv->option.value; + DBUG_ASSERT(data); + if (0 == strcmp(data, "all")) + { + vers_conditions.init(FOR_SYSTEM_TIME_ALL, UNIT_TIMESTAMP); + } + else if (0 != strcmp(data, "now")) + { + Item *ts= create_temporal_literal(thd, data, strlen(data), + system_charset_info, + MYSQL_TYPE_DATETIME, true); + if (!ts) + DBUG_RETURN(-1); + vers_conditions.init(FOR_SYSTEM_TIME_AS_OF, UNIT_TIMESTAMP, ts); + } + } + if (vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED) { switch (slex->lock_type) diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index da8fa18cb26..bc2b37d9d6d 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -382,6 +382,11 @@ static Sys_var_charptr Sys_basedir( READ_ONLY GLOBAL_VAR(mysql_home_ptr), CMD_LINE(REQUIRED_ARG, 'b'), IN_FS_CHARSET, DEFAULT(0)); +static Sys_var_charptr sys_temporal_current_timestamp( + "temporal_current_timestamp", "Default AS OF value for versioned tables", + GLOBAL_VAR(temporal_current_timestamp), CMD_LINE(REQUIRED_ARG, 'b'), + IN_FS_CHARSET, DEFAULT("now")); + static Sys_var_ulonglong Sys_binlog_cache_size( "binlog_cache_size", "The size of the transactional cache for " "updates to transactional engines for the binary log. " -- cgit v1.2.1 From 204b54d2d9f966f5fec0baef3974eff98ec125ad Mon Sep 17 00:00:00 2001 From: kevg Date: Sat, 4 Mar 2017 23:05:45 +0300 Subject: SQL: create versioned tmp table from query [fixes #144] --- mysql-test/suite/versioning/r/create.result | 2 ++ mysql-test/suite/versioning/t/create.test | 3 +++ sql/handler.cc | 3 ++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/versioning/r/create.result b/mysql-test/suite/versioning/r/create.result index 1fcf0c1e6a8..2614babef72 100644 --- a/mysql-test/suite/versioning/r/create.result +++ b/mysql-test/suite/versioning/r/create.result @@ -223,4 +223,6 @@ create or replace table t1 ( A int ) without system versioning without system versioning; ERROR HY000: Wrong parameters for `t1`: Versioning specified more than once for the same table +create or replace table t1 (a int) with system versioning; +create temporary table tmp with system versioning select * from t1; drop table t1; diff --git a/mysql-test/suite/versioning/t/create.test b/mysql-test/suite/versioning/t/create.test index db07f5b2521..aa873dfdcaf 100644 --- a/mysql-test/suite/versioning/t/create.test +++ b/mysql-test/suite/versioning/t/create.test @@ -204,4 +204,7 @@ create or replace table t1 ( A int ) without system versioning without system versioning; +create or replace table t1 (a int) with system versioning; +create temporary table tmp with system versioning select * from t1; + drop table t1; diff --git a/sql/handler.cc b/sql/handler.cc index ba947fd7a2d..f7620a0543b 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6724,7 +6724,8 @@ bool Vers_parse_info::check_and_fix_implicit( generated_as_row.start || generated_as_row.end || period_for_system_time.start || period_for_system_time.end; - if (with == 0 && (not_set == 0 || !table_with_system_versioning)) + if (!thd->lex->tmp_table() && with == 0 && + (not_set == 0 || !table_with_system_versioning)) { my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, "versioned fields missing"); -- cgit v1.2.1 From 17745222a1a1dbc72ecbe5a9c0ca0daeacc675a8 Mon Sep 17 00:00:00 2001 From: kevg Date: Sun, 5 Mar 2017 23:51:02 +0300 Subject: SQL: incorrect check on specific JOIN query [fixes #145] --- mysql-test/suite/versioning/r/select.result | 3 +++ mysql-test/suite/versioning/t/select.test | 3 +++ sql/sql_base.cc | 5 +++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index 72f8e0424d6..4258f84b16e 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -406,6 +406,9 @@ create or replace table t1 (x int) with system versioning; insert into t1 values (1); select * from t1 for system_time all for update; ERROR HY000: Wrong parameters for `FOR SYSTEM_TIME query`: write-locking of historic rows +create or replace table t1 (a int not null auto_increment primary key) with system versioning; +select * from (t1 as t2 left join t1 as t3 using (a)) natural left join t1; +a drop table t1; call verify_vtq; No A B C D diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index ca3f8d2b3b7..9af249c1056 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -131,6 +131,9 @@ insert into t1 values (1); --error ER_VERS_WRONG_PARAMS select * from t1 for system_time all for update; +create or replace table t1 (a int not null auto_increment primary key) with system versioning; +select * from (t1 as t2 left join t1 as t3 using (a)) natural left join t1; + drop table t1; call verify_vtq; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 02adbb656c1..e8ec8104f8b 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -6420,8 +6420,9 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, if (!my_strcasecmp(system_charset_info, field_name_1, cur_field_name_2)) { DBUG_PRINT ("info", ("match c1.is_common=%d", nj_col_1->is_common)); - if (cur_nj_col_2->is_common || - (found && (!using_fields || is_using_column_1))) + if ((!it_1.field() || !it_1.field()->vers_sys_field()) && + (cur_nj_col_2->is_common || + (found && (!using_fields || is_using_column_1)))) { my_error(ER_NON_UNIQ_ERROR, MYF(0), field_name_1, thd->where); goto err; -- cgit v1.2.1 From 9355e3e9661f80bc3a6813411c7d5f33f6fec60d Mon Sep 17 00:00:00 2001 From: kevg Date: Mon, 6 Mar 2017 15:53:53 +0300 Subject: SQL: CREATE TABLE LIKE for versioned tables [fixes #146] --- mysql-test/suite/versioning/r/create.result | 11 +++++++++++ mysql-test/suite/versioning/t/create.test | 5 +++++ sql/handler.cc | 27 +++++++++++++++++++++++++++ sql/handler.h | 2 ++ sql/sql_parse.cc | 9 +++++---- sql/sql_table.cc | 7 +++++++ 6 files changed, 57 insertions(+), 4 deletions(-) diff --git a/mysql-test/suite/versioning/r/create.result b/mysql-test/suite/versioning/r/create.result index 2614babef72..ad27bc065c3 100644 --- a/mysql-test/suite/versioning/r/create.result +++ b/mysql-test/suite/versioning/r/create.result @@ -225,4 +225,15 @@ A int ERROR HY000: Wrong parameters for `t1`: Versioning specified more than once for the same table create or replace table t1 (a int) with system versioning; create temporary table tmp with system versioning select * from t1; +create or replace table t1 (a int) with system versioning; +create table tt1 like t1; +show create table tt1; +Table Create Table +tt1 CREATE TABLE `tt1` ( + `a` int(11) DEFAULT NULL, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +drop table tt1; drop table t1; diff --git a/mysql-test/suite/versioning/t/create.test b/mysql-test/suite/versioning/t/create.test index aa873dfdcaf..99f7105fc38 100644 --- a/mysql-test/suite/versioning/t/create.test +++ b/mysql-test/suite/versioning/t/create.test @@ -207,4 +207,9 @@ create or replace table t1 ( create or replace table t1 (a int) with system versioning; create temporary table tmp with system versioning select * from t1; +create or replace table t1 (a int) with system versioning; +create table tt1 like t1; +show create table tt1; +drop table tt1; + drop table t1; diff --git a/sql/handler.cc b/sql/handler.cc index f7620a0543b..2bbc52fb19f 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6850,6 +6850,33 @@ bool Vers_parse_info::check_and_fix_alter(THD *thd, Alter_info *alter_info, check_generated_type(table_name, alter_info, integer_fields))); } +bool Vers_parse_info::fix_create_like(THD *thd, Alter_info *alter_info, + HA_CREATE_INFO *create_info) +{ + List_iterator it(alter_info->create_list); + Create_field *f= NULL; + + DBUG_ASSERT(alter_info->create_list.elements > 2); + for (uint i= 0; i < alter_info->create_list.elements - 1; ++i) + f= it++; + DBUG_ASSERT(f->flags & VERS_SYS_START_FLAG); + if (create_string(thd->mem_root, &generated_as_row.start, f->field_name) || + create_string(thd->mem_root, &period_for_system_time.start, + f->field_name)) + return true; + + f= it++; + DBUG_ASSERT(f->flags & VERS_SYS_END_FLAG); + if (create_string(thd->mem_root, &generated_as_row.end, f->field_name) || + create_string(thd->mem_root, &period_for_system_time.end, f->field_name)) + return true; + + create_info->options|= HA_VERSIONED_TABLE; + + return false; +} + + bool Vers_parse_info::check_with_conditions(const char *table_name) const { if (!generated_as_row.start) diff --git a/sql/handler.h b/sql/handler.h index f5e3d83d8d9..19a0b2963e4 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1723,6 +1723,8 @@ public: bool integer_fields, const char *table_name); bool check_and_fix_alter(THD *thd, Alter_info *alter_info, HA_CREATE_INFO *create_info, TABLE_SHARE *share); + bool fix_create_like(THD *thd, Alter_info *alter_info, + HA_CREATE_INFO *create_info); /** User has added 'WITH SYSTEM VERSIONING' to table definition */ bool declared_with_system_versioning : 1; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 75e608a0377..d16211101fd 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3877,10 +3877,11 @@ mysql_execute_command(THD *thd) create_info.use_default_db_type(thd); DBUG_ASSERT(create_info.db_type); - if (create_info.vers_info.check_and_fix_implicit(thd, - &alter_info, - create_info.db_type->flags & HTON_SUPPORTS_SYS_VERSIONING, - create_table->table_name)) + if (!create_info.like() && + create_info.vers_info.check_and_fix_implicit( + thd, &alter_info, + create_info.db_type->flags & HTON_SUPPORTS_SYS_VERSIONING, + create_table->table_name)) { goto end_with_restore_list; } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 3a921e0dc79..cb6b18eee4c 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5378,6 +5378,13 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, thd->work_part_info= src_table->table->part_info->get_clone(thd); #endif + if (src_table->table->versioned() && + local_create_info.vers_info.fix_create_like(thd, &local_alter_info, + &local_create_info)) + { + goto err; + } + /* Adjust description of source table before using it for creation of target table. -- cgit v1.2.1 From 7a22dd37164c1277410319984411994fb098e85b Mon Sep 17 00:00:00 2001 From: kevg Date: Mon, 6 Mar 2017 20:07:10 +0300 Subject: SQL: INNER JOIN USING with versioned tables [fixes #147] --- mysql-test/suite/versioning/r/select.result | 11 ++++++++++- mysql-test/suite/versioning/t/select.test | 10 +++++++++- sql/sql_base.cc | 2 +- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index 4258f84b16e..89e6c614c1e 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -409,7 +409,16 @@ ERROR HY000: Wrong parameters for `FOR SYSTEM_TIME query`: write-locking of hist create or replace table t1 (a int not null auto_increment primary key) with system versioning; select * from (t1 as t2 left join t1 as t3 using (a)) natural left join t1; a -drop table t1; +create or replace table t1 (a int) with system versioning; +create or replace table t2 (a int) with system versioning; +insert into t1 values(1); +insert into t2 values(1); +create view v1 as select * from t2 inner join t1 using (a); +select * from v1; +a +1 +drop view v1; +drop table t1, t2; call verify_vtq; No A B C D 1 1 1 1 1 diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index 9af249c1056..13c6c82aa99 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -134,7 +134,15 @@ select * from t1 for system_time all for update; create or replace table t1 (a int not null auto_increment primary key) with system versioning; select * from (t1 as t2 left join t1 as t3 using (a)) natural left join t1; -drop table t1; +create or replace table t1 (a int) with system versioning; +create or replace table t2 (a int) with system versioning; +insert into t1 values(1); +insert into t2 values(1); +create view v1 as select * from t2 inner join t1 using (a); +select * from v1; +drop view v1; + +drop table t1, t2; call verify_vtq; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index e8ec8104f8b..b0fe02aba69 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -5350,7 +5350,7 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, { if (!my_strcasecmp(system_charset_info, curr_nj_col->name(), name)) { - if (nj_col) + if (nj_col && !curr_nj_col->table_field->field->vers_sys_field()) { my_error(ER_NON_UNIQ_ERROR, MYF(0), name, thd->where); DBUG_RETURN(NULL); -- cgit v1.2.1 From afe64a450e2b50e85181df040d19ef7a0b87aeab Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 8 Mar 2017 00:45:23 +0700 Subject: IB: moved VTQ funcs to separate file --- storage/innobase/CMakeLists.txt | 3 +- storage/innobase/dict/dict0load.cc | 1 - storage/innobase/handler/ha_innodb.cc | 371 +----------------------------- storage/innobase/include/vers0vtq.h | 52 +++++ storage/innobase/vers/vers0vtq.cc | 412 ++++++++++++++++++++++++++++++++++ 5 files changed, 467 insertions(+), 372 deletions(-) create mode 100644 storage/innobase/include/vers0vtq.h create mode 100644 storage/innobase/vers/vers0vtq.cc diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt index dfcd348690b..f694f4fa512 100644 --- a/storage/innobase/CMakeLists.txt +++ b/storage/innobase/CMakeLists.txt @@ -149,7 +149,8 @@ SET(INNOBASE_SOURCES ut/ut0ut.cc ut/ut0vec.cc ut/ut0wqueue.cc - ut/ut0timer.cc) + ut/ut0timer.cc + vers/vers0vtq.cc) IF(WITH_INNODB) # Legacy option diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc index fa73380fcad..85f1296234a 100644 --- a/storage/innobase/dict/dict0load.cc +++ b/storage/innobase/dict/dict0load.cc @@ -3797,4 +3797,3 @@ dict_table_open_on_index_id( } return table; } - diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index e96d9c52909..aea14e9ca59 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -53,7 +53,6 @@ this program; if not, write to the Free Software Foundation, Inc., // MySQL 5.7 Header */ // #include #include -#include #include #include #include @@ -121,6 +120,7 @@ this program; if not, write to the Free Software Foundation, Inc., #include "trx0xa.h" #include "ut0mem.h" #include "row0ext.h" +#include "vers0vtq.h" #define thd_get_trx_isolation(X) ((enum_tx_isolation)thd_tx_isolation(X)) @@ -1537,23 +1537,6 @@ innobase_fts_store_docid( } #endif -bool -vtq_query_trx_id(THD* thd, void *out, ulonglong in_trx_id, vtq_field_t field); - -bool -vtq_query_commit_ts(THD* thd, void *out, const MYSQL_TIME &commit_ts, vtq_field_t field, bool backwards); - -bool -vtq_trx_sees( - THD *thd, - bool &result, - ulonglong trx_id1, - ulonglong trx_id0, - ulonglong commit_id1, - uchar iso_level1, - ulonglong commit_id0); - - /*************************************************************//** Check for a valid value of innobase_commit_concurrency. @return 0 for valid innodb_commit_concurrency */ @@ -23182,355 +23165,3 @@ ib_push_frm_error( break; } } - - -inline -void -innobase_vtq_result(THD* thd, vtq_record_t& q, void *out, vtq_field_t field) -{ - ut_ad(field == VTQ_ALL || out); - - switch (field) { - case VTQ_ALL: - if (out) { - *reinterpret_cast(out) = q; - } - break; - case VTQ_TRX_ID: - *reinterpret_cast(out) = q.trx_id; - break; - case VTQ_COMMIT_ID: - *reinterpret_cast(out) = q.commit_id; - break; - case VTQ_BEGIN_TS: { - MYSQL_TIME* out_ts = reinterpret_cast(out); - thd_get_timezone(thd)->gmt_sec_to_TIME(out_ts, q.begin_ts.tv_sec); - out_ts->second_part = q.begin_ts.tv_usec; - break; - } - case VTQ_COMMIT_TS: { - MYSQL_TIME* out_ts = reinterpret_cast(out); - thd_get_timezone(thd)->gmt_sec_to_TIME(out_ts, q.commit_ts.tv_sec); - out_ts->second_part = q.commit_ts.tv_usec; - break; - } - case VTQ_ISO_LEVEL: - *reinterpret_cast(out) = q.iso_level; - break; - default: - ut_error; - } -} - - -inline -const char * -vtq_query_t::cache_result(mem_heap_t* heap, const rec_t* rec) -{ - prev_query.tv_sec = 0; - return dict_process_sys_vtq(heap, rec, result); -} - -UNIV_INTERN -bool -vtq_query_trx_id(THD* thd, void *out, ulonglong _in_trx_id, vtq_field_t field) -{ - trx_t* trx; - dict_index_t* index; - btr_pcur_t pcur; - dtuple_t* tuple; - dfield_t* dfield; - trx_id_t trx_id_net; - mtr_t mtr; - mem_heap_t* heap; - rec_t* rec; - bool found = false; - - DBUG_ENTER("vtq_query_trx_id"); - - if (_in_trx_id == 0) { - DBUG_RETURN(false); - } - - ut_ad(sizeof(_in_trx_id) == sizeof(trx_id_t)); - trx_id_t in_trx_id = static_cast(_in_trx_id); - - trx = thd_to_trx(thd); - ut_a(trx); - - vtq_record_t &cached = trx->vtq_query.result; - - if (cached.trx_id == in_trx_id) { - innobase_vtq_result(thd, cached, out, field); - DBUG_RETURN(true); - } - - index = dict_table_get_first_index(dict_sys->sys_vtq); - heap = mem_heap_create(0); - - ut_ad(index); - ut_ad(dict_index_is_clust(index)); - - mach_write_to_8( - reinterpret_cast(&trx_id_net), - in_trx_id); - - tuple = dtuple_create(heap, 1); - dfield = dtuple_get_nth_field(tuple, DICT_FLD__SYS_VTQ__TRX_ID); - dfield_set_data(dfield, &trx_id_net, 8); - dict_index_copy_types(tuple, index, 1); - - mtr_start_trx(&mtr, trx); - btr_pcur_open_on_user_rec(index, tuple, PAGE_CUR_GE, - BTR_SEARCH_LEAF, &pcur, &mtr); - - if (!btr_pcur_is_on_user_rec(&pcur)) - goto not_found; - - rec = btr_pcur_get_rec(&pcur); - { - const char *err = trx->vtq_query.cache_result(heap, rec); - if (err) { - fprintf(stderr, "InnoDB: vtq_query_trx_id: get VTQ field failed: %s\n", err); - ut_ad(false && "get VTQ field failed"); - goto not_found; - } - } - - if (cached.trx_id != in_trx_id) - goto not_found; - - innobase_vtq_result(thd, cached, out, field); - found = true; - -not_found: - btr_pcur_close(&pcur); - mtr_commit(&mtr); - mem_heap_free(heap); - - DBUG_RETURN(found); -} - -static -inline -void rec_get_timeval(const rec_t* rec, ulint nfield, timeval& out) -{ - ulint len; - const byte* field; - field = rec_get_nth_field_old( - rec, nfield, &len); - - ut_ad(len == sizeof(ullong)); - - out.tv_sec = mach_read_from_4(field); - out.tv_usec = mach_read_from_4(field + 4); -} - -inline -const char * -vtq_query_t::cache_result( - mem_heap_t* heap, - const rec_t* rec, - const timeval& _ts_query, - bool _backwards) -{ - prev_query = _ts_query; - backwards = _backwards; - return dict_process_sys_vtq(heap, rec, result); -} - -static -inline -bool -operator== (const timeval &a, const timeval &b) -{ - return a.tv_sec == b.tv_sec && a.tv_usec == b.tv_usec; -} - -static -inline -bool -operator> (const timeval &a, const timeval &b) -{ - return a.tv_sec > b.tv_sec || (a.tv_sec == b.tv_sec && a.tv_usec > b.tv_usec); -} - -static -inline -bool -operator< (const timeval &a, const timeval &b) -{ - return b > a; -} - -UNIV_INTERN -bool -vtq_query_commit_ts(THD* thd, void *out, const MYSQL_TIME &_commit_ts, vtq_field_t field, bool backwards) -{ - trx_t* trx; - btr_pcur_t pcur; - dtuple_t* tuple; - page_cur_mode_t mode; - mtr_t mtr; - mem_heap_t* heap; - uint err; - timeval commit_ts; - timeval rec_ts = { 0, 0 }; - const rec_t *rec, *clust_rec; - dict_index_t* index = dict_sys->vtq_commit_ts_ind; - dict_index_t* clust_index; - bool found = false; - - DBUG_ENTER("vtq_query_commit_ts"); - - mode = backwards ? PAGE_CUR_LE : PAGE_CUR_GE; - - trx = thd_to_trx(thd); - ut_a(trx); - - vtq_record_t &cached = trx->vtq_query.result; - timeval &prev_query = trx->vtq_query.prev_query; - bool prev_bwds = trx->vtq_query.backwards; - - commit_ts.tv_usec = _commit_ts.second_part; - commit_ts.tv_sec = thd_get_timezone(thd)->TIME_to_gmt_sec(&_commit_ts, &err); - if (err) { - if (err == ER_WARN_DATA_OUT_OF_RANGE) { - if (_commit_ts.year <= TIMESTAMP_MIN_YEAR) { - commit_ts.tv_usec = 0; - commit_ts.tv_sec = 1; - } else { - ut_ad(_commit_ts.year >= TIMESTAMP_MAX_YEAR); - commit_ts.tv_usec = TIME_MAX_SECOND_PART; - commit_ts.tv_sec = MY_TIME_T_MAX; - } - } else { - DBUG_RETURN(false); - } - } else if (cached.commit_ts == commit_ts || - (prev_query.tv_sec && prev_bwds == backwards && ( - (!backwards && (commit_ts < prev_query) && commit_ts > cached.commit_ts) || - (backwards && (commit_ts > prev_query) && commit_ts < cached.commit_ts)))) - { - innobase_vtq_result(thd, cached, out, field); - DBUG_RETURN(true); - } - - heap = mem_heap_create(0); - - tuple = dtuple_create(heap, 1); - dict_index_copy_types(tuple, index, 1); - dtuple_get_nth_field(tuple, 0)->len = UNIV_SQL_NULL; - set_tuple_col_8(tuple, 0, commit_ts, heap); - - mtr_start_trx(&mtr, trx); - btr_pcur_open_on_user_rec(index, tuple, mode, - BTR_SEARCH_LEAF, &pcur, &mtr); - - if (btr_pcur_is_on_user_rec(&pcur)) { - rec = btr_pcur_get_rec(&pcur); - rec_get_timeval(rec, 0, rec_ts); - - if (rec_ts.tv_sec == commit_ts.tv_sec - && rec_ts.tv_usec == commit_ts.tv_usec) - goto found; - } else { - rec_ts = commit_ts; - } - - if (mode == PAGE_CUR_GE) { - btr_pcur_move_to_prev_user_rec(&pcur, &mtr); - } else { - btr_pcur_move_to_next_user_rec(&pcur, &mtr); - } - - if (!btr_pcur_is_on_user_rec(&pcur)) - goto not_found; - - rec = btr_pcur_get_rec(&pcur); -found: - clust_rec = row_get_clust_rec(BTR_SEARCH_LEAF, rec, index, &clust_index, &mtr); - if (!clust_rec) { - fprintf(stderr, "InnoDB: vtq_query_commit_ts: secondary index is out of sync\n"); - ut_ad(false && "secondary index is out of sync"); - goto not_found; - } - - { - const char *err = - trx->vtq_query.cache_result( - heap, - clust_rec, - rec_ts, - backwards); - if (err) { - fprintf(stderr, "InnoDB: vtq_query_commit_ts: get VTQ field failed: %s\n", err); - ut_ad(false && "get VTQ field failed"); - goto not_found; - } - } - innobase_vtq_result(thd, cached, out, field); - found = true; - -not_found: - btr_pcur_close(&pcur); - mtr_commit(&mtr); - mem_heap_free(heap); - - DBUG_RETURN(found); -} - -bool -vtq_trx_sees( - THD *thd, - bool &result, - ulonglong trx_id1, - ulonglong trx_id0, - ulonglong commit_id1, - uchar iso_level1, - ulonglong commit_id0) -{ - DBUG_ENTER("vtq_trx_sees"); - - if (trx_id1 == trx_id0) { - result = false; - DBUG_RETURN(true); - } - - if (trx_id1 == ULONGLONG_MAX || trx_id0 == 0) { - result = true; - DBUG_RETURN(true); - } - - static const char* msg_cant_find = "InnoDB: vtq_trx_sees: can't find COMMIT_ID%c by TRX_ID: %llu\n"; - if (!commit_id1) { - if (!vtq_query_trx_id(thd, NULL, trx_id1, VTQ_ALL)) { - fprintf(stderr, msg_cant_find, '1', trx_id1); - DBUG_RETURN(false); - } - trx_t* trx = thd_to_trx(thd); - ut_ad(trx); - commit_id1 = trx->vtq_query.result.commit_id; - iso_level1 = trx->vtq_query.result.iso_level; - } - - if (!commit_id0) { - if (!vtq_query_trx_id(thd, &commit_id0, trx_id0, VTQ_COMMIT_ID)) { - fprintf(stderr, msg_cant_find, '0', trx_id0); - DBUG_RETURN(false); - } - } - - // Trivial case: TX1 started after TX0 committed - if (trx_id1 > commit_id0 - // Concurrent transactions: TX1 committed after TX0 and TX1 is read (un)committed - || (commit_id1 > commit_id0 && iso_level1 < TRX_ISO_REPEATABLE_READ)) - { - result = true; - } else { - // All other cases: TX1 does not see TX0 - result = false; - } - - DBUG_RETURN(true); -} diff --git a/storage/innobase/include/vers0vtq.h b/storage/innobase/include/vers0vtq.h new file mode 100644 index 00000000000..2b486c25271 --- /dev/null +++ b/storage/innobase/include/vers0vtq.h @@ -0,0 +1,52 @@ +/* Copyright (c) 2017, MariaDB Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ + +/** Query VTQ by TRX_ID. +@param[in] thd MySQL thread +@param[out] out field value or whole record returned by query (selected by `field`) +@param[in] in_trx_id query parameter TRX_ID +@param[in] field field to get in `out` or VTQ_ALL for whole record (vtq_record_t) +@return TRUE if record is found, FALSE otherwise */ +bool +vtq_query_trx_id(THD* thd, void *out, ulonglong in_trx_id, vtq_field_t field); + +/** Query VTQ by COMMIT_TS. +@param[in] thd MySQL thread +@param[out] out field value or whole record returned by query (selected by `field`) +@param[in] commit_ts query parameter COMMIT_TS +@param[in] field field to get in `out` or VTQ_ALL for whole record (vtq_record_t) +@param[in] backwards direction of VTQ search +@return TRUE if record is found, FALSE otherwise */ +bool +vtq_query_commit_ts(THD* thd, void *out, const MYSQL_TIME &commit_ts, vtq_field_t field, bool backwards); + +/** Check if transaction TX1 sees transaction TX0. +@param[in] thd MySQL thread +@param[out] result true if TX1 sees TX0 +@param[in] trx_id1 TX1 TRX_ID +@param[in] trx_id0 TX0 TRX_ID +@param[in] commit_id1 TX1 COMMIT_ID +@param[in] iso_level1 TX1 isolation level +@param[in] commit_id0 TX0 COMMIT_ID +@return FALSE if there is no trx_id1 in VTQ, otherwise TRUE */ +bool +vtq_trx_sees( + THD *thd, + bool &result, + ulonglong trx_id1, + ulonglong trx_id0, + ulonglong commit_id1, + uchar iso_level1, + ulonglong commit_id0); diff --git a/storage/innobase/vers/vers0vtq.cc b/storage/innobase/vers/vers0vtq.cc new file mode 100644 index 00000000000..66ffc69829a --- /dev/null +++ b/storage/innobase/vers/vers0vtq.cc @@ -0,0 +1,412 @@ +/* Copyright (c) 2017, MariaDB Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ + +#include +#include + +#include "btr0pcur.h" +#include "dict0load.h" +#include "ha_innodb.h" +#include "row0ins.ic" +#include "row0row.h" +#include "trx0trx.h" +#include "trx0types.h" +#include "trx0vtq.h" + + +/** Field or record selector. +@param[in] thd MySQL thread +@param[in] q VTQ record to get values from +@param[out] out field value or whole record returned +@param[in] field field to get in `out` or VTQ_ALL for whole record (vtq_record_t copied) */ +static +inline +void +vtq_result(THD* thd, vtq_record_t& q, void *out, vtq_field_t field) +{ + ut_ad(field == VTQ_ALL || out); + + switch (field) { + case VTQ_ALL: + if (out) { + *reinterpret_cast(out) = q; + } + break; + case VTQ_TRX_ID: + *reinterpret_cast(out) = q.trx_id; + break; + case VTQ_COMMIT_ID: + *reinterpret_cast(out) = q.commit_id; + break; + case VTQ_BEGIN_TS: { + MYSQL_TIME* out_ts = reinterpret_cast(out); + thd_get_timezone(thd)->gmt_sec_to_TIME(out_ts, q.begin_ts.tv_sec); + out_ts->second_part = q.begin_ts.tv_usec; + break; + } + case VTQ_COMMIT_TS: { + MYSQL_TIME* out_ts = reinterpret_cast(out); + thd_get_timezone(thd)->gmt_sec_to_TIME(out_ts, q.commit_ts.tv_sec); + out_ts->second_part = q.commit_ts.tv_usec; + break; + } + case VTQ_ISO_LEVEL: + *reinterpret_cast(out) = q.iso_level; + break; + default: + ut_error; + } +} + +inline +const char * +vtq_query_t::cache_result(mem_heap_t* heap, const rec_t* rec) +{ + prev_query.tv_sec = 0; + return dict_process_sys_vtq(heap, rec, result); +} + + +/** Query VTQ by TRX_ID. +@param[in] thd MySQL thread +@param[out] out field value or whole record returned by query (selected by `field`) +@param[in] in_trx_id query parameter TRX_ID +@param[in] field field to get in `out` or VTQ_ALL for whole record (vtq_record_t) +@return TRUE if record is found, FALSE otherwise */ +UNIV_INTERN +bool +vtq_query_trx_id(THD* thd, void *out, ulonglong _in_trx_id, vtq_field_t field) +{ + trx_t* trx; + dict_index_t* index; + btr_pcur_t pcur; + dtuple_t* tuple; + dfield_t* dfield; + trx_id_t trx_id_net; + mtr_t mtr; + mem_heap_t* heap; + rec_t* rec; + bool found = false; + + DBUG_ENTER("vtq_query_trx_id"); + + if (_in_trx_id == 0) { + DBUG_RETURN(false); + } + + ut_ad(sizeof(_in_trx_id) == sizeof(trx_id_t)); + trx_id_t in_trx_id = static_cast(_in_trx_id); + + trx = thd_to_trx(thd); + ut_a(trx); + + vtq_record_t &cached = trx->vtq_query.result; + + if (cached.trx_id == in_trx_id) { + vtq_result(thd, cached, out, field); + DBUG_RETURN(true); + } + + index = dict_table_get_first_index(dict_sys->sys_vtq); + heap = mem_heap_create(0); + + ut_ad(index); + ut_ad(dict_index_is_clust(index)); + + mach_write_to_8( + reinterpret_cast(&trx_id_net), + in_trx_id); + + tuple = dtuple_create(heap, 1); + dfield = dtuple_get_nth_field(tuple, DICT_FLD__SYS_VTQ__TRX_ID); + dfield_set_data(dfield, &trx_id_net, 8); + dict_index_copy_types(tuple, index, 1); + + mtr_start_trx(&mtr, trx); + btr_pcur_open_on_user_rec(index, tuple, PAGE_CUR_GE, + BTR_SEARCH_LEAF, &pcur, &mtr); + + if (!btr_pcur_is_on_user_rec(&pcur)) + goto not_found; + + rec = btr_pcur_get_rec(&pcur); + { + const char *err = trx->vtq_query.cache_result(heap, rec); + if (err) { + fprintf(stderr, "InnoDB: vtq_query_trx_id: get VTQ field failed: %s\n", err); + ut_ad(false && "get VTQ field failed"); + goto not_found; + } + } + + if (cached.trx_id != in_trx_id) + goto not_found; + + vtq_result(thd, cached, out, field); + found = true; + +not_found: + btr_pcur_close(&pcur); + mtr_commit(&mtr); + mem_heap_free(heap); + + DBUG_RETURN(found); +} + +static +inline +void rec_get_timeval(const rec_t* rec, ulint nfield, timeval& out) +{ + ulint len; + const byte* field; + field = rec_get_nth_field_old( + rec, nfield, &len); + + ut_ad(len == sizeof(ullong)); + + out.tv_sec = mach_read_from_4(field); + out.tv_usec = mach_read_from_4(field + 4); +} + +inline +const char * +vtq_query_t::cache_result( + mem_heap_t* heap, + const rec_t* rec, + const timeval& _ts_query, + bool _backwards) +{ + prev_query = _ts_query; + backwards = _backwards; + return dict_process_sys_vtq(heap, rec, result); +} + +static +inline +bool +operator== (const timeval &a, const timeval &b) +{ + return a.tv_sec == b.tv_sec && a.tv_usec == b.tv_usec; +} + +static +inline +bool +operator> (const timeval &a, const timeval &b) +{ + return a.tv_sec > b.tv_sec || (a.tv_sec == b.tv_sec && a.tv_usec > b.tv_usec); +} + +static +inline +bool +operator< (const timeval &a, const timeval &b) +{ + return b > a; +} + + +/** Query VTQ by COMMIT_TS. +@param[in] thd MySQL thread +@param[out] out field value or whole record returned by query (selected by `field`) +@param[in] commit_ts query parameter COMMIT_TS +@param[in] field field to get in `out` or VTQ_ALL for whole record (vtq_record_t) +@param[in] backwards direction of VTQ search +@return TRUE if record is found, FALSE otherwise */ +UNIV_INTERN +bool +vtq_query_commit_ts( + THD* thd, + void *out, + const MYSQL_TIME &_commit_ts, + vtq_field_t field, + bool backwards) +{ + trx_t* trx; + btr_pcur_t pcur; + dtuple_t* tuple; + page_cur_mode_t mode; + mtr_t mtr; + mem_heap_t* heap; + uint err; + timeval commit_ts; + timeval rec_ts = { 0, 0 }; + const rec_t *rec, *clust_rec; + dict_index_t* index = dict_sys->vtq_commit_ts_ind; + dict_index_t* clust_index; + bool found = false; + + DBUG_ENTER("vtq_query_commit_ts"); + + mode = backwards ? PAGE_CUR_LE : PAGE_CUR_GE; + + trx = thd_to_trx(thd); + ut_a(trx); + + vtq_record_t &cached = trx->vtq_query.result; + timeval &prev_query = trx->vtq_query.prev_query; + bool prev_bwds = trx->vtq_query.backwards; + + commit_ts.tv_usec = _commit_ts.second_part; + commit_ts.tv_sec = thd_get_timezone(thd)->TIME_to_gmt_sec(&_commit_ts, &err); + if (err) { + if (err == ER_WARN_DATA_OUT_OF_RANGE) { + if (_commit_ts.year <= TIMESTAMP_MIN_YEAR) { + commit_ts.tv_usec = 0; + commit_ts.tv_sec = 1; + } else { + ut_ad(_commit_ts.year >= TIMESTAMP_MAX_YEAR); + commit_ts.tv_usec = TIME_MAX_SECOND_PART; + commit_ts.tv_sec = MY_TIME_T_MAX; + } + } else { + DBUG_RETURN(false); + } + } else if (cached.commit_ts == commit_ts || + (prev_query.tv_sec && prev_bwds == backwards && ( + (!backwards && (commit_ts < prev_query) && commit_ts > cached.commit_ts) || + (backwards && (commit_ts > prev_query) && commit_ts < cached.commit_ts)))) + { + vtq_result(thd, cached, out, field); + DBUG_RETURN(true); + } + + heap = mem_heap_create(0); + + tuple = dtuple_create(heap, 1); + dict_index_copy_types(tuple, index, 1); + dtuple_get_nth_field(tuple, 0)->len = UNIV_SQL_NULL; + set_tuple_col_8(tuple, 0, commit_ts, heap); + + mtr_start_trx(&mtr, trx); + btr_pcur_open_on_user_rec(index, tuple, mode, + BTR_SEARCH_LEAF, &pcur, &mtr); + + if (btr_pcur_is_on_user_rec(&pcur)) { + rec = btr_pcur_get_rec(&pcur); + rec_get_timeval(rec, 0, rec_ts); + + if (rec_ts.tv_sec == commit_ts.tv_sec + && rec_ts.tv_usec == commit_ts.tv_usec) + goto found; + } else { + rec_ts = commit_ts; + } + + if (mode == PAGE_CUR_GE) { + btr_pcur_move_to_prev_user_rec(&pcur, &mtr); + } else { + btr_pcur_move_to_next_user_rec(&pcur, &mtr); + } + + if (!btr_pcur_is_on_user_rec(&pcur)) + goto not_found; + + rec = btr_pcur_get_rec(&pcur); +found: + clust_rec = row_get_clust_rec(BTR_SEARCH_LEAF, rec, index, &clust_index, &mtr); + if (!clust_rec) { + fprintf(stderr, "InnoDB: vtq_query_commit_ts: secondary index is out of sync\n"); + ut_ad(false && "secondary index is out of sync"); + goto not_found; + } + + { + const char *err = + trx->vtq_query.cache_result( + heap, + clust_rec, + rec_ts, + backwards); + if (err) { + fprintf(stderr, "InnoDB: vtq_query_commit_ts: get VTQ field failed: %s\n", err); + ut_ad(false && "get VTQ field failed"); + goto not_found; + } + } + vtq_result(thd, cached, out, field); + found = true; + +not_found: + btr_pcur_close(&pcur); + mtr_commit(&mtr); + mem_heap_free(heap); + + DBUG_RETURN(found); +} + +/** Check if transaction TX1 sees transaction TX0. +@param[in] thd MySQL thread +@param[out] result true if TX1 sees TX0 +@param[in] trx_id1 TX1 TRX_ID +@param[in] trx_id0 TX0 TRX_ID +@param[in] commit_id1 TX1 COMMIT_ID +@param[in] iso_level1 TX1 isolation level +@param[in] commit_id0 TX0 COMMIT_ID +@return FALSE if there is no trx_id1 in VTQ, otherwise TRUE */ +bool +vtq_trx_sees( + THD *thd, + bool &result, + ulonglong trx_id1, + ulonglong trx_id0, + ulonglong commit_id1, + uchar iso_level1, + ulonglong commit_id0) +{ + DBUG_ENTER("vtq_trx_sees"); + + if (trx_id1 == trx_id0) { + result = false; + DBUG_RETURN(true); + } + + if (trx_id1 == ULONGLONG_MAX || trx_id0 == 0) { + result = true; + DBUG_RETURN(true); + } + + static const char* msg_cant_find = "InnoDB: vtq_trx_sees: can't find COMMIT_ID%c by TRX_ID: %llu\n"; + if (!commit_id1) { + if (!vtq_query_trx_id(thd, NULL, trx_id1, VTQ_ALL)) { + fprintf(stderr, msg_cant_find, '1', trx_id1); + DBUG_RETURN(false); + } + trx_t* trx = thd_to_trx(thd); + ut_ad(trx); + commit_id1 = trx->vtq_query.result.commit_id; + iso_level1 = trx->vtq_query.result.iso_level; + } + + if (!commit_id0) { + if (!vtq_query_trx_id(thd, &commit_id0, trx_id0, VTQ_COMMIT_ID)) { + fprintf(stderr, msg_cant_find, '0', trx_id0); + DBUG_RETURN(false); + } + } + + // Trivial case: TX1 started after TX0 committed + if (trx_id1 > commit_id0 + // Concurrent transactions: TX1 committed after TX0 and TX1 is read (un)committed + || (commit_id1 > commit_id0 && iso_level1 < TRX_ISO_REPEATABLE_READ)) + { + result = true; + } else { + // All other cases: TX1 does not see TX0 + result = false; + } + + DBUG_RETURN(true); +} -- cgit v1.2.1 From cbb674282aab725acb87c73dc2fb4699eb8b52c2 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Thu, 9 Mar 2017 12:16:53 +0700 Subject: SQL: moved VTQ items to separate file --- sql/CMakeLists.txt | 1 + sql/item.h | 1 + sql/item_timefunc.cc | 257 ---------------------------------------------- sql/item_timefunc.h | 115 --------------------- sql/item_vers.cc | 280 +++++++++++++++++++++++++++++++++++++++++++++++++++ sql/item_vers.h | 140 ++++++++++++++++++++++++++ 6 files changed, 422 insertions(+), 372 deletions(-) create mode 100644 sql/item_vers.cc create mode 100644 sql/item_vers.h diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 08a39b1975d..ee34891d0c9 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -143,6 +143,7 @@ SET (SQL_SOURCE rpl_gtid.cc rpl_parallel.cc sql_type.cc sql_type.h item_windowfunc.cc sql_window.cc + item_vers.cc sql_cte.cc sql_cte.h sql_sequence.cc sql_sequence.h ha_sequence.h ${WSREP_SOURCES} diff --git a/sql/item.h b/sql/item.h index f7bc1110898..eb695726472 100644 --- a/sql/item.h +++ b/sql/item.h @@ -4937,6 +4937,7 @@ public: #include "item_xmlfunc.h" #include "item_jsonfunc.h" #include "item_create.h" +#include "item_vers.h" #endif /** diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 2f9b467408f..a1a9ca5c8ae 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -3273,260 +3273,3 @@ bool Item_func_last_day::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) ltime->time_type= MYSQL_TIMESTAMP_DATE; return (null_value= 0); } - -Item_func_vtq_ts::Item_func_vtq_ts( - THD *thd, - Item* a, - vtq_field_t _vtq_field, - handlerton* hton) : - VTQ_common(thd, a, hton), - vtq_field(_vtq_field) -{ - decimals= 6; - null_value= true; - DBUG_ASSERT(arg_count == 1 && args[0]); -} - -Item_func_vtq_ts::Item_func_vtq_ts( - THD *thd, - Item* a, - vtq_field_t _vtq_field) : - VTQ_common(thd, a), - vtq_field(_vtq_field) -{ - decimals= 6; - null_value= true; - DBUG_ASSERT(arg_count == 1 && args[0]); -} - -template -void -VTQ_common::init_hton() -{ - if (!hton) - { - if (Item_func_X::args[0]->type() == Item::FIELD_ITEM) - { - Item_field *f= - static_cast(Item_func_X::args[0]); - DBUG_ASSERT( - f->field && - f->field->table && - f->field->table->s && - f->field->table->s->db_plugin); - hton= f->field->table->file->partition_ht(); - DBUG_ASSERT(hton); - } - else if (innodb_plugin) - { - hton= plugin_hton(plugin_int_to_ref(innodb_plugin)); - DBUG_ASSERT(hton); - } - if (hton && !(hton->flags & HTON_SUPPORTS_SYS_VERSIONING)) - { - my_error(ER_VERS_ENGINE_UNSUPPORTED, MYF(0), Item::name ? Item::name : this->func_name()); - hton= NULL; - } - } -} - -bool -Item_func_vtq_ts::get_date(MYSQL_TIME *res, ulonglong fuzzy_date) -{ - THD *thd= current_thd; // can it differ from constructor's? - DBUG_ASSERT(thd); - ulonglong trx_id= args[0]->val_uint(); - if (trx_id == ULONGLONG_MAX) - { - null_value= false; - thd->variables.time_zone->gmt_sec_to_TIME(res, TIMESTAMP_MAX_VALUE); - return false; - } - - init_hton(); - - if (!hton) - return true; - - DBUG_ASSERT(hton->vers_query_trx_id); - null_value= !hton->vers_query_trx_id(thd, res, trx_id, vtq_field); - - return false; -} - - -Item_func_vtq_id::Item_func_vtq_id( - THD *thd, - Item* a, - vtq_field_t _vtq_field, - bool _backwards) : - VTQ_common(thd, a), - vtq_field(_vtq_field), - backwards(_backwards) -{ - memset(&cached_result, 0, sizeof(cached_result)); - decimals= 0; - unsigned_flag= 1; - null_value= true; - DBUG_ASSERT(arg_count == 1 && args[0]); -} - -Item_func_vtq_id::Item_func_vtq_id( - THD *thd, - Item* a, - Item* b, - vtq_field_t _vtq_field) : - VTQ_common(thd, a, b), - vtq_field(_vtq_field), - backwards(false) -{ - memset(&cached_result, 0, sizeof(cached_result)); - decimals= 0; - unsigned_flag= 1; - null_value= true; - DBUG_ASSERT(arg_count == 2 && args[0] && args[1]); -} - -longlong -Item_func_vtq_id::get_by_trx_id(ulonglong trx_id) -{ - ulonglong res; - THD *thd= current_thd; // can it differ from constructor's? - DBUG_ASSERT(thd); - - if (trx_id == ULONGLONG_MAX) - { - null_value= true; - return 0; - } - - DBUG_ASSERT(hton->vers_query_trx_id); - null_value= !hton->vers_query_trx_id(thd, &res, trx_id, vtq_field); - return res; -} - -longlong -Item_func_vtq_id::get_by_commit_ts(MYSQL_TIME &commit_ts, bool backwards) -{ - THD *thd= current_thd; // can it differ from constructor's? - DBUG_ASSERT(thd); - - DBUG_ASSERT(hton->vers_query_commit_ts); - null_value= !hton->vers_query_commit_ts(thd, &cached_result, commit_ts, VTQ_ALL, backwards); - if (null_value) - { - return 0; - } - - switch (vtq_field) - { - case VTQ_COMMIT_ID: - return cached_result.commit_id; - case VTQ_ISO_LEVEL: - return cached_result.iso_level; - case VTQ_TRX_ID: - return cached_result.trx_id; - default: - DBUG_ASSERT(0); - null_value= true; - } - - return 0; -} - -longlong -Item_func_vtq_id::val_int() -{ - init_hton(); - - if (!hton) - { - null_value= true; - return 0; - } - - if (args[0]->is_null()) - { - if (arg_count < 2 || vtq_field == VTQ_TRX_ID) - { - null_value= true; - return 0; - } - return get_by_trx_id(args[1]->val_uint()); - } - else - { - MYSQL_TIME commit_ts; - if (args[0]->get_date(&commit_ts, 0)) - { - null_value= true; - return 0; - } - if (arg_count > 1) - { - backwards= args[1]->val_bool(); - DBUG_ASSERT(arg_count == 2); - } - return get_by_commit_ts(commit_ts, backwards); - } -} - -Item_func_vtq_trx_sees::Item_func_vtq_trx_sees( - THD *thd, - Item* a, - Item* b) : - VTQ_common(thd, a, b), - accept_eq(false) -{ - null_value= true; - DBUG_ASSERT(arg_count == 2 && args[0] && args[1]); -} - -longlong -Item_func_vtq_trx_sees::val_int() -{ - THD *thd= current_thd; - DBUG_ASSERT(thd); - - init_hton(); - - if (!hton) - { - null_value= true; - return 0; - } - - ulonglong trx_id1, trx_id0; - ulonglong commit_id1= 0; - ulonglong commit_id0= 0; - uchar iso_level1= 0; - - DBUG_ASSERT(arg_count > 1); - trx_id1= args[0]->val_uint(); - trx_id0= args[1]->val_uint(); - - vtq_record_t *cached= args[0]->vtq_cached_result(); - if (cached && cached->commit_id) - { - commit_id1= cached->commit_id; - iso_level1= cached->iso_level; - } - - cached= args[1]->vtq_cached_result(); - if (cached && cached->commit_id) - { - commit_id0= cached->commit_id; - } - - if (accept_eq && trx_id1 && trx_id1 == trx_id0) - { - null_value= false; - return true; - } - - DBUG_ASSERT(hton->vers_trx_sees); - bool result= false; - null_value= !hton->vers_trx_sees(thd, result, trx_id1, trx_id0, commit_id1, iso_level1, commit_id0); - return result; -} - diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 4d7935b8506..f1a719fb775 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -1286,119 +1286,4 @@ public: { return get_item_copy(thd, mem_root, this); } }; -#include "vtq.h" - -template -class VTQ_common : public Item_func_X -{ -protected: - handlerton *hton; - void init_hton(); -public: - VTQ_common(THD *thd, Item* a) : - Item_func_X(thd, a), - hton(NULL) {} - VTQ_common(THD *thd, Item* a, Item* b) : - Item_func_X(thd, a, b), - hton(NULL) {} - VTQ_common(THD *thd, Item* a, handlerton* _hton) : - Item_func_X(thd, a), - hton(_hton) {} -}; - -class Item_func_vtq_ts : - public VTQ_common -{ - vtq_field_t vtq_field; -public: - Item_func_vtq_ts(THD *thd, Item* a, vtq_field_t _vtq_field, handlerton *hton); - Item_func_vtq_ts(THD *thd, Item* a, vtq_field_t _vtq_field); - const char *func_name() const - { - if (vtq_field == VTQ_BEGIN_TS) - { - return "vtq_begin_ts"; - } - return "vtq_commit_ts"; - } - bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy(thd, mem_root, this); } -}; - -class Item_func_vtq_id : - public VTQ_common -{ - vtq_field_t vtq_field; - vtq_record_t cached_result; - bool backwards; - - longlong get_by_trx_id(ulonglong trx_id); - longlong get_by_commit_ts(MYSQL_TIME &commit_ts, bool backwards); - -public: - Item_func_vtq_id(THD *thd, Item* a, vtq_field_t _vtq_field, bool _backwards= false); - Item_func_vtq_id(THD *thd, Item* a, Item* b, vtq_field_t _vtq_field); - - vtq_record_t *vtq_cached_result() { return &cached_result; } - - const char *func_name() const - { - switch (vtq_field) - { - case VTQ_TRX_ID: - return "vtq_trx_id"; - case VTQ_COMMIT_ID: - return "vtq_commit_id"; - case VTQ_ISO_LEVEL: - return "vtq_iso_level"; - default: - DBUG_ASSERT(0); - } - return NULL; - } - - void fix_length_and_dec() - { - Item_int_func::fix_length_and_dec(); - max_length= 20; - } - - longlong val_int(); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy(thd, mem_root, this); } -}; - -class Item_func_vtq_trx_sees : - public VTQ_common -{ -protected: - bool accept_eq; - -public: - Item_func_vtq_trx_sees(THD *thd, Item* a, Item* b); - const char *func_name() const - { - return "vtq_trx_sees"; - } - longlong val_int(); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy(thd, mem_root, this); } -}; - -class Item_func_vtq_trx_sees_eq : - public Item_func_vtq_trx_sees -{ -public: - Item_func_vtq_trx_sees_eq(THD *thd, Item* a, Item* b) : - Item_func_vtq_trx_sees(thd, a, b) - { - accept_eq= true; - } - const char *func_name() const - { - return "vtq_trx_sees_eq"; - } -}; - #endif /* ITEM_TIMEFUNC_INCLUDED */ diff --git a/sql/item_vers.cc b/sql/item_vers.cc new file mode 100644 index 00000000000..0a15d67b535 --- /dev/null +++ b/sql/item_vers.cc @@ -0,0 +1,280 @@ +/* Copyright (c) 2017, MariaDB Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ + + +/** + @brief + System Versioning items +*/ + +#include "item.h" +#include "sql_class.h" +#include "tztime.h" + +Item_func_vtq_ts::Item_func_vtq_ts( + THD *thd, + Item* a, + vtq_field_t _vtq_field, + handlerton* hton) : + VTQ_common(thd, a, hton), + vtq_field(_vtq_field) +{ + decimals= 6; + null_value= true; + DBUG_ASSERT(arg_count == 1 && args[0]); +} + +Item_func_vtq_ts::Item_func_vtq_ts( + THD *thd, + Item* a, + vtq_field_t _vtq_field) : + VTQ_common(thd, a), + vtq_field(_vtq_field) +{ + decimals= 6; + null_value= true; + DBUG_ASSERT(arg_count == 1 && args[0]); +} + +template +void +VTQ_common::init_hton() +{ + if (!hton) + { + if (Item_func_X::args[0]->type() == Item::FIELD_ITEM) + { + Item_field *f= + static_cast(Item_func_X::args[0]); + DBUG_ASSERT( + f->field && + f->field->table && + f->field->table->s && + f->field->table->s->db_plugin); + hton= f->field->table->file->partition_ht(); + DBUG_ASSERT(hton); + } + else if (innodb_plugin) + { + hton= plugin_hton(plugin_int_to_ref(innodb_plugin)); + DBUG_ASSERT(hton); + } + if (hton && !(hton->flags & HTON_SUPPORTS_SYS_VERSIONING)) + { + my_error(ER_VERS_ENGINE_UNSUPPORTED, MYF(0), Item::name ? Item::name : this->func_name()); + hton= NULL; + } + } +} + +bool +Item_func_vtq_ts::get_date(MYSQL_TIME *res, ulonglong fuzzy_date) +{ + THD *thd= current_thd; // can it differ from constructor's? + DBUG_ASSERT(thd); + ulonglong trx_id= args[0]->val_uint(); + if (trx_id == ULONGLONG_MAX) + { + null_value= false; + thd->variables.time_zone->gmt_sec_to_TIME(res, TIMESTAMP_MAX_VALUE); + return false; + } + + init_hton(); + + if (!hton) + return true; + + DBUG_ASSERT(hton->vers_query_trx_id); + null_value= !hton->vers_query_trx_id(thd, res, trx_id, vtq_field); + + return false; +} + + +Item_func_vtq_id::Item_func_vtq_id( + THD *thd, + Item* a, + vtq_field_t _vtq_field, + bool _backwards) : + VTQ_common(thd, a), + vtq_field(_vtq_field), + backwards(_backwards) +{ + memset(&cached_result, 0, sizeof(cached_result)); + decimals= 0; + unsigned_flag= 1; + null_value= true; + DBUG_ASSERT(arg_count == 1 && args[0]); +} + +Item_func_vtq_id::Item_func_vtq_id( + THD *thd, + Item* a, + Item* b, + vtq_field_t _vtq_field) : + VTQ_common(thd, a, b), + vtq_field(_vtq_field), + backwards(false) +{ + memset(&cached_result, 0, sizeof(cached_result)); + decimals= 0; + unsigned_flag= 1; + null_value= true; + DBUG_ASSERT(arg_count == 2 && args[0] && args[1]); +} + +longlong +Item_func_vtq_id::get_by_trx_id(ulonglong trx_id) +{ + ulonglong res; + THD *thd= current_thd; // can it differ from constructor's? + DBUG_ASSERT(thd); + + if (trx_id == ULONGLONG_MAX) + { + null_value= true; + return 0; + } + + DBUG_ASSERT(hton->vers_query_trx_id); + null_value= !hton->vers_query_trx_id(thd, &res, trx_id, vtq_field); + return res; +} + +longlong +Item_func_vtq_id::get_by_commit_ts(MYSQL_TIME &commit_ts, bool backwards) +{ + THD *thd= current_thd; // can it differ from constructor's? + DBUG_ASSERT(thd); + + DBUG_ASSERT(hton->vers_query_commit_ts); + null_value= !hton->vers_query_commit_ts(thd, &cached_result, commit_ts, VTQ_ALL, backwards); + if (null_value) + { + return 0; + } + + switch (vtq_field) + { + case VTQ_COMMIT_ID: + return cached_result.commit_id; + case VTQ_ISO_LEVEL: + return cached_result.iso_level; + case VTQ_TRX_ID: + return cached_result.trx_id; + default: + DBUG_ASSERT(0); + null_value= true; + } + + return 0; +} + +longlong +Item_func_vtq_id::val_int() +{ + init_hton(); + + if (!hton) + { + null_value= true; + return 0; + } + + if (args[0]->is_null()) + { + if (arg_count < 2 || vtq_field == VTQ_TRX_ID) + { + null_value= true; + return 0; + } + return get_by_trx_id(args[1]->val_uint()); + } + else + { + MYSQL_TIME commit_ts; + if (args[0]->get_date(&commit_ts, 0)) + { + null_value= true; + return 0; + } + if (arg_count > 1) + { + backwards= args[1]->val_bool(); + DBUG_ASSERT(arg_count == 2); + } + return get_by_commit_ts(commit_ts, backwards); + } +} + +Item_func_vtq_trx_sees::Item_func_vtq_trx_sees( + THD *thd, + Item* a, + Item* b) : + VTQ_common(thd, a, b), + accept_eq(false) +{ + null_value= true; + DBUG_ASSERT(arg_count == 2 && args[0] && args[1]); +} + +longlong +Item_func_vtq_trx_sees::val_int() +{ + THD *thd= current_thd; + DBUG_ASSERT(thd); + + init_hton(); + + if (!hton) + { + null_value= true; + return 0; + } + + ulonglong trx_id1, trx_id0; + ulonglong commit_id1= 0; + ulonglong commit_id0= 0; + uchar iso_level1= 0; + + DBUG_ASSERT(arg_count > 1); + trx_id1= args[0]->val_uint(); + trx_id0= args[1]->val_uint(); + + vtq_record_t *cached= args[0]->vtq_cached_result(); + if (cached && cached->commit_id) + { + commit_id1= cached->commit_id; + iso_level1= cached->iso_level; + } + + cached= args[1]->vtq_cached_result(); + if (cached && cached->commit_id) + { + commit_id0= cached->commit_id; + } + + if (accept_eq && trx_id1 && trx_id1 == trx_id0) + { + null_value= false; + return true; + } + + DBUG_ASSERT(hton->vers_trx_sees); + bool result= false; + null_value= !hton->vers_trx_sees(thd, result, trx_id1, trx_id0, commit_id1, iso_level1, commit_id0); + return result; +} diff --git a/sql/item_vers.h b/sql/item_vers.h new file mode 100644 index 00000000000..aa5575ff9b1 --- /dev/null +++ b/sql/item_vers.h @@ -0,0 +1,140 @@ +#ifndef ITEM_VERS_INCLUDED +#define ITEM_VERS_INCLUDED +/* Copyright (c) 2017, MariaDB Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ + + +/* System Versioning items */ + +#include "vtq.h" + +#ifdef USE_PRAGMA_INTERFACE +#pragma interface /* gcc class implementation */ +#endif + +template +class VTQ_common : public Item_func_X +{ +protected: + handlerton *hton; + void init_hton(); +public: + VTQ_common(THD *thd, Item* a) : + Item_func_X(thd, a), + hton(NULL) {} + VTQ_common(THD *thd, Item* a, Item* b) : + Item_func_X(thd, a, b), + hton(NULL) {} + VTQ_common(THD *thd, Item* a, handlerton* _hton) : + Item_func_X(thd, a), + hton(_hton) {} +}; + +class Item_func_vtq_ts : + public VTQ_common +{ + vtq_field_t vtq_field; +public: + Item_func_vtq_ts(THD *thd, Item* a, vtq_field_t _vtq_field, handlerton *hton); + Item_func_vtq_ts(THD *thd, Item* a, vtq_field_t _vtq_field); + const char *func_name() const + { + if (vtq_field == VTQ_BEGIN_TS) + { + return "vtq_begin_ts"; + } + return "vtq_commit_ts"; + } + bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy(thd, mem_root, this); } +}; + +class Item_func_vtq_id : + public VTQ_common +{ + vtq_field_t vtq_field; + vtq_record_t cached_result; + bool backwards; + + longlong get_by_trx_id(ulonglong trx_id); + longlong get_by_commit_ts(MYSQL_TIME &commit_ts, bool backwards); + +public: + Item_func_vtq_id(THD *thd, Item* a, vtq_field_t _vtq_field, bool _backwards= false); + Item_func_vtq_id(THD *thd, Item* a, Item* b, vtq_field_t _vtq_field); + + vtq_record_t *vtq_cached_result() { return &cached_result; } + + const char *func_name() const + { + switch (vtq_field) + { + case VTQ_TRX_ID: + return "vtq_trx_id"; + case VTQ_COMMIT_ID: + return "vtq_commit_id"; + case VTQ_ISO_LEVEL: + return "vtq_iso_level"; + default: + DBUG_ASSERT(0); + } + return NULL; + } + + void fix_length_and_dec() + { + Item_int_func::fix_length_and_dec(); + max_length= 20; + } + + longlong val_int(); + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy(thd, mem_root, this); } +}; + +class Item_func_vtq_trx_sees : + public VTQ_common +{ +protected: + bool accept_eq; + +public: + Item_func_vtq_trx_sees(THD *thd, Item* a, Item* b); + const char *func_name() const + { + return "vtq_trx_sees"; + } + longlong val_int(); + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy(thd, mem_root, this); } +}; + +class Item_func_vtq_trx_sees_eq : + public Item_func_vtq_trx_sees +{ +public: + Item_func_vtq_trx_sees_eq(THD *thd, Item* a, Item* b) : + Item_func_vtq_trx_sees(thd, a, b) + { + accept_eq= true; + } + const char *func_name() const + { + return "vtq_trx_sees_eq"; + } +}; + +#endif /* ITEM_VERS_INCLUDED */ -- cgit v1.2.1 From 0e0103893691eae714e2f278498300b8d005cebf Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Fri, 10 Mar 2017 20:25:30 +0700 Subject: SQL: forced, hidden versioning [closes #32] --- include/mysql_com.h | 4 +-- plugin/versioning/CMakeLists.txt | 17 ++++++++++ plugin/versioning/versioning.cc | 69 ++++++++++++++++++++++++++++++++++++++++ sql/handler.cc | 10 +++++- sql/handler.h | 3 +- sql/mysqld.cc | 2 ++ sql/mysqld.h | 2 ++ sql/sql_parse.cc | 5 +-- sql/sql_show.cc | 8 +++-- sql/sys_vars.cc | 8 +++++ 10 files changed, 118 insertions(+), 10 deletions(-) create mode 100644 plugin/versioning/CMakeLists.txt create mode 100644 plugin/versioning/versioning.cc diff --git a/include/mysql_com.h b/include/mysql_com.h index 58c28f6d074..21b3d1e4803 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -185,10 +185,10 @@ enum enum_indicator_type #define FIELD_IS_DROPPED (1U << 26) /* Intern: Field is being dropped */ #define VERS_SYS_START_FLAG (1 << 27) /* autogenerated column declared with - `generated always at row start` + `generated always as row start` (see II.a SQL Standard) */ #define VERS_SYS_END_FLAG (1 << 28) /* autogenerated column declared with - `generated always at row end` + `generated always as row end` (see II.a SQL Standard).*/ #define VERS_OPTIMIZED_UPDATE_FLAG (1 << 29) /* column that doesn't support system versioning when table diff --git a/plugin/versioning/CMakeLists.txt b/plugin/versioning/CMakeLists.txt new file mode 100644 index 00000000000..9ae0b58af66 --- /dev/null +++ b/plugin/versioning/CMakeLists.txt @@ -0,0 +1,17 @@ +# Copyright (c) 2016, MariaDB corporation. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +MYSQL_ADD_PLUGIN(versioning versioning.cc + MODULE_ONLY MODULE_OUTPUT_NAME "versioning" COMPONENT Test) diff --git a/plugin/versioning/versioning.cc b/plugin/versioning/versioning.cc new file mode 100644 index 00000000000..44faf85aef7 --- /dev/null +++ b/plugin/versioning/versioning.cc @@ -0,0 +1,69 @@ +/* Copyright (c) 2016, MariaDB corporation. All rights + reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include +#include +#include "sql_plugin.h" // st_plugin_int + +/* + Disable __attribute__() on non-gcc compilers. +*/ +#if !defined(__attribute__) && !defined(__GNUC__) +#define __attribute__(A) +#endif + +static int forced_versioning_init(void *p __attribute__ ((unused))) +{ + + DBUG_ENTER("forced_versioning_init"); + vers_force= true; + vers_hide= true; + DBUG_RETURN(0); +} + +static int forced_versioning_deinit(void *p __attribute__ ((unused))) +{ + DBUG_ENTER("forced_versioning_deinit"); + vers_force= false; + vers_hide= false; + DBUG_RETURN(0); +} + + +struct st_mysql_daemon forced_versioning_plugin= +{ MYSQL_DAEMON_INTERFACE_VERSION }; + +/* + Plugin library descriptor +*/ + +maria_declare_plugin(forced_versioning) +{ + MYSQL_DAEMON_PLUGIN, + &forced_versioning_plugin, + "forced_versioning", + "Natsys Lab", + "Enable System Vesioning for all newly created tables", + PLUGIN_LICENSE_GPL, + forced_versioning_init, /* Plugin Init */ + forced_versioning_deinit, /* Plugin Deinit */ + 0x0100 /* 1.0 */, + NULL, /* status variables */ + NULL, /* system variables */ + "1.0", /* string version */ + MariaDB_PLUGIN_MATURITY_EXPERIMENTAL /* maturity */ +} +maria_declare_plugin_end; diff --git a/sql/handler.cc b/sql/handler.cc index 2bbc52fb19f..909e0aa6fee 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6669,9 +6669,17 @@ bool Vers_parse_info::fix_implicit(THD *thd, Alter_info *alter_info, bool Vers_parse_info::check_and_fix_implicit( THD *thd, Alter_info *alter_info, - bool integer_fields, + HA_CREATE_INFO *create_info, const char* table_name) { + bool integer_fields= + create_info->db_type->flags & HTON_SUPPORTS_SYS_VERSIONING; + + if (vers_force) { + declared_with_system_versioning= true; + create_info->options|= HA_VERSIONED_TABLE; + } + if (!need_to_check()) return false; diff --git a/sql/handler.h b/sql/handler.h index 19a0b2963e4..a0da6852da4 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1720,7 +1720,8 @@ private: public: bool check_and_fix_implicit(THD *thd, Alter_info *alter_info, - bool integer_fields, const char *table_name); + HA_CREATE_INFO *create_info, + const char *table_name); bool check_and_fix_alter(THD *thd, Alter_info *alter_info, HA_CREATE_INFO *create_info, TABLE_SHARE *share); bool fix_create_like(THD *thd, Alter_info *alter_info, diff --git a/sql/mysqld.cc b/sql/mysqld.cc index b7eccea80c6..bb96893e49d 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -783,6 +783,8 @@ char *opt_logname, *opt_slow_logname, *opt_bin_logname; /* System Versioning */ char *temporal_current_timestamp; +my_bool vers_force= false; +my_bool vers_hide= false; /* Static variables */ diff --git a/sql/mysqld.h b/sql/mysqld.h index ece0992dd82..20300895fe5 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -176,6 +176,8 @@ extern char *opt_backup_history_logname, *opt_backup_progress_logname, extern const char *log_output_str; extern const char *log_backup_output_str; extern char *temporal_current_timestamp; +extern my_bool vers_force; +extern my_bool vers_hide; extern char *mysql_home_ptr, *pidfile_name_ptr; extern MYSQL_PLUGIN_IMPORT char glob_hostname[FN_REFLEN]; extern char mysql_home[FN_REFLEN]; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index d16211101fd..677dd269722 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3876,12 +3876,9 @@ mysql_execute_command(THD *thd) if (!(create_info.used_fields & HA_CREATE_USED_ENGINE)) create_info.use_default_db_type(thd); - DBUG_ASSERT(create_info.db_type); if (!create_info.like() && create_info.vers_info.check_and_fix_implicit( - thd, &alter_info, - create_info.db_type->flags & HTON_SUPPORTS_SYS_VERSIONING, - create_table->table_name)) + thd, &alter_info, &create_info, create_table->table_name)) { goto end_with_restore_list; } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 93836c82085..0f1098dcede 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2064,6 +2064,10 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, { uint flags = field->flags; + if (vers_hide && + (flags & (VERS_SYS_START_FLAG | VERS_SYS_END_FLAG))) + continue; + if (ptr != table->field) packet->append(STRING_WITH_LEN(",\n")); @@ -2229,7 +2233,7 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, hton->index_options); } - if (table->versioned()) + if (table->versioned() && !vers_hide) { const Field *fs = table->vers_start_field(); const Field *fe = table->vers_end_field(); @@ -2278,7 +2282,7 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, add_table_options(thd, table, create_info_arg, table_list->schema_table != 0, 0, packet); - if (table->versioned()) + if (table->versioned() && !vers_hide) { packet->append(STRING_WITH_LEN(" WITH SYSTEM VERSIONING")); } diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index bc2b37d9d6d..b6f84e88d07 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -387,6 +387,14 @@ static Sys_var_charptr sys_temporal_current_timestamp( GLOBAL_VAR(temporal_current_timestamp), CMD_LINE(REQUIRED_ARG, 'b'), IN_FS_CHARSET, DEFAULT("now")); +static Sys_var_mybool Sys_vers_force( + "vers_force", "Force system versioning for all created tables", + GLOBAL_VAR(vers_force), CMD_LINE(OPT_ARG), DEFAULT(FALSE)); + +static Sys_var_mybool Sys_vers_hide( + "vers_hide", "Hide system versioning from being displayed in table info", + GLOBAL_VAR(vers_hide), CMD_LINE(OPT_ARG), DEFAULT(FALSE)); + static Sys_var_ulonglong Sys_binlog_cache_size( "binlog_cache_size", "The size of the transactional cache for " "updates to transactional engines for the binary log. " -- cgit v1.2.1 From d85e7a5e016819447578646cd0d7cab0d8f2260b Mon Sep 17 00:00:00 2001 From: kevg Date: Fri, 10 Mar 2017 16:55:14 +0300 Subject: SQL: NATUAL JOIN on view + table [fixes #148] --- mysql-test/suite/versioning/r/select.result | 7 +++++++ mysql-test/suite/versioning/t/select.test | 6 ++++++ sql/sql_select.cc | 3 ++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index 89e6c614c1e..3db2eafb1cd 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -418,6 +418,13 @@ select * from v1; a 1 drop view v1; +create or replace table t1 (a int) with system versioning; +insert into t1 values (1); +create view vt1 as select a from t1; +select * from t1 natural join vt1; +a +1 +drop view vt1; drop table t1, t2; call verify_vtq; No A B C D diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index 13c6c82aa99..5144e6366bf 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -142,6 +142,12 @@ create view v1 as select * from t2 inner join t1 using (a); select * from v1; drop view v1; +create or replace table t1 (a int) with system versioning; +insert into t1 values (1); +create view vt1 as select a from t1; +select * from t1 natural join vt1; +drop view vt1; + drop table t1, t2; call verify_vtq; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 3d5f158df36..a75a33e1405 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -832,7 +832,8 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, Item *row_start= NULL; Item *row_end= NULL; - if (table->is_derived() && !table->is_recursive_with_table()) + if ((table->is_derived() && !table->is_recursive_with_table()) || + table->join_columns) { row_start= newx Item_field(thd, &slex->context, NULL, NULL, fstart->field_name); -- cgit v1.2.1 From 4782b74023083b9d5956c76c7c444f1a3f6a3419 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Sat, 11 Mar 2017 13:09:07 +0700 Subject: Misc: warnings fix related to b0419561a3475ff3464316c7104455685819acca --- sql/item_vers.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/item_vers.cc b/sql/item_vers.cc index 0a15d67b535..81cc3808651 100644 --- a/sql/item_vers.cc +++ b/sql/item_vers.cc @@ -19,9 +19,9 @@ System Versioning items */ -#include "item.h" #include "sql_class.h" #include "tztime.h" +#include "item.h" Item_func_vtq_ts::Item_func_vtq_ts( THD *thd, -- cgit v1.2.1 From a37cf5258b69c88d555fee73d3df0978aab226d3 Mon Sep 17 00:00:00 2001 From: kevg Date: Mon, 13 Mar 2017 14:29:21 +0300 Subject: SQL: CREATE VIEW with view_list from versioned table [fixes #151] --- mysql-test/suite/versioning/r/view.result | 2 ++ mysql-test/suite/versioning/t/view.test | 3 +++ sql/sql_view.cc | 21 +++++++++++++++++---- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/mysql-test/suite/versioning/r/view.result b/mysql-test/suite/versioning/r/view.result index 0406f47cf3b..4dc6455e7ab 100644 --- a/mysql-test/suite/versioning/r/view.result +++ b/mysql-test/suite/versioning/r/view.result @@ -110,6 +110,8 @@ x 1 select * from vvvt1 for system_time all; x +create or replace table t1 (x int) with system versioning; +create or replace view vt1(c) as select x from t1; drop view vvvt1; drop view vvt1; drop view vt1; diff --git a/mysql-test/suite/versioning/t/view.test b/mysql-test/suite/versioning/t/view.test index 1ed487fec44..909e55eac82 100644 --- a/mysql-test/suite/versioning/t/view.test +++ b/mysql-test/suite/versioning/t/view.test @@ -70,6 +70,9 @@ select * from vt1 for system_time all; select * from vvt1 for system_time all; select * from vvvt1 for system_time all; +create or replace table t1 (x int) with system versioning; +create or replace view vt1(c) as select x from t1; + drop view vvvt1; drop view vvt1; drop view vt1; diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 8ee4a75e259..215d81f5724 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -463,12 +463,25 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, TABLE_SHARE *s= tl->table->s; if (s->versioned) { + const char *start= s->vers_start_field()->field_name; + const char *end = s->vers_end_field()->field_name; + select_lex->item_list.push_back(new (thd->mem_root) Item_field( - thd, &select_lex->context, NULL, NULL, - s->vers_start_field()->field_name)); + thd, &select_lex->context, NULL, NULL, start)); select_lex->item_list.push_back(new (thd->mem_root) Item_field( - thd, &select_lex->context, NULL, NULL, - s->vers_end_field()->field_name)); + thd, &select_lex->context, NULL, NULL, end)); + + if (lex->view_list.elements) + { + if (LEX_STRING *s= thd->make_lex_string(start, strlen(start))) + lex->view_list.push_back(s); + else + goto err; + if (LEX_STRING *s= thd->make_lex_string(end, strlen(end))) + lex->view_list.push_back(s); + else + goto err; + } } } } -- cgit v1.2.1 From 9ea02899f85162039d6b2a200217fc4eec38b777 Mon Sep 17 00:00:00 2001 From: kevg Date: Mon, 13 Mar 2017 20:14:24 +0300 Subject: SQL: nested equi-join for versioned table [fixes #150] --- mysql-test/suite/versioning/r/select.result | 3 +++ mysql-test/suite/versioning/t/select.test | 3 +++ sql/sql_select.cc | 6 +++--- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index 3db2eafb1cd..aa47bc0f614 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -425,6 +425,9 @@ select * from t1 natural join vt1; a 1 drop view vt1; +create or replace table t1(x int) with system versioning; +select * from (t1 as r left join t1 as u using (x)), t1; +x x drop table t1, t2; call verify_vtq; No A B C D diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index 5144e6366bf..2b7ba18c351 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -148,6 +148,9 @@ create view vt1 as select a from t1; select * from t1 natural join vt1; drop view vt1; +create or replace table t1(x int) with system versioning; +select * from (t1 as r left join t1 as u using (x)), t1; + drop table t1, t2; call verify_vtq; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a75a33e1405..f9e67a8caaa 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -835,10 +835,10 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, if ((table->is_derived() && !table->is_recursive_with_table()) || table->join_columns) { - row_start= newx Item_field(thd, &slex->context, NULL, NULL, + row_start= newx Item_field(thd, &slex->context, table->db, table->alias, fstart->field_name); - row_end= - newx Item_field(thd, &slex->context, NULL, NULL, fend->field_name); + row_end= newx Item_field(thd, &slex->context, table->db, table->alias, + fend->field_name); } else { -- cgit v1.2.1 From 77f23b3e4961ffa0bf188d2e97bdf51d16075368 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 14 Mar 2017 06:44:48 +0300 Subject: Tests: sys_vars.sysvars_server_notembedded result Related to: #32, #117 --- .../sys_vars/r/sysvars_server_notembedded.result | 42 ++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result index 26f539685df..d2036f830be 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result @@ -4769,6 +4769,20 @@ NUMERIC_BLOCK_SIZE 1 ENUM_VALUE_LIST NULL READ_ONLY YES COMMAND_LINE_ARGUMENT REQUIRED +VARIABLE_NAME TEMPORAL_CURRENT_TIMESTAMP +SESSION_VALUE NULL +GLOBAL_VALUE now +GLOBAL_VALUE_ORIGIN COMPILE-TIME +DEFAULT_VALUE now +VARIABLE_SCOPE GLOBAL +VARIABLE_TYPE VARCHAR +VARIABLE_COMMENT Default AS OF value for versioned tables +NUMERIC_MIN_VALUE NULL +NUMERIC_MAX_VALUE NULL +NUMERIC_BLOCK_SIZE NULL +ENUM_VALUE_LIST NULL +READ_ONLY NO +COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME THREAD_CACHE_SIZE SESSION_VALUE NULL GLOBAL_VALUE 151 @@ -5119,6 +5133,34 @@ NUMERIC_BLOCK_SIZE NULL ENUM_VALUE_LIST NEVER,COMPLEMENTARY,PREFERABLY READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED +VARIABLE_NAME VERS_FORCE +SESSION_VALUE NULL +GLOBAL_VALUE OFF +GLOBAL_VALUE_ORIGIN COMPILE-TIME +DEFAULT_VALUE OFF +VARIABLE_SCOPE GLOBAL +VARIABLE_TYPE BOOLEAN +VARIABLE_COMMENT Force system versioning for all created tables +NUMERIC_MIN_VALUE NULL +NUMERIC_MAX_VALUE NULL +NUMERIC_BLOCK_SIZE NULL +ENUM_VALUE_LIST OFF,ON +READ_ONLY NO +COMMAND_LINE_ARGUMENT OPTIONAL +VARIABLE_NAME VERS_HIDE +SESSION_VALUE NULL +GLOBAL_VALUE OFF +GLOBAL_VALUE_ORIGIN COMPILE-TIME +DEFAULT_VALUE OFF +VARIABLE_SCOPE GLOBAL +VARIABLE_TYPE BOOLEAN +VARIABLE_COMMENT Hide system versioning from being displayed in table info +NUMERIC_MIN_VALUE NULL +NUMERIC_MAX_VALUE NULL +NUMERIC_BLOCK_SIZE NULL +ENUM_VALUE_LIST OFF,ON +READ_ONLY NO +COMMAND_LINE_ARGUMENT OPTIONAL VARIABLE_NAME WAIT_TIMEOUT SESSION_VALUE 28800 GLOBAL_VALUE 28800 -- cgit v1.2.1 From 92c7a87119d1a212d0028dd05a834f458cc9e6f8 Mon Sep 17 00:00:00 2001 From: kevg Date: Tue, 14 Mar 2017 10:09:44 +0300 Subject: Misc: vers_setup_select() Item_field ctor fix Related to #150 --- sql/sql_select.cc | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index f9e67a8caaa..1421a41a9f4 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -827,24 +827,13 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, dst_cond= &table->on_expr; } - Field *fstart= table->table->vers_start_field(); - Field *fend= table->table->vers_end_field(); + const char *fstart= table->table->vers_start_field()->field_name; + const char *fend= table->table->vers_end_field()->field_name; - Item *row_start= NULL; - Item *row_end= NULL; - if ((table->is_derived() && !table->is_recursive_with_table()) || - table->join_columns) - { - row_start= newx Item_field(thd, &slex->context, table->db, table->alias, - fstart->field_name); - row_end= newx Item_field(thd, &slex->context, table->db, table->alias, - fend->field_name); - } - else - { - row_start= newx Item_field(thd, &slex->context, fstart); - row_end= newx Item_field(thd, &slex->context, fend); - } + Item *row_start= + newx Item_field(thd, &slex->context, table->db, table->alias, fstart); + Item *row_end= + newx Item_field(thd, &slex->context, table->db, table->alias, fend); Item *row_end2= row_end; if (table->table->versioned_by_sql()) -- cgit v1.2.1 From 4ebf680c9bb7fa42656a87024e9d464226b089d4 Mon Sep 17 00:00:00 2001 From: kevg Date: Tue, 14 Mar 2017 13:05:39 +0300 Subject: SQL: VIEW over a JOIN of versioned tables [fixes #153] --- mysql-test/suite/versioning/r/view.result | 17 +++++++++++++---- mysql-test/suite/versioning/t/view.test | 15 +++++++++++---- sql/sql_view.cc | 4 ++-- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/mysql-test/suite/versioning/r/view.result b/mysql-test/suite/versioning/r/view.result index 4dc6455e7ab..104e2a557e8 100644 --- a/mysql-test/suite/versioning/r/view.result +++ b/mysql-test/suite/versioning/r/view.result @@ -112,7 +112,16 @@ select * from vvvt1 for system_time all; x create or replace table t1 (x int) with system versioning; create or replace view vt1(c) as select x from t1; -drop view vvvt1; -drop view vvt1; -drop view vt1; -drop table t1; +create or replace table t1 (a int) with system versioning; +create or replace table t2 (b int) with system versioning; +insert into t1 values (1); +insert into t2 values (2); +create or replace view vt12 as select * from t1 cross join t2; +select * from vt12; +a b +1 2 +create or replace view vt12 as select * from t1 for system_time as of timestamp '0-0-0' cross join t2; +select * from vt12; +a b +drop view vt1, vvt1, vvvt1, vt12; +drop table t1, t2; diff --git a/mysql-test/suite/versioning/t/view.test b/mysql-test/suite/versioning/t/view.test index 909e55eac82..c284df3ec5e 100644 --- a/mysql-test/suite/versioning/t/view.test +++ b/mysql-test/suite/versioning/t/view.test @@ -73,7 +73,14 @@ select * from vvvt1 for system_time all; create or replace table t1 (x int) with system versioning; create or replace view vt1(c) as select x from t1; -drop view vvvt1; -drop view vvt1; -drop view vt1; -drop table t1; +create or replace table t1 (a int) with system versioning; +create or replace table t2 (b int) with system versioning; +insert into t1 values (1); +insert into t2 values (2); +create or replace view vt12 as select * from t1 cross join t2; +select * from vt12; +create or replace view vt12 as select * from t1 for system_time as of timestamp '0-0-0' cross join t2; +select * from vt12; + +drop view vt1, vvt1, vvvt1, vt12; +drop table t1, t2; diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 215d81f5724..d542a5710f6 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -467,9 +467,9 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, const char *end = s->vers_end_field()->field_name; select_lex->item_list.push_back(new (thd->mem_root) Item_field( - thd, &select_lex->context, NULL, NULL, start)); + thd, &select_lex->context, tables->db, tables->alias, start)); select_lex->item_list.push_back(new (thd->mem_root) Item_field( - thd, &select_lex->context, NULL, NULL, end)); + thd, &select_lex->context, tables->db, tables->alias, end)); if (lex->view_list.elements) { -- cgit v1.2.1 From 7fd549095f11162915641b2a292a57e2d50ddbea Mon Sep 17 00:00:00 2001 From: kevg Date: Tue, 14 Mar 2017 13:38:59 +0300 Subject: IB: return correct sys_trx_end in TRIGGER after UPDATE [fixes #100] --- mysql-test/suite/versioning/r/select.result | 18 ++++++++++++++++++ mysql-test/suite/versioning/t/select.test | 16 ++++++++++++++++ storage/innobase/row/row0mysql.cc | 1 - 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index aa47bc0f614..2ed36061e70 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -428,6 +428,22 @@ drop view vt1; create or replace table t1(x int) with system versioning; select * from (t1 as r left join t1 as u using (x)), t1; x x +create or replace table t1 (a int) with system versioning; +insert into t1 values (1); +create trigger read_end after update on t1 +for each row set @end = old.sys_trx_end; +update t1 set a=2; +select @end; +@end +2038-01-19 03:14:07.000000 +create or replace table t1 (a int) with system versioning engine=innodb; +insert into t1 values (1); +create trigger read_end after update on t1 +for each row set @end = old.sys_trx_end; +update t1 set a=2; +select @end; +@end +18446744073709551615 drop table t1, t2; call verify_vtq; No A B C D @@ -440,6 +456,8 @@ No A B C D 7 1 1 1 1 8 1 1 1 1 9 1 1 1 1 +10 1 1 1 1 +11 1 1 1 1 drop procedure test_01; drop procedure test_02; drop procedure verify_vtq; diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index 2b7ba18c351..5b6bce2678f 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -151,6 +151,22 @@ drop view vt1; create or replace table t1(x int) with system versioning; select * from (t1 as r left join t1 as u using (x)), t1; +# @end should be max timestamp +create or replace table t1 (a int) with system versioning; +insert into t1 values (1); +create trigger read_end after update on t1 + for each row set @end = old.sys_trx_end; +update t1 set a=2; +select @end; + +# @end should be max trx_id +create or replace table t1 (a int) with system versioning engine=innodb; +insert into t1 values (1); +create trigger read_end after update on t1 + for each row set @end = old.sys_trx_end; +update t1 set a=2; +select @end; + drop table t1, t2; call verify_vtq; diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index ce1a0dda7b2..5c1ac9775ee 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -1497,7 +1497,6 @@ row_insert_for_mysql( if (ins_mode == ROW_INS_HISTORICAL) { set_tuple_col_8(node->row, table->vers_row_end, trx->id, node->entry_sys_heap); - int8store(&mysql_rec[t->mysql_col_offset], trx->id); } else { set_tuple_col_8(node->row, table->vers_row_end, IB_UINT64_MAX, node->entry_sys_heap); -- cgit v1.2.1 From 5a08bd35156fe28726744cd5abbafad4e308b029 Mon Sep 17 00:00:00 2001 From: kevg Date: Tue, 14 Mar 2017 20:55:17 +0300 Subject: Tests: subqueries with JOINed tables with different FOR SYSTEM_TIME clauses [closes #154] --- mysql-test/suite/versioning/r/select.result | 12 ++++++++++++ mysql-test/suite/versioning/t/select.test | 8 ++++++++ 2 files changed, 20 insertions(+) diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index 2ed36061e70..229c470d408 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -444,6 +444,18 @@ update t1 set a=2; select @end; @end 18446744073709551615 +create or replace table t1 (a int) with system versioning; +create or replace table t2 (b int) with system versioning; +insert into t1 values (1); +insert into t2 values (2); +select * from (select * from t1 cross join t2) as tmp; +a b +1 2 +select * from (select * from (select * from t1 cross join t2) as tmp1) as tmp2; +a b +1 2 +select * from (select * from t1 cross join t2 for system_time as of timestamp '0-0-0') as tmp; +a b drop table t1, t2; call verify_vtq; No A B C D diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index 5b6bce2678f..d04d9fc914d 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -167,6 +167,14 @@ create trigger read_end after update on t1 update t1 set a=2; select @end; +create or replace table t1 (a int) with system versioning; +create or replace table t2 (b int) with system versioning; +insert into t1 values (1); +insert into t2 values (2); +select * from (select * from t1 cross join t2) as tmp; +select * from (select * from (select * from t1 cross join t2) as tmp1) as tmp2; +select * from (select * from t1 cross join t2 for system_time as of timestamp '0-0-0') as tmp; + drop table t1, t2; call verify_vtq; -- cgit v1.2.1 From fb0b3e590288564317a8ba048914a3a912e7627c Mon Sep 17 00:00:00 2001 From: kevg Date: Wed, 15 Mar 2017 16:32:44 +0300 Subject: SQL: NATURAL LEFT JOIN for versioned tables [fixes #156] --- mysql-test/suite/versioning/r/select.result | 10 ++++++++++ mysql-test/suite/versioning/t/select.test | 6 ++++++ sql/sql_base.cc | 11 +++++++---- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index 229c470d408..9dc32249692 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -456,6 +456,16 @@ a b 1 2 select * from (select * from t1 cross join t2 for system_time as of timestamp '0-0-0') as tmp; a b +create or replace table t1(a1 int) with system versioning; +create or replace table t2(a2 int) with system versioning; +insert into t1 values(1),(2); +insert into t2 values(1),(2); +select * from t1 for system_time all natural left join t2 for system_time all; +a1 a2 +1 1 +2 1 +1 2 +2 2 drop table t1, t2; call verify_vtq; No A B C D diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index d04d9fc914d..a535cd67e07 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -175,6 +175,12 @@ select * from (select * from t1 cross join t2) as tmp; select * from (select * from (select * from t1 cross join t2) as tmp1) as tmp2; select * from (select * from t1 cross join t2 for system_time as of timestamp '0-0-0') as tmp; +create or replace table t1(a1 int) with system versioning; +create or replace table t2(a2 int) with system versioning; +insert into t1 values(1),(2); +insert into t2 values(1),(2); +select * from t1 for system_time all natural left join t2 for system_time all; + drop table t1, t2; call verify_vtq; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index b0fe02aba69..14bc741057b 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -5350,7 +5350,7 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, { if (!my_strcasecmp(system_charset_info, curr_nj_col->name(), name)) { - if (nj_col && !curr_nj_col->table_field->field->vers_sys_field()) + if (nj_col) { my_error(ER_NON_UNIQ_ERROR, MYF(0), name, thd->where); DBUG_RETURN(NULL); @@ -6379,6 +6379,10 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, bool is_using_column_1; if (!(nj_col_1= it_1.get_or_create_column_ref(thd, leaf_1))) goto err; + + if (nj_col_1->field() && nj_col_1->field()->vers_sys_field()) + continue; + field_name_1= nj_col_1->name(); is_using_column_1= using_fields && test_if_string_in_list(field_name_1, using_fields); @@ -6420,9 +6424,8 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, if (!my_strcasecmp(system_charset_info, field_name_1, cur_field_name_2)) { DBUG_PRINT ("info", ("match c1.is_common=%d", nj_col_1->is_common)); - if ((!it_1.field() || !it_1.field()->vers_sys_field()) && - (cur_nj_col_2->is_common || - (found && (!using_fields || is_using_column_1)))) + if (cur_nj_col_2->is_common || + (found && (!using_fields || is_using_column_1))) { my_error(ER_NON_UNIQ_ERROR, MYF(0), field_name_1, thd->where); goto err; -- cgit v1.2.1 From 1894fab11a998c4715d774aa5ec2f036baa8f5b9 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 15 Mar 2017 18:36:54 +0300 Subject: Tests: split versioning.select into combinations --- mysql-test/suite/versioning/common.inc | 51 ++++- mysql-test/suite/versioning/common.opt | 18 +- mysql-test/suite/versioning/common_finish.inc | 5 + mysql-test/suite/versioning/r/alter.result | 49 +++++ .../suite/versioning/r/auto_increment.result | 49 +++++ mysql-test/suite/versioning/r/commit_id.result | 49 +++++ mysql-test/suite/versioning/r/delete.result | 49 +++++ mysql-test/suite/versioning/r/insert.result | 49 +++++ mysql-test/suite/versioning/r/select.result | 216 ++++++++------------- mysql-test/suite/versioning/r/update.result | 49 +++++ mysql-test/suite/versioning/t/alter.test | 3 +- mysql-test/suite/versioning/t/auto_increment.test | 2 +- mysql-test/suite/versioning/t/commit_id.test | 4 +- mysql-test/suite/versioning/t/delete.test | 3 +- mysql-test/suite/versioning/t/insert.test | 3 +- mysql-test/suite/versioning/t/select.combinations | 5 + mysql-test/suite/versioning/t/select.test | 65 +++---- mysql-test/suite/versioning/t/update.test | 3 +- 18 files changed, 486 insertions(+), 186 deletions(-) create mode 100644 mysql-test/suite/versioning/common_finish.inc create mode 100644 mysql-test/suite/versioning/t/select.combinations diff --git a/mysql-test/suite/versioning/common.inc b/mysql-test/suite/versioning/common.inc index 6723395f92f..9e26903c03b 100644 --- a/mysql-test/suite/versioning/common.inc +++ b/mysql-test/suite/versioning/common.inc @@ -1,5 +1,3 @@ --- source include/have_innodb.inc - set @@session.time_zone='+00:00'; select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; @@ -19,4 +17,53 @@ begin into @start_trx_id from information_schema.innodb_vtq; end~~ + +create function if not exists default_engine() +returns varchar(255) +deterministic +begin + declare e varchar(255); + select lower(engine) from information_schema.engines where support='DEFAULT' into e; + return e; +end~~ + +create function if not exists sys_datatype() +returns varchar(255) +deterministic +begin + if default_engine() = 'innodb' then + return 'bigint unsigned'; + elseif default_engine() = 'myisam' then + return 'timestamp(6)'; + end if; + return NULL; +end~~ + +create function if not exists sys_commit_ts(sys_field varchar(255)) +returns varchar(255) +deterministic +begin + if default_engine() = 'innodb' then + return concat('vtq_commit_ts(', sys_field, ')'); + elseif default_engine() = 'myisam' then + return sys_field; + end if; + return NULL; +end~~ + +create procedure if not exists innodb_verify_vtq(recs int) +begin + declare i int default 1; + if default_engine() = 'innodb' then + call verify_vtq; + elseif default_engine() = 'myisam' then + create temporary table tmp (No int, A bool, B bool, C bool, D bool); + while i <= recs do + insert into tmp values (i, 1, 1, 1, 1); + set i= i + 1; + end while; + select * from tmp; + drop table tmp; + end if; +end~~ delimiter ;~~ diff --git a/mysql-test/suite/versioning/common.opt b/mysql-test/suite/versioning/common.opt index 32a25eea24f..c108024a0bd 100644 --- a/mysql-test/suite/versioning/common.opt +++ b/mysql-test/suite/versioning/common.opt @@ -1 +1,17 @@ ---loose-innodb-vtq +--innodb +--innodb-cmpmem +--innodb-cmp-per-index +--innodb-trx +--innodb-locks +--innodb-metrics +--innodb-buffer-pool-stats +--innodb-buffer-page +--innodb-buffer-page-lru +--innodb-sys-columns +--innodb-sys-fields +--innodb-sys-foreign +--innodb-sys-foreign-cols +--innodb-sys-indexes +--innodb-sys-tables +--innodb-sys-virtual +--innodb-vtq diff --git a/mysql-test/suite/versioning/common_finish.inc b/mysql-test/suite/versioning/common_finish.inc new file mode 100644 index 00000000000..0dbe07085c9 --- /dev/null +++ b/mysql-test/suite/versioning/common_finish.inc @@ -0,0 +1,5 @@ +drop procedure verify_vtq; +drop procedure innodb_verify_vtq; +drop function default_engine; +drop function sys_commit_ts; +drop function sys_datatype; diff --git a/mysql-test/suite/versioning/r/alter.result b/mysql-test/suite/versioning/r/alter.result index 7b0523d4e96..598aa6b98a8 100644 --- a/mysql-test/suite/versioning/r/alter.result +++ b/mysql-test/suite/versioning/r/alter.result @@ -248,6 +248,51 @@ select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; end~~ +create function if not exists default_engine() +returns varchar(255) +deterministic +begin +declare e varchar(255); +select lower(engine) from information_schema.engines where support='DEFAULT' into e; +return e; +end~~ +create function if not exists sys_datatype() +returns varchar(255) +deterministic +begin +if default_engine() = 'innodb' then +return 'bigint unsigned'; +elseif default_engine() = 'myisam' then +return 'timestamp(6)'; +end if; +return NULL; +end~~ +create function if not exists sys_commit_ts(sys_field varchar(255)) +returns varchar(255) +deterministic +begin +if default_engine() = 'innodb' then +return concat('vtq_commit_ts(', sys_field, ')'); +elseif default_engine() = 'myisam' then +return sys_field; +end if; +return NULL; +end~~ +create procedure if not exists innodb_verify_vtq(recs int) +begin +declare i int default 1; +if default_engine() = 'innodb' then +call verify_vtq; +elseif default_engine() = 'myisam' then +create temporary table tmp (No int, A bool, B bool, C bool, D bool); +while i <= recs do +insert into tmp values (i, 1, 1, 1, 1); +set i= i + 1; +end while; +select * from tmp; +drop table tmp; +end if; +end~~ create or replace table t( a int ) engine=innodb; @@ -448,3 +493,7 @@ No A B C D 11 1 1 1 1 drop table t; drop procedure verify_vtq; +drop procedure innodb_verify_vtq; +drop function default_engine; +drop function sys_commit_ts; +drop function sys_datatype; diff --git a/mysql-test/suite/versioning/r/auto_increment.result b/mysql-test/suite/versioning/r/auto_increment.result index 81222963826..ae06e9348bf 100644 --- a/mysql-test/suite/versioning/r/auto_increment.result +++ b/mysql-test/suite/versioning/r/auto_increment.result @@ -15,6 +15,51 @@ select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; end~~ +create function if not exists default_engine() +returns varchar(255) +deterministic +begin +declare e varchar(255); +select lower(engine) from information_schema.engines where support='DEFAULT' into e; +return e; +end~~ +create function if not exists sys_datatype() +returns varchar(255) +deterministic +begin +if default_engine() = 'innodb' then +return 'bigint unsigned'; +elseif default_engine() = 'myisam' then +return 'timestamp(6)'; +end if; +return NULL; +end~~ +create function if not exists sys_commit_ts(sys_field varchar(255)) +returns varchar(255) +deterministic +begin +if default_engine() = 'innodb' then +return concat('vtq_commit_ts(', sys_field, ')'); +elseif default_engine() = 'myisam' then +return sys_field; +end if; +return NULL; +end~~ +create procedure if not exists innodb_verify_vtq(recs int) +begin +declare i int default 1; +if default_engine() = 'innodb' then +call verify_vtq; +elseif default_engine() = 'myisam' then +create temporary table tmp (No int, A bool, B bool, C bool, D bool); +while i <= recs do +insert into tmp values (i, 1, 1, 1, 1); +set i= i + 1; +end while; +select * from tmp; +drop table tmp; +end if; +end~~ create procedure test_01( sys_type varchar(255), engine varchar(255), @@ -135,3 +180,7 @@ No A B C D 11 1 1 1 1 drop procedure test_01; drop procedure verify_vtq; +drop procedure innodb_verify_vtq; +drop function default_engine; +drop function sys_commit_ts; +drop function sys_datatype; diff --git a/mysql-test/suite/versioning/r/commit_id.result b/mysql-test/suite/versioning/r/commit_id.result index bb70b239fa0..9a41c0f3eb1 100644 --- a/mysql-test/suite/versioning/r/commit_id.result +++ b/mysql-test/suite/versioning/r/commit_id.result @@ -15,6 +15,51 @@ select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; end~~ +create function if not exists default_engine() +returns varchar(255) +deterministic +begin +declare e varchar(255); +select lower(engine) from information_schema.engines where support='DEFAULT' into e; +return e; +end~~ +create function if not exists sys_datatype() +returns varchar(255) +deterministic +begin +if default_engine() = 'innodb' then +return 'bigint unsigned'; +elseif default_engine() = 'myisam' then +return 'timestamp(6)'; +end if; +return NULL; +end~~ +create function if not exists sys_commit_ts(sys_field varchar(255)) +returns varchar(255) +deterministic +begin +if default_engine() = 'innodb' then +return concat('vtq_commit_ts(', sys_field, ')'); +elseif default_engine() = 'myisam' then +return sys_field; +end if; +return NULL; +end~~ +create procedure if not exists innodb_verify_vtq(recs int) +begin +declare i int default 1; +if default_engine() = 'innodb' then +call verify_vtq; +elseif default_engine() = 'myisam' then +create temporary table tmp (No int, A bool, B bool, C bool, D bool); +while i <= recs do +insert into tmp values (i, 1, 1, 1, 1); +set i= i + 1; +end while; +select * from tmp; +drop table tmp; +end if; +end~~ create table t1( id int auto_increment primary key) with system versioning @@ -101,3 +146,7 @@ No A B C D 6 1 1 1 1 7 1 1 1 1 drop procedure verify_vtq; +drop procedure innodb_verify_vtq; +drop function default_engine; +drop function sys_commit_ts; +drop function sys_datatype; diff --git a/mysql-test/suite/versioning/r/delete.result b/mysql-test/suite/versioning/r/delete.result index e8e7ba34919..784a0a8ad0c 100644 --- a/mysql-test/suite/versioning/r/delete.result +++ b/mysql-test/suite/versioning/r/delete.result @@ -15,6 +15,51 @@ select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; end~~ +create function if not exists default_engine() +returns varchar(255) +deterministic +begin +declare e varchar(255); +select lower(engine) from information_schema.engines where support='DEFAULT' into e; +return e; +end~~ +create function if not exists sys_datatype() +returns varchar(255) +deterministic +begin +if default_engine() = 'innodb' then +return 'bigint unsigned'; +elseif default_engine() = 'myisam' then +return 'timestamp(6)'; +end if; +return NULL; +end~~ +create function if not exists sys_commit_ts(sys_field varchar(255)) +returns varchar(255) +deterministic +begin +if default_engine() = 'innodb' then +return concat('vtq_commit_ts(', sys_field, ')'); +elseif default_engine() = 'myisam' then +return sys_field; +end if; +return NULL; +end~~ +create procedure if not exists innodb_verify_vtq(recs int) +begin +declare i int default 1; +if default_engine() = 'innodb' then +call verify_vtq; +elseif default_engine() = 'myisam' then +create temporary table tmp (No int, A bool, B bool, C bool, D bool); +while i <= recs do +insert into tmp values (i, 1, 1, 1, 1); +set i= i + 1; +end while; +select * from tmp; +drop table tmp; +end if; +end~~ create or replace procedure test_01( sys_type varchar(255), engine varchar(255), @@ -308,3 +353,7 @@ drop procedure test_01; drop procedure test_02; drop procedure test_03; drop procedure verify_vtq; +drop procedure innodb_verify_vtq; +drop function default_engine; +drop function sys_commit_ts; +drop function sys_datatype; diff --git a/mysql-test/suite/versioning/r/insert.result b/mysql-test/suite/versioning/r/insert.result index cd89083480a..8619ce3a916 100644 --- a/mysql-test/suite/versioning/r/insert.result +++ b/mysql-test/suite/versioning/r/insert.result @@ -15,6 +15,51 @@ select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; end~~ +create function if not exists default_engine() +returns varchar(255) +deterministic +begin +declare e varchar(255); +select lower(engine) from information_schema.engines where support='DEFAULT' into e; +return e; +end~~ +create function if not exists sys_datatype() +returns varchar(255) +deterministic +begin +if default_engine() = 'innodb' then +return 'bigint unsigned'; +elseif default_engine() = 'myisam' then +return 'timestamp(6)'; +end if; +return NULL; +end~~ +create function if not exists sys_commit_ts(sys_field varchar(255)) +returns varchar(255) +deterministic +begin +if default_engine() = 'innodb' then +return concat('vtq_commit_ts(', sys_field, ')'); +elseif default_engine() = 'myisam' then +return sys_field; +end if; +return NULL; +end~~ +create procedure if not exists innodb_verify_vtq(recs int) +begin +declare i int default 1; +if default_engine() = 'innodb' then +call verify_vtq; +elseif default_engine() = 'myisam' then +create temporary table tmp (No int, A bool, B bool, C bool, D bool); +while i <= recs do +insert into tmp values (i, 1, 1, 1, 1); +set i= i + 1; +end while; +select * from tmp; +drop table tmp; +end if; +end~~ create procedure test_01( sys_type varchar(255), engine varchar(255), @@ -305,3 +350,7 @@ drop procedure test_03; drop procedure test_04; drop procedure test_05; drop procedure verify_vtq; +drop procedure innodb_verify_vtq; +drop function default_engine; +drop function sys_commit_ts; +drop function sys_datatype; diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index 9dc32249692..86a56fe05a0 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -15,11 +15,56 @@ select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; end~~ -create procedure test_01( -sys_type varchar(255), -engine varchar(255), -fields varchar(255)) +create function if not exists default_engine() +returns varchar(255) +deterministic begin +declare e varchar(255); +select lower(engine) from information_schema.engines where support='DEFAULT' into e; +return e; +end~~ +create function if not exists sys_datatype() +returns varchar(255) +deterministic +begin +if default_engine() = 'innodb' then +return 'bigint unsigned'; +elseif default_engine() = 'myisam' then +return 'timestamp(6)'; +end if; +return NULL; +end~~ +create function if not exists sys_commit_ts(sys_field varchar(255)) +returns varchar(255) +deterministic +begin +if default_engine() = 'innodb' then +return concat('vtq_commit_ts(', sys_field, ')'); +elseif default_engine() = 'myisam' then +return sys_field; +end if; +return NULL; +end~~ +create procedure if not exists innodb_verify_vtq(recs int) +begin +declare i int default 1; +if default_engine() = 'innodb' then +call verify_vtq; +elseif default_engine() = 'myisam' then +create temporary table tmp (No int, A bool, B bool, C bool, D bool); +while i <= recs do +insert into tmp values (i, 1, 1, 1, 1); +set i= i + 1; +end while; +select * from tmp; +drop table tmp; +end if; +end~~ +create procedure test_01() +begin +declare engine varchar(255) default default_engine(); +declare sys_type varchar(255) default sys_datatype(); +declare fields varchar(255) default sys_commit_ts('sys_start'); set @str= concat(' create table t1( x int unsigned, @@ -66,14 +111,20 @@ select x as FROMTO2_x, y from t1 for system_time from transaction 0 to transacti select x as BETWAND2_x, y from t1 for system_time between transaction 0 and transaction @x1; select x as FROMTO2_ext_x, y from t1 for system_time transaction from 0 to @x1; select x as BETWAND2_ext_x, y from t1 for system_time transaction between 0 and @x1; +else +select x as ASOF2_x, y from t1 for system_time as of timestamp @t0; +select x as FROMTO2_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; +select x as BETWAND2_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; +select x as FROMTO2_ext_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; +select x as BETWAND2_ext_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; end if; drop table t1; end~~ -create or replace procedure test_02( -sys_type varchar(255), -engine varchar(255), -fields varchar(255)) +create or replace procedure test_02() begin +declare engine varchar(255) default default_engine(); +declare sys_type varchar(255) default sys_datatype(); +declare fields varchar(255) default sys_commit_ts('sys_start'); set @str0= concat('( x int, y int, @@ -103,86 +154,7 @@ query for system_time as of timestamp @t0; drop table t1; drop table t2; end~~ -call test_01('timestamp(6)', 'myisam', 'sys_start'); -x y -0 100 -1 101 -2 102 -4 104 -5 105 -6 106 -7 107 -3 33 -ASOF_x y -0 100 -1 101 -2 102 -3 103 -4 104 -5 105 -6 106 -7 107 -8 108 -9 109 -FROMTO_x y -0 100 -1 101 -2 102 -3 103 -4 104 -5 105 -6 106 -7 107 -8 108 -9 109 -BETWAND_x y -0 100 -1 101 -2 102 -3 103 -4 104 -5 105 -6 106 -7 107 -8 108 -9 109 -3 33 -FROMTO_ext_x y -0 100 -1 101 -2 102 -3 103 -4 104 -5 105 -6 106 -7 107 -8 108 -9 109 -BETWAND_ext_x y -0 100 -1 101 -2 102 -3 103 -4 104 -5 105 -6 106 -7 107 -8 108 -9 109 -3 33 -ALL_x y -0 100 -1 101 -2 102 -3 103 -4 104 -5 105 -6 106 -7 107 -8 108 -9 109 -3 33 -call test_01('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_start)'); +call test_01(); x y 0 100 1 101 @@ -318,40 +290,7 @@ BETWAND2_ext_x y 8 108 9 109 3 33 -call test_02('timestamp(6)', 'myisam', 'sys_start'); -IJ1_x1 y1 x2 y2 -1 1 1 2 -1 2 1 2 -1 3 1 2 -LJ1_x1 y1 x2 y2 -1 1 1 2 -1 2 1 2 -1 3 1 2 -4 4 NULL NULL -5 5 NULL NULL -RJ1_x1 y1 x2 y2 -1 1 1 2 -1 2 1 2 -1 3 1 2 -NULL NULL 2 1 -NULL NULL 3 1 -IJ2_x1 y1 x2 y2 -1 1 1 2 -1 2 1 2 -1 3 1 2 -LJ2_x1 y1 x2 y2 -1 1 1 2 -1 2 1 2 -1 3 1 2 -4 4 NULL NULL -5 5 NULL NULL -RJ2_x1 y1 x2 y2 -1 1 1 2 -1 2 1 2 -1 3 1 2 -NULL NULL 2 1 -NULL NULL 3 1 -call test_02('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_start)'); +call test_02(); IJ1_x1 y1 x2 y2 1 1 1 2 1 2 1 2 @@ -386,14 +325,7 @@ NULL NULL 2 1 NULL NULL 3 1 create table t1( A int -) with system versioning engine=myisam; -insert into t1 values(1); -select * from t1; -A -1 -create or replace table t1( -A int -) with system versioning engine=innodb; +) with system versioning; insert into t1 values(1); select * from t1; A @@ -435,15 +367,7 @@ for each row set @end = old.sys_trx_end; update t1 set a=2; select @end; @end -2038-01-19 03:14:07.000000 -create or replace table t1 (a int) with system versioning engine=innodb; -insert into t1 values (1); -create trigger read_end after update on t1 -for each row set @end = old.sys_trx_end; -update t1 set a=2; -select @end; -@end -18446744073709551615 +MAX_RESULT create or replace table t1 (a int) with system versioning; create or replace table t2 (b int) with system versioning; insert into t1 values (1); @@ -467,7 +391,7 @@ a1 a2 1 2 2 2 drop table t1, t2; -call verify_vtq; +call innodb_verify_vtq(19); No A B C D 1 1 1 1 1 2 1 1 1 1 @@ -480,6 +404,18 @@ No A B C D 9 1 1 1 1 10 1 1 1 1 11 1 1 1 1 +12 1 1 1 1 +13 1 1 1 1 +14 1 1 1 1 +15 1 1 1 1 +16 1 1 1 1 +17 1 1 1 1 +18 1 1 1 1 +19 1 1 1 1 drop procedure test_01; drop procedure test_02; drop procedure verify_vtq; +drop procedure innodb_verify_vtq; +drop function default_engine; +drop function sys_commit_ts; +drop function sys_datatype; diff --git a/mysql-test/suite/versioning/r/update.result b/mysql-test/suite/versioning/r/update.result index 19820660146..0b998dde300 100644 --- a/mysql-test/suite/versioning/r/update.result +++ b/mysql-test/suite/versioning/r/update.result @@ -15,6 +15,51 @@ select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; end~~ +create function if not exists default_engine() +returns varchar(255) +deterministic +begin +declare e varchar(255); +select lower(engine) from information_schema.engines where support='DEFAULT' into e; +return e; +end~~ +create function if not exists sys_datatype() +returns varchar(255) +deterministic +begin +if default_engine() = 'innodb' then +return 'bigint unsigned'; +elseif default_engine() = 'myisam' then +return 'timestamp(6)'; +end if; +return NULL; +end~~ +create function if not exists sys_commit_ts(sys_field varchar(255)) +returns varchar(255) +deterministic +begin +if default_engine() = 'innodb' then +return concat('vtq_commit_ts(', sys_field, ')'); +elseif default_engine() = 'myisam' then +return sys_field; +end if; +return NULL; +end~~ +create procedure if not exists innodb_verify_vtq(recs int) +begin +declare i int default 1; +if default_engine() = 'innodb' then +call verify_vtq; +elseif default_engine() = 'myisam' then +create temporary table tmp (No int, A bool, B bool, C bool, D bool); +while i <= recs do +insert into tmp values (i, 1, 1, 1, 1); +set i= i + 1; +end while; +select * from tmp; +drop table tmp; +end if; +end~~ create procedure test_01( sys_type varchar(255), engine varchar(255), @@ -528,3 +573,7 @@ drop procedure test_05; drop procedure test_06; drop procedure test_07; drop procedure verify_vtq; +drop procedure innodb_verify_vtq; +drop function default_engine; +drop function sys_commit_ts; +drop function sys_datatype; diff --git a/mysql-test/suite/versioning/t/alter.test b/mysql-test/suite/versioning/t/alter.test index da780f6ca55..b6ffb41f33b 100644 --- a/mysql-test/suite/versioning/t/alter.test +++ b/mysql-test/suite/versioning/t/alter.test @@ -204,4 +204,5 @@ select * from t; call verify_vtq; drop table t; -drop procedure verify_vtq; + +-- source suite/versioning/common_finish.inc diff --git a/mysql-test/suite/versioning/t/auto_increment.test b/mysql-test/suite/versioning/t/auto_increment.test index ee5cb9411d0..7b79be575d1 100644 --- a/mysql-test/suite/versioning/t/auto_increment.test +++ b/mysql-test/suite/versioning/t/auto_increment.test @@ -64,5 +64,5 @@ call test_01('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); call verify_vtq; drop procedure test_01; -drop procedure verify_vtq; +-- source suite/versioning/common_finish.inc diff --git a/mysql-test/suite/versioning/t/commit_id.test b/mysql-test/suite/versioning/t/commit_id.test index 9f06e8a5b50..7f7886f07a5 100644 --- a/mysql-test/suite/versioning/t/commit_id.test +++ b/mysql-test/suite/versioning/t/commit_id.test @@ -6,7 +6,6 @@ with system versioning engine innodb; - # VTQ_ISO_LEVEL # set transaction isolation level read uncommitted; @@ -76,4 +75,5 @@ select drop table t1; call verify_vtq; -drop procedure verify_vtq; + +-- source suite/versioning/common_finish.inc diff --git a/mysql-test/suite/versioning/t/delete.test b/mysql-test/suite/versioning/t/delete.test index 320efd29d56..1830f512b88 100644 --- a/mysql-test/suite/versioning/t/delete.test +++ b/mysql-test/suite/versioning/t/delete.test @@ -117,4 +117,5 @@ call verify_vtq; drop procedure test_01; drop procedure test_02; drop procedure test_03; -drop procedure verify_vtq; + +-- source suite/versioning/common_finish.inc diff --git a/mysql-test/suite/versioning/t/insert.test b/mysql-test/suite/versioning/t/insert.test index 2ed44d3ec98..730c5478841 100644 --- a/mysql-test/suite/versioning/t/insert.test +++ b/mysql-test/suite/versioning/t/insert.test @@ -193,4 +193,5 @@ drop procedure test_02; drop procedure test_03; drop procedure test_04; drop procedure test_05; -drop procedure verify_vtq; + +-- source suite/versioning/common_finish.inc diff --git a/mysql-test/suite/versioning/t/select.combinations b/mysql-test/suite/versioning/t/select.combinations new file mode 100644 index 00000000000..75fb20d9f5e --- /dev/null +++ b/mysql-test/suite/versioning/t/select.combinations @@ -0,0 +1,5 @@ +[innodb] +default-storage-engine=innodb + +[myisam] +default-storage-engine=myisam diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index a535cd67e07..115706f9130 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -1,11 +1,12 @@ -- source suite/versioning/common.inc delimiter ~~; -create procedure test_01( - sys_type varchar(255), - engine varchar(255), - fields varchar(255)) +create procedure test_01() begin + declare engine varchar(255) default default_engine(); + declare sys_type varchar(255) default sys_datatype(); + declare fields varchar(255) default sys_commit_ts('sys_start'); + set @str= concat(' create table t1( x int unsigned, @@ -51,21 +52,28 @@ begin select x as ALL_x, y from t1 for system_time all; if engine = 'innodb' then - select x as ASOF2_x, y from t1 for system_time as of transaction @x0; - select x as FROMTO2_x, y from t1 for system_time from transaction 0 to transaction @x1; - select x as BETWAND2_x, y from t1 for system_time between transaction 0 and transaction @x1; - select x as FROMTO2_ext_x, y from t1 for system_time transaction from 0 to @x1; - select x as BETWAND2_ext_x, y from t1 for system_time transaction between 0 and @x1; + select x as ASOF2_x, y from t1 for system_time as of transaction @x0; + select x as FROMTO2_x, y from t1 for system_time from transaction 0 to transaction @x1; + select x as BETWAND2_x, y from t1 for system_time between transaction 0 and transaction @x1; + select x as FROMTO2_ext_x, y from t1 for system_time transaction from 0 to @x1; + select x as BETWAND2_ext_x, y from t1 for system_time transaction between 0 and @x1; + else + select x as ASOF2_x, y from t1 for system_time as of timestamp @t0; + select x as FROMTO2_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; + select x as BETWAND2_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; + select x as FROMTO2_ext_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; + select x as BETWAND2_ext_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; end if; drop table t1; end~~ -create or replace procedure test_02( - sys_type varchar(255), - engine varchar(255), - fields varchar(255)) +create or replace procedure test_02() begin + declare engine varchar(255) default default_engine(); + declare sys_type varchar(255) default sys_datatype(); + declare fields varchar(255) default sys_commit_ts('sys_start'); + set @str0= concat('( x int, y int, @@ -102,22 +110,13 @@ begin end~~ delimiter ;~~ -call test_01('timestamp(6)', 'myisam', 'sys_start'); -call test_01('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_start)'); - -call test_02('timestamp(6)', 'myisam', 'sys_start'); -call test_02('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_start)'); +call test_01(); +call test_02(); # wildcard expansion on hidden fields. create table t1( A int -) with system versioning engine=myisam; -insert into t1 values(1); -select * from t1; - -create or replace table t1( - A int -) with system versioning engine=innodb; +) with system versioning; insert into t1 values(1); select * from t1; @@ -151,20 +150,13 @@ drop view vt1; create or replace table t1(x int) with system versioning; select * from (t1 as r left join t1 as u using (x)), t1; -# @end should be max timestamp +# @end should be max create or replace table t1 (a int) with system versioning; insert into t1 values (1); create trigger read_end after update on t1 for each row set @end = old.sys_trx_end; update t1 set a=2; -select @end; - -# @end should be max trx_id -create or replace table t1 (a int) with system versioning engine=innodb; -insert into t1 values (1); -create trigger read_end after update on t1 - for each row set @end = old.sys_trx_end; -update t1 set a=2; +--replace_result 18446744073709551615 MAX_RESULT "2038-01-19 03:14:07.000000" MAX_RESULT select @end; create or replace table t1 (a int) with system versioning; @@ -183,8 +175,9 @@ select * from t1 for system_time all natural left join t2 for system_time all; drop table t1, t2; -call verify_vtq; +call innodb_verify_vtq(19); drop procedure test_01; drop procedure test_02; -drop procedure verify_vtq; + +-- source suite/versioning/common_finish.inc diff --git a/mysql-test/suite/versioning/t/update.test b/mysql-test/suite/versioning/t/update.test index 861e5dd66eb..bec4aef208c 100644 --- a/mysql-test/suite/versioning/t/update.test +++ b/mysql-test/suite/versioning/t/update.test @@ -263,4 +263,5 @@ drop procedure test_04; drop procedure test_05; drop procedure test_06; drop procedure test_07; -drop procedure verify_vtq; + +-- source suite/versioning/common_finish.inc -- cgit v1.2.1 From 352d83569b29725ded23202844079398b569fa46 Mon Sep 17 00:00:00 2001 From: kevg Date: Thu, 16 Mar 2017 18:35:36 +0300 Subject: SQL: versioning for tmp HEAP tables created from IB tables [closes #158] --- mysql-test/suite/versioning/r/view.result | 1 + sql/sql_select.cc | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/versioning/r/view.result b/mysql-test/suite/versioning/r/view.result index 104e2a557e8..258a2dcb92c 100644 --- a/mysql-test/suite/versioning/r/view.result +++ b/mysql-test/suite/versioning/r/view.result @@ -55,6 +55,7 @@ x prepare stmt from 'select * from vt1 for system_time as of timestamp @t1'; execute stmt; x +1 drop prepare stmt; create or replace view vt1 as select * from t1; select * from vt1 for system_time all; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1421a41a9f4..79bbe9c90d6 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -864,7 +864,14 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, } Item *cond1= 0, *cond2= 0, *curr= 0; - if (table->table->versioned_by_sql() || vers_simple_select) + // Temporary tables of type HEAP can be created from INNODB tables and + // thus will have uint64 type of sys_trx_(start|end) field. + // They need special handling. + TABLE *t= table->table; + if ((t->s->table_category == TABLE_CATEGORY_TEMPORARY + ? t->vers_start_field()->type() != MYSQL_TYPE_LONGLONG + : t->versioned_by_sql()) || + vers_simple_select) { switch (vers_conditions.type) { -- cgit v1.2.1 From 21e8b22f531face05c2007aa6d5a6ae6907c62e3 Mon Sep 17 00:00:00 2001 From: kevg Date: Tue, 21 Mar 2017 13:33:26 +0300 Subject: Misc: vers_select_conds_t::init_from_sysvar() --- sql/sql_select.cc | 43 +++++++++++++++++++++++++------------------ sql/table.h | 2 ++ 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 79bbe9c90d6..c91895ce056 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -668,6 +668,29 @@ setup_without_group(THD *thd, Ref_ptr_array ref_pointer_array, DBUG_RETURN(res); } +bool vers_select_conds_t::init_from_sysvar(THD *thd) +{ + const char var[]= "temporal_current_timestamp"; + sys_var *sv= intern_find_sys_var(var, sizeof(var) - 1); + DBUG_ASSERT(sv); + const char *data= *(char **)sv->option.value; + DBUG_ASSERT(data); + if (0 == strcmp(data, "all")) + { + init(FOR_SYSTEM_TIME_ALL, UNIT_TIMESTAMP); + } + else if (0 != strcmp(data, "now")) + { + Item *ts= + create_temporal_literal(thd, data, strlen(data), system_charset_info, + MYSQL_TYPE_DATETIME, true); + if (!ts) + return true; + init(FOR_SYSTEM_TIME_AS_OF, UNIT_TIMESTAMP, ts); + } + return false; +} + int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LEX *slex) { @@ -778,24 +801,8 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, if (vers_conditions.type == FOR_SYSTEM_TIME_UNSPECIFIED) { - const char var[]= "temporal_current_timestamp"; - sys_var *sv= intern_find_sys_var(var, sizeof(var) - 1); - DBUG_ASSERT(sv); - const char *data= *(char **)sv->option.value; - DBUG_ASSERT(data); - if (0 == strcmp(data, "all")) - { - vers_conditions.init(FOR_SYSTEM_TIME_ALL, UNIT_TIMESTAMP); - } - else if (0 != strcmp(data, "now")) - { - Item *ts= create_temporal_literal(thd, data, strlen(data), - system_charset_info, - MYSQL_TYPE_DATETIME, true); - if (!ts) - DBUG_RETURN(-1); - vers_conditions.init(FOR_SYSTEM_TIME_AS_OF, UNIT_TIMESTAMP, ts); - } + if (vers_conditions.init_from_sysvar(thd)) + DBUG_RETURN(-1); } if (vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED) diff --git a/sql/table.h b/sql/table.h index 12e5830089d..ba497f1c365 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1882,6 +1882,8 @@ struct vers_select_conds_t start= s; end= e; } + + bool init_from_sysvar(THD *thd); }; struct LEX; -- cgit v1.2.1 From e8ae9f1ae9e361c41148f32f9efbae49ccadff19 Mon Sep 17 00:00:00 2001 From: kevg Date: Thu, 23 Mar 2017 16:14:19 +0300 Subject: SQL: VIEW NATURAL JOIN TABLE [fixes #161] --- mysql-test/suite/versioning/r/select.result | 28 +++++++++++++++++++++++++++- mysql-test/suite/versioning/t/select.test | 14 +++++++++++++- sql/sql_base.cc | 9 +++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index 86a56fe05a0..167d1c8ff9a 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -390,8 +390,32 @@ a1 a2 2 1 1 2 2 2 +create or replace table t1(a1 int) with system versioning; +create or replace table t2(a2 int) with system versioning; +insert into t1 values(1),(2); +insert into t2 values(1),(2); +create or replace view v1 as select a1 from t1; +select * from v1 natural join t2; +a1 a2 +1 1 +2 1 +1 2 +2 2 +select * from v1 natural left join t2; +a1 a2 +1 1 +2 1 +1 2 +2 2 +select * from v1 natural right join t2; +a2 a1 +1 1 +2 1 +1 2 +2 2 +drop view v1; drop table t1, t2; -call innodb_verify_vtq(19); +call innodb_verify_vtq(21); No A B C D 1 1 1 1 1 2 1 1 1 1 @@ -412,6 +436,8 @@ No A B C D 17 1 1 1 1 18 1 1 1 1 19 1 1 1 1 +20 1 1 1 1 +21 1 1 1 1 drop procedure test_01; drop procedure test_02; drop procedure verify_vtq; diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index 115706f9130..35cbc068070 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -173,9 +173,21 @@ insert into t1 values(1),(2); insert into t2 values(1),(2); select * from t1 for system_time all natural left join t2 for system_time all; +# natural join of a view and table +create or replace table t1(a1 int) with system versioning; +create or replace table t2(a2 int) with system versioning; +insert into t1 values(1),(2); +insert into t2 values(1),(2); +create or replace view v1 as select a1 from t1; + +select * from v1 natural join t2; +select * from v1 natural left join t2; +select * from v1 natural right join t2; + +drop view v1; drop table t1, t2; -call innodb_verify_vtq(19); +call innodb_verify_vtq(21); drop procedure test_01; drop procedure test_02; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 14bc741057b..2ca2c9141f3 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -6383,6 +6383,15 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, if (nj_col_1->field() && nj_col_1->field()->vers_sys_field()) continue; + if (table_ref_1->is_view() && table_ref_1->table->versioned()) + { + Item *item= nj_col_1->view_field->item; + DBUG_ASSERT(item->type() == Item::FIELD_ITEM); + Item_field *item_field= (Item_field *)item; + if (item_field->field->vers_sys_field()) + continue; + } + field_name_1= nj_col_1->name(); is_using_column_1= using_fields && test_if_string_in_list(field_name_1, using_fields); -- cgit v1.2.1 From 14f007f907355baf1cb0d4a63bd3ab4f1e01398d Mon Sep 17 00:00:00 2001 From: kevg Date: Thu, 23 Mar 2017 23:19:22 +0300 Subject: SQL: versioning in embedded JOINs [fixes #160] --- mysql-test/suite/versioning/r/select.result | 18 +++++++++++++++++- mysql-test/suite/versioning/t/select.test | 8 +++++++- sql/sql_select.cc | 6 ++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index 167d1c8ff9a..34ce9e3976e 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -413,9 +413,22 @@ a2 a1 2 1 1 2 2 2 +create or replace table t1 (a int) with system versioning; +insert into t1 values (1); +insert into t1 values (2); +insert into t1 values (3); +select * from t1 left outer join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; +a a +2 1 +3 1 +2 2 +3 2 +2 3 +3 3 +1 NULL drop view v1; drop table t1, t2; -call innodb_verify_vtq(21); +call innodb_verify_vtq(24); No A B C D 1 1 1 1 1 2 1 1 1 1 @@ -438,6 +451,9 @@ No A B C D 19 1 1 1 1 20 1 1 1 1 21 1 1 1 1 +22 1 1 1 1 +23 1 1 1 1 +24 1 1 1 1 drop procedure test_01; drop procedure test_02; drop procedure verify_vtq; diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index 35cbc068070..fb086b0060d 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -184,10 +184,16 @@ select * from v1 natural join t2; select * from v1 natural left join t2; select * from v1 natural right join t2; +create or replace table t1 (a int) with system versioning; +insert into t1 values (1); +insert into t1 values (2); +insert into t1 values (3); +select * from t1 left outer join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; + drop view v1; drop table t1, t2; -call innodb_verify_vtq(21); +call innodb_verify_vtq(24); drop procedure test_01; drop procedure test_02; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c91895ce056..7658bb9e2d0 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -834,6 +834,12 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, dst_cond= &table->on_expr; } + if (TABLE_LIST *t= table->embedding) + { + if (t->on_expr) + dst_cond= &t->on_expr; + } + const char *fstart= table->table->vers_start_field()->field_name; const char *fend= table->table->vers_end_field()->field_name; -- cgit v1.2.1 From 7a525e7e93c651352ef869325b2c2337d4806125 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Fri, 24 Mar 2017 14:53:20 +0300 Subject: Parser: no implicit NOT NULL for system fields [fixes #163] --- mysql-test/suite/versioning/r/alter.result | 4 ++-- mysql-test/suite/versioning/r/create.result | 4 ++-- sql/field.cc | 2 ++ sql/field.h | 4 +++- sql/sql_yacc.yy | 20 ++++++++++++++++++-- 5 files changed, 27 insertions(+), 7 deletions(-) diff --git a/mysql-test/suite/versioning/r/alter.result b/mysql-test/suite/versioning/r/alter.result index 598aa6b98a8..13932ea1805 100644 --- a/mysql-test/suite/versioning/r/alter.result +++ b/mysql-test/suite/versioning/r/alter.result @@ -53,8 +53,8 @@ show create table t; Table Create Table t CREATE TABLE `t` ( `a` int(11) DEFAULT NULL, - `trx_start` timestamp(6) NOT NULL GENERATED ALWAYS AS ROW START, - `trx_end` timestamp(6) NOT NULL GENERATED ALWAYS AS ROW END, + `trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (`trx_start`, `trx_end`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING alter table t without system versioning; diff --git a/mysql-test/suite/versioning/r/create.result b/mysql-test/suite/versioning/r/create.result index ad27bc065c3..81c240297e3 100644 --- a/mysql-test/suite/versioning/r/create.result +++ b/mysql-test/suite/versioning/r/create.result @@ -9,8 +9,8 @@ show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `XNo` int(10) unsigned DEFAULT NULL, - `Sys_start` timestamp(6) NOT NULL GENERATED ALWAYS AS ROW START, - `Sys_end` timestamp(6) NOT NULL GENERATED ALWAYS AS ROW END, + `Sys_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `Sys_end` timestamp(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (`Sys_start`, `Sys_end`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING # Implicit fields test diff --git a/sql/field.cc b/sql/field.cc index 3c34d973bf5..3a1fee59937 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -10630,6 +10630,8 @@ Column_definition::Column_definition(THD *thd, Field *old_field, check_constraint= orig_field ? orig_field->check_constraint : 0; option_list= old_field->option_list; pack_flag= 0; + versioning= VERSIONING_NOT_SET; + implicit_not_null= false; switch (sql_type) { case MYSQL_TYPE_BLOB: diff --git a/sql/field.h b/sql/field.h index e955323b917..317ae018066 100644 --- a/sql/field.h +++ b/sql/field.h @@ -3871,6 +3871,7 @@ public: *check_constraint; // Check constraint enum_column_versioning versioning; + bool implicit_not_null; Column_definition(): comment(null_lex_str), @@ -3880,7 +3881,8 @@ public: srid(0), geom_type(Field::GEOM_GEOMETRY), option_list(NULL), pack_flag(0), vcol_info(0), default_value(0), check_constraint(0), - versioning(VERSIONING_NOT_SET) + versioning(VERSIONING_NOT_SET), + implicit_not_null(false) { interval_list.empty(); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 7a17b90a191..5eab752df3f 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -6305,6 +6305,11 @@ field_def: my_yyabort_error((ER_VERS_WRONG_PARAMS, MYF(0), table_name, err)); } *p= field_name; + if (lex->last_field->implicit_not_null) + { + lex->last_field->flags&= ~NOT_NULL_FLAG; + lex->last_field->implicit_not_null= false; + } } ; @@ -6517,7 +6522,10 @@ field_type: Unless --explicit-defaults-for-timestamp is given. */ if (!opt_explicit_defaults_for_timestamp) + { Lex->last_field->flags|= NOT_NULL_FLAG; + Lex->last_field->implicit_not_null= true; + } $$.set(opt_mysql56_temporal_format ? MYSQL_TYPE_TIMESTAMP2 : MYSQL_TYPE_TIMESTAMP, $2); } @@ -6704,7 +6712,11 @@ opt_attribute_list: ; attribute: - NULL_SYM { Lex->last_field->flags&= ~ NOT_NULL_FLAG; } + NULL_SYM + { + Lex->last_field->flags&= ~ NOT_NULL_FLAG; + Lex->last_field->implicit_not_null= false; + } | DEFAULT column_default_expr { Lex->last_field->default_value= $2; } | ON UPDATE_SYM NOW_SYM opt_default_time_precision { @@ -6731,7 +6743,11 @@ attribute: ; serial_attribute: - not NULL_SYM { Lex->last_field->flags|= NOT_NULL_FLAG; } + not NULL_SYM + { + Lex->last_field->flags|= NOT_NULL_FLAG; + Lex->last_field->implicit_not_null= false; + } | opt_primary KEY_SYM { LEX *lex=Lex; -- cgit v1.2.1 From 67cd92b6f47b6f229fbdf62812ff805f38a03750 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Fri, 24 Mar 2017 16:00:42 +0300 Subject: SQL, IB: Copy history via CREATE .. SELECT [closes #157, #152] --- mysql-test/suite/versioning/common.opt | 1 + mysql-test/suite/versioning/r/create.result | 283 ++++++++++++++------- mysql-test/suite/versioning/r/sysvars.result | 88 +++++++ mysql-test/suite/versioning/r/variables.result | 38 --- mysql-test/suite/versioning/t/create.combinations | 5 + mysql-test/suite/versioning/t/create.test | 189 +++++++++----- mysql-test/suite/versioning/t/derived_tables.opt | 1 + mysql-test/suite/versioning/t/foreign.opt | 1 + mysql-test/suite/versioning/t/partition.opt | 1 + mysql-test/suite/versioning/t/rpl_test.opt | 1 + mysql-test/suite/versioning/t/sysvars.opt | 1 + mysql-test/suite/versioning/t/sysvars.test | 62 +++++ mysql-test/suite/versioning/t/truncate_history.opt | 1 + mysql-test/suite/versioning/t/variables.test | 28 -- mysql-test/suite/versioning/t/view.opt | 1 + plugin/versioning/versioning.cc | 4 +- sql/handler.cc | 102 +++++++- sql/handler.h | 5 +- sql/mysqld.cc | 2 +- sql/mysqld.h | 8 +- sql/sql_base.cc | 21 +- sql/sql_insert.cc | 6 + sql/sql_parse.cc | 12 +- sql/sql_select.cc | 7 +- sql/sql_show.cc | 6 +- sql/sys_vars.cc | 11 +- sql/table.cc | 4 +- storage/innobase/handler/ha_innodb.cc | 5 +- storage/innobase/row/row0mysql.cc | 2 +- 29 files changed, 628 insertions(+), 268 deletions(-) create mode 100644 mysql-test/suite/versioning/r/sysvars.result delete mode 100644 mysql-test/suite/versioning/r/variables.result create mode 100644 mysql-test/suite/versioning/t/create.combinations create mode 100644 mysql-test/suite/versioning/t/derived_tables.opt create mode 100644 mysql-test/suite/versioning/t/foreign.opt create mode 100644 mysql-test/suite/versioning/t/partition.opt create mode 100644 mysql-test/suite/versioning/t/rpl_test.opt create mode 100644 mysql-test/suite/versioning/t/sysvars.opt create mode 100644 mysql-test/suite/versioning/t/sysvars.test create mode 100644 mysql-test/suite/versioning/t/truncate_history.opt delete mode 100644 mysql-test/suite/versioning/t/variables.test create mode 100644 mysql-test/suite/versioning/t/view.opt diff --git a/mysql-test/suite/versioning/common.opt b/mysql-test/suite/versioning/common.opt index c108024a0bd..cc66825a3df 100644 --- a/mysql-test/suite/versioning/common.opt +++ b/mysql-test/suite/versioning/common.opt @@ -15,3 +15,4 @@ --innodb-sys-tables --innodb-sys-virtual --innodb-vtq +--vers-hide=implicit diff --git a/mysql-test/suite/versioning/r/create.result b/mysql-test/suite/versioning/r/create.result index 81c240297e3..ef78a693268 100644 --- a/mysql-test/suite/versioning/r/create.result +++ b/mysql-test/suite/versioning/r/create.result @@ -1,226 +1,281 @@ +set @@session.time_zone='+00:00'; +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +create procedure if not exists verify_vtq() +begin +set @i= 0; +select +@i:= @i + 1 as No, +trx_id > 0 as A, +commit_id >= trx_id as B, +begin_ts > '1-1-1 0:0:0' as C, +commit_ts > begin_ts as D +from information_schema.innodb_vtq +where trx_id > @start_trx_id; +select ifnull(max(trx_id), 0) +into @start_trx_id +from information_schema.innodb_vtq; +end~~ +create function if not exists default_engine() +returns varchar(255) +deterministic +begin +declare e varchar(255); +select lower(engine) from information_schema.engines where support='DEFAULT' into e; +return e; +end~~ +create function if not exists sys_datatype() +returns varchar(255) +deterministic +begin +if default_engine() = 'innodb' then +return 'bigint unsigned'; +elseif default_engine() = 'myisam' then +return 'timestamp(6)'; +end if; +return NULL; +end~~ +create function if not exists sys_commit_ts(sys_field varchar(255)) +returns varchar(255) +deterministic +begin +if default_engine() = 'innodb' then +return concat('vtq_commit_ts(', sys_field, ')'); +elseif default_engine() = 'myisam' then +return sys_field; +end if; +return NULL; +end~~ +create procedure if not exists innodb_verify_vtq(recs int) +begin +declare i int default 1; +if default_engine() = 'innodb' then +call verify_vtq; +elseif default_engine() = 'myisam' then +create temporary table tmp (No int, A bool, B bool, C bool, D bool); +while i <= recs do +insert into tmp values (i, 1, 1, 1, 1); +set i= i + 1; +end while; +select * from tmp; +drop table tmp; +end if; +end~~ drop table if exists t1; create table t1 ( -XNo int unsigned, -Sys_start timestamp(6) generated always as row start, -Sys_end timestamp(6) generated always as row end, +x1 int unsigned, +Sys_start SYS_TRX_TYPE generated always as row start, +Sys_end SYS_TRX_TYPE generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `XNo` int(10) unsigned DEFAULT NULL, - `Sys_start` timestamp(6) GENERATED ALWAYS AS ROW START, - `Sys_end` timestamp(6) GENERATED ALWAYS AS ROW END, + `x1` int(10) unsigned DEFAULT NULL, + `Sys_start` SYS_TRX_TYPE GENERATED ALWAYS AS ROW START, + `Sys_end` SYS_TRX_TYPE GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (`Sys_start`, `Sys_end`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +) ENGINE=INNODB_OR_MYISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING # Implicit fields test create or replace table t1 ( -XNo int unsigned +x2 int unsigned ) with system versioning; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `XNo` int(10) unsigned DEFAULT NULL, - `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, - `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + `x2` int(10) unsigned DEFAULT NULL, + `sys_trx_start` SYS_TRX_TYPE GENERATED ALWAYS AS ROW START, + `sys_trx_end` SYS_TRX_TYPE GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +) ENGINE=INNODB_OR_MYISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING create or replace table t1 ( -XNo int unsigned, -Sys_start timestamp(6) generated always as row start, -Sys_start2 timestamp(6) generated always as row start, -Sys_end timestamp(6) generated always as row end, +x3 int unsigned, +Sys_start SYS_TRX_TYPE generated always as row start, +Sys_start2 SYS_TRX_TYPE generated always as row start, +Sys_end SYS_TRX_TYPE generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning; ERROR HY000: Wrong parameters for `t1`: multiple 'GENERATED ALWAYS AS ROW START' create or replace table t1 ( -XNo int unsigned, -Sys_start timestamp(6) generated always as row start, -Sys_end2 timestamp(6) generated always as row end, +x4 int unsigned, +Sys_start SYS_TRX_TYPE generated always as row start, +Sys_end2 SYS_TRX_TYPE generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning; ERROR HY000: Wrong parameters for `t1`: 'PERIOD FOR SYSTEM_TIME' and 'GENERATED AS ROW END' mismatch create or replace table t1 ( -XNo int unsigned, -Sys_start timestamp(6) generated always as row start, -Sys_end timestamp(6) generated always as row end, -Sys_end2 timestamp(6) generated always as row end, +x5 int unsigned, +Sys_start SYS_TRX_TYPE generated always as row start, +Sys_end SYS_TRX_TYPE generated always as row end, +Sys_end2 SYS_TRX_TYPE generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning; ERROR HY000: Wrong parameters for `t1`: multiple 'GENERATED ALWAYS AS ROW END' create or replace table t1 ( -XNo int unsigned, +x6 int unsigned, period for system_time (Sys_start, Sys_end) ) with system versioning; ERROR HY000: Wrong parameters for `t1`: 'GENERATED AS ROW START' column missing create or replace table t1 ( -XNo int unsigned, -Sys_start timestamp(6) generated always as row start, -Sys_end timestamp(6) generated always as row end, -Sys_end2 timestamp(6) generated always as row end, +x7 int unsigned, +Sys_start SYS_TRX_TYPE generated always as row start, +Sys_end SYS_TRX_TYPE generated always as row end, +Sys_end2 SYS_TRX_TYPE generated always as row end, period for system_time (Sys_start, Sys_end) ); ERROR HY000: Wrong parameters for `t1`: multiple 'GENERATED ALWAYS AS ROW END' create or replace table t1 ( -XNo int unsigned, -Sys_start timestamp(6) generated always as row start, -Sys_end timestamp(6) generated always as row end, +x8 int unsigned, +Sys_start SYS_TRX_TYPE generated always as row start, +Sys_end SYS_TRX_TYPE generated always as row end, period for system_time (sys_insert, sys_remove) ) with system versioning; ERROR HY000: Wrong parameters for `t1`: 'PERIOD FOR SYSTEM_TIME' and 'GENERATED AS ROW START' mismatch create or replace table t1 ( -XNo int unsigned, -Sys_start timestamp(6) generated always as row start, -Sys_end timestamp(6) generated always as row end, +x9 int unsigned, +Sys_start SYS_TRX_TYPE generated always as row start, +Sys_end SYS_TRX_TYPE generated always as row end, period for system_time (Sys_start, Sys_end) ); ERROR HY000: Wrong parameters for `t1`: 'WITH SYSTEM VERSIONING' missing create or replace table t1 ( -XNo int unsigned, -Sys_start timestamp(6) generated always as row start, -Sys_end timestamp(6) generated always as row end, +x10 int unsigned, +Sys_start SYS_TRX_TYPE generated always as row start, +Sys_end SYS_TRX_TYPE generated always as row end, period for system_time (Sys_start, Sys_start) ); ERROR HY000: Wrong parameters for `t1`: 'PERIOD FOR SYSTEM_TIME' columns must be different create or replace table t1 ( -XNo int unsigned, -Sys_start int generated always as row start, +x11 int unsigned, +Sys_start bigint unsigned generated always as row start, Sys_end timestamp(6) generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning; -ERROR HY000: `Sys_start` must be of type `TIMESTAMP(6)` for versioned table `t1` +Got one of the listed errors create or replace table t1 ( -XNo int unsigned, +x12 int unsigned, Sys_start timestamp(6) generated always as row start, -Sys_end int generated always as row end, +Sys_end bigint unsigned generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning; -ERROR HY000: `Sys_end` must be of type `TIMESTAMP(6)` for versioned table `t1` +Got one of the listed errors create or replace table t1 ( -XNo int unsigned, -Sys_start timestamp(6) generated always as row start, -Sys_end bigint generated always as row end, -period for system_time (Sys_start, Sys_end) -) with system versioning engine innodb; -ERROR HY000: `Sys_start` must be of type `BIGINT(20) UNSIGNED` for versioned table `t1` -create or replace table t1 ( -XNo int unsigned, +x13 int unsigned, Sys_start bigint generated always as row start, -Sys_end bigint generated always as row end, +Sys_end bigint unsigned generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning engine innodb; ERROR HY000: `Sys_start` must be of type `BIGINT(20) UNSIGNED` for versioned table `t1` create or replace table t1 ( -XNo int unsigned, +x14 int unsigned, Sys_start bigint unsigned generated always as row start, Sys_end bigint generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning engine innodb; ERROR HY000: `Sys_end` must be of type `BIGINT(20) UNSIGNED` for versioned table `t1` create or replace table t1 ( -A int with system versioning, +A1 int with system versioning, B int ); show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `A` int(11) DEFAULT NULL, + `A1` int(11) DEFAULT NULL, `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, - `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, - `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + `sys_trx_start` SYS_TRX_TYPE GENERATED ALWAYS AS ROW START, + `sys_trx_end` SYS_TRX_TYPE GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +) ENGINE=INNODB_OR_MYISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING create or replace table t1 ( -A int with system versioning, +A2 int with system versioning, B int ) with system versioning; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `A` int(11) DEFAULT NULL, + `A2` int(11) DEFAULT NULL, `B` int(11) DEFAULT NULL, - `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, - `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + `sys_trx_start` SYS_TRX_TYPE GENERATED ALWAYS AS ROW START, + `sys_trx_end` SYS_TRX_TYPE GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +) ENGINE=INNODB_OR_MYISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING create or replace table t1 ( -A int, +A3 int, B int without system versioning ); ERROR HY000: Wrong parameters for `t1`: 'WITH SYSTEM VERSIONING' missing create or replace table t1 ( -A int, +A4 int, B int without system versioning ) with system versioning; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `A` int(11) DEFAULT NULL, + `A4` int(11) DEFAULT NULL, `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, - `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, - `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + `sys_trx_start` SYS_TRX_TYPE GENERATED ALWAYS AS ROW START, + `sys_trx_end` SYS_TRX_TYPE GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +) ENGINE=INNODB_OR_MYISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING create or replace table t1 ( -A int with system versioning, +A5 int with system versioning, B int without system versioning ); show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `A` int(11) DEFAULT NULL, + `A5` int(11) DEFAULT NULL, `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, - `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, - `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + `sys_trx_start` SYS_TRX_TYPE GENERATED ALWAYS AS ROW START, + `sys_trx_end` SYS_TRX_TYPE GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +) ENGINE=INNODB_OR_MYISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING create or replace table t1 ( -A int with system versioning, +A6 int with system versioning, B int without system versioning ) with system versioning; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `A` int(11) DEFAULT NULL, + `A6` int(11) DEFAULT NULL, `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, - `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, - `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + `sys_trx_start` SYS_TRX_TYPE GENERATED ALWAYS AS ROW START, + `sys_trx_end` SYS_TRX_TYPE GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +) ENGINE=INNODB_OR_MYISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING create or replace table t1 ( -A int without system versioning +A7 int without system versioning ); ERROR HY000: Wrong parameters for `t1`: 'WITH SYSTEM VERSIONING' missing create or replace table t1 ( -A int without system versioning +A8 int without system versioning ) with system versioning; -ERROR HY000: Wrong parameters for `t1`: versioned fields missing +ERROR HY000: Wrong parameters for `t1`: no columns defined with system versioning! create or replace table t1 ( -A int without system versioning with system versioning +A9 int without system versioning with system versioning ); ERROR HY000: Wrong parameters for `t1`: Versioning specified more than once for the same field create or replace table t1 ( -A int with system versioning without system versioning +A10 int with system versioning without system versioning ); ERROR HY000: Wrong parameters for `t1`: Versioning specified more than once for the same field create table t( -a int +a11 int ) without system versioning; ERROR HY000: Wrong parameters for `t`: 'WITHOUT SYSTEM VERSIONING' is not allowed create or replace table t1 ( -A int +A12 int ) without system versioning with system versioning; ERROR HY000: Wrong parameters for `t1`: Versioning specified more than once for the same table create or replace table t1 ( -A int +A13 int ) with system versioning without system versioning; ERROR HY000: Wrong parameters for `t1`: Versioning specified more than once for the same table create or replace table t1 ( -A int +A14 int ) with system versioning with system versioning; ERROR HY000: Wrong parameters for `t1`: Versioning specified more than once for the same table create or replace table t1 ( -A int +A15 int ) without system versioning without system versioning; ERROR HY000: Wrong parameters for `t1`: Versioning specified more than once for the same table create or replace table t1 (a int) with system versioning; @@ -231,9 +286,53 @@ show create table tt1; Table Create Table tt1 CREATE TABLE `tt1` ( `a` int(11) DEFAULT NULL, - `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, - `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + `sys_trx_start` SYS_TRX_TYPE GENERATED ALWAYS AS ROW START, + `sys_trx_end` SYS_TRX_TYPE GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +) ENGINE=INNODB_OR_MYISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING drop table tt1; +create or replace table t1 (x int) with system versioning; +create or replace table t2 (y int); +create or replace table t3 select * from t1 for system_time all, t2; +show create table t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `x` int(11) DEFAULT NULL, + `y` int(11) DEFAULT NULL +) ENGINE=INNODB_OR_MYISAM DEFAULT CHARSET=latin1 +create or replace table t2 ( +y int, +st SYS_TRX_TYPE generated always as row start, +en SYS_TRX_TYPE generated always as row end, +period for system_time (st, en) +) with system versioning; +create or replace table t3 select * from t2; +show create table t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `y` int(11) DEFAULT NULL, + `st` SYS_TRX_TYPE GENERATED ALWAYS AS ROW START, + `en` SYS_TRX_TYPE GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (`st`, `en`) +) ENGINE=INNODB_OR_MYISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +create or replace table t3 select x, y, t1.sys_trx_start, t2.en from t1, t2; +ERROR HY000: Wrong parameters for `t3`: system fields selected from different tables +insert into t2 values (1), (2); +delete from t2 where y = 2; +create or replace table t3 select * from t2 for system_time all; +select st, en from t2 where y = 1 into @st, @en; +select y from t2 for system_time all where st = @st and en = @en; +y +1 +select st, en from t2 for system_time all where y = 2 into @st, @en; +select y from t2 for system_time all where st = @st and en = @en; +y +2 drop table t1; +drop table t2; +drop table t3; +drop procedure verify_vtq; +drop procedure innodb_verify_vtq; +drop function default_engine; +drop function sys_commit_ts; +drop function sys_datatype; diff --git a/mysql-test/suite/versioning/r/sysvars.result b/mysql-test/suite/versioning/r/sysvars.result new file mode 100644 index 00000000000..120a3583754 --- /dev/null +++ b/mysql-test/suite/versioning/r/sysvars.result @@ -0,0 +1,88 @@ +create table t (a int) with system versioning; +insert into t values (1); +update t set a= 2; +select * from t; +a +2 +show variables where variable_name = "temporal_current_timestamp"; +Variable_name Value +temporal_current_timestamp now +set global temporal_current_timestamp = '2031-1-1 0:0:0'; +select * from t; +a +2 +set global temporal_current_timestamp = '2011-1-1 0:0:0'; +select * from t; +a +set global temporal_current_timestamp = 'all'; +select * from t; +a +2 +1 +show variables where Variable_name like "temporal_current_timestamp%"; +Variable_name Value +temporal_current_timestamp all +create view vt as select * from t; +select * from t; +a +2 +1 +drop view vt; +select * from (select * from t) as tt; +a +2 +1 +set session temporal_current_timestamp = 'now'; +ERROR HY000: Variable 'temporal_current_timestamp' is a GLOBAL variable and should be set with SET GLOBAL +set global temporal_current_timestamp = 'now'; +show variables where variable_name = "vers_hide"; +Variable_name Value +vers_hide IMPLICIT +select * from t for system_time all; +a +2 +1 +set global vers_hide= AUTO; +select * from t; +a +2 +select * from t for system_time as of timestamp current_timestamp(6); +a +2 +select * from t for system_time all; +a sys_trx_start sys_trx_end +2 TIMESTAMP TIMESTAMP +1 TIMESTAMP TIMESTAMP +select * from t for system_time timestamp from '0-0-0' to current_timestamp(6); +a sys_trx_start sys_trx_end +2 TIMESTAMP TIMESTAMP +1 TIMESTAMP TIMESTAMP +select * from t for system_time timestamp between '0-0-0' and current_timestamp(6); +a sys_trx_start sys_trx_end +2 TIMESTAMP TIMESTAMP +1 TIMESTAMP TIMESTAMP +set global vers_hide= NEVER; +select * from t; +a sys_trx_start sys_trx_end +2 TIMESTAMP TIMESTAMP +set global vers_hide= FULL; +create or replace table t ( +x int, +st timestamp(6) generated always as row start, +en timestamp(6) generated always as row end, +period for system_time (st, en)) +with system versioning; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `x` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +insert into t values (1); +delete from t; +select * from t; +x +select * from t for system_time all; +x +1 +drop table t; +set global vers_hide= IMPLICIT; diff --git a/mysql-test/suite/versioning/r/variables.result b/mysql-test/suite/versioning/r/variables.result deleted file mode 100644 index c0d15cbf1e8..00000000000 --- a/mysql-test/suite/versioning/r/variables.result +++ /dev/null @@ -1,38 +0,0 @@ -create table t (a int) with system versioning; -insert into t values (1); -update t set a=2; -select * from t; -a -2 -show variables where Variable_name like "temporal_current_timestamp%"; -Variable_name Value -temporal_current_timestamp now -set global temporal_current_timestamp = '2031-1-1 0:0:0'; -select * from t; -a -2 -set global temporal_current_timestamp = '2011-1-1 0:0:0'; -select * from t; -a -set global temporal_current_timestamp = 'all'; -select * from t; -a -2 -1 -show variables where Variable_name like "temporal_current_timestamp%"; -Variable_name Value -temporal_current_timestamp all -create view vt as select * from t; -select * from t; -a -2 -1 -drop view vt; -select * from (select * from t) as tt; -a -2 -1 -set session temporal_current_timestamp = 'now'; -ERROR HY000: Variable 'temporal_current_timestamp' is a GLOBAL variable and should be set with SET GLOBAL -drop table t; -set global temporal_current_timestamp = 'now'; diff --git a/mysql-test/suite/versioning/t/create.combinations b/mysql-test/suite/versioning/t/create.combinations new file mode 100644 index 00000000000..75fb20d9f5e --- /dev/null +++ b/mysql-test/suite/versioning/t/create.combinations @@ -0,0 +1,5 @@ +[innodb] +default-storage-engine=innodb + +[myisam] +default-storage-engine=myisam diff --git a/mysql-test/suite/versioning/t/create.test b/mysql-test/suite/versioning/t/create.test index 99f7105fc38..ba860365dc1 100644 --- a/mysql-test/suite/versioning/t/create.test +++ b/mysql-test/suite/versioning/t/create.test @@ -1,215 +1,264 @@ --- source include/have_innodb.inc +-- source suite/versioning/common.inc --disable_warnings drop table if exists t1; --enable_warnings -create table t1 ( - XNo int unsigned, - Sys_start timestamp(6) generated always as row start, - Sys_end timestamp(6) generated always as row end, +--let $sys_datatype= `select sys_datatype()` + +--replace_result "bigint unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE +eval create table t1 ( + x1 int unsigned, + Sys_start $sys_datatype generated always as row start, + Sys_end $sys_datatype generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning; +--replace_result InnoDB INNODB_OR_MYISAM MyISAM INNODB_OR_MYISAM "bigint(20) unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE show create table t1; --echo # Implicit fields test create or replace table t1 ( - XNo int unsigned + x2 int unsigned ) with system versioning; +--replace_result InnoDB INNODB_OR_MYISAM MyISAM INNODB_OR_MYISAM "bigint(20) unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE show create table t1; +--replace_result "bigint unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE --error ER_VERS_WRONG_PARAMS -create or replace table t1 ( - XNo int unsigned, - Sys_start timestamp(6) generated always as row start, - Sys_start2 timestamp(6) generated always as row start, - Sys_end timestamp(6) generated always as row end, +eval create or replace table t1 ( + x3 int unsigned, + Sys_start $sys_datatype generated always as row start, + Sys_start2 $sys_datatype generated always as row start, + Sys_end $sys_datatype generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning; +--replace_result "bigint unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE --error ER_VERS_WRONG_PARAMS -create or replace table t1 ( - XNo int unsigned, - Sys_start timestamp(6) generated always as row start, - Sys_end2 timestamp(6) generated always as row end, +eval create or replace table t1 ( + x4 int unsigned, + Sys_start $sys_datatype generated always as row start, + Sys_end2 $sys_datatype generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning; +--replace_result "bigint unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE --error ER_VERS_WRONG_PARAMS -create or replace table t1 ( - XNo int unsigned, - Sys_start timestamp(6) generated always as row start, - Sys_end timestamp(6) generated always as row end, - Sys_end2 timestamp(6) generated always as row end, +eval create or replace table t1 ( + x5 int unsigned, + Sys_start $sys_datatype generated always as row start, + Sys_end $sys_datatype generated always as row end, + Sys_end2 $sys_datatype generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning; --error ER_VERS_WRONG_PARAMS create or replace table t1 ( - XNo int unsigned, + x6 int unsigned, period for system_time (Sys_start, Sys_end) ) with system versioning; +--replace_result "bigint unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE --error ER_VERS_WRONG_PARAMS -create or replace table t1 ( - XNo int unsigned, - Sys_start timestamp(6) generated always as row start, - Sys_end timestamp(6) generated always as row end, - Sys_end2 timestamp(6) generated always as row end, +eval create or replace table t1 ( + x7 int unsigned, + Sys_start $sys_datatype generated always as row start, + Sys_end $sys_datatype generated always as row end, + Sys_end2 $sys_datatype generated always as row end, period for system_time (Sys_start, Sys_end) ); +--replace_result "bigint unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE --error ER_VERS_WRONG_PARAMS -create or replace table t1 ( - XNo int unsigned, - Sys_start timestamp(6) generated always as row start, - Sys_end timestamp(6) generated always as row end, +eval create or replace table t1 ( + x8 int unsigned, + Sys_start $sys_datatype generated always as row start, + Sys_end $sys_datatype generated always as row end, period for system_time (sys_insert, sys_remove) ) with system versioning; +--replace_result "bigint unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE --error ER_VERS_WRONG_PARAMS -create or replace table t1 ( - XNo int unsigned, - Sys_start timestamp(6) generated always as row start, - Sys_end timestamp(6) generated always as row end, +eval create or replace table t1 ( + x9 int unsigned, + Sys_start $sys_datatype generated always as row start, + Sys_end $sys_datatype generated always as row end, period for system_time (Sys_start, Sys_end) ); +--replace_result "bigint unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE --error ER_VERS_WRONG_PARAMS -create or replace table t1 ( - XNo int unsigned, - Sys_start timestamp(6) generated always as row start, - Sys_end timestamp(6) generated always as row end, +eval create or replace table t1 ( + x10 int unsigned, + Sys_start $sys_datatype generated always as row start, + Sys_end $sys_datatype generated always as row end, period for system_time (Sys_start, Sys_start) ); ---error ER_VERS_FIELD_WRONG_TYPE +--error ER_VERS_FIELD_WRONG_TYPE, ER_VERS_FIELD_WRONG_TYPE create or replace table t1 ( - XNo int unsigned, - Sys_start int generated always as row start, + x11 int unsigned, + Sys_start bigint unsigned generated always as row start, Sys_end timestamp(6) generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning; ---error ER_VERS_FIELD_WRONG_TYPE +--error ER_VERS_FIELD_WRONG_TYPE, ER_VERS_FIELD_WRONG_TYPE create or replace table t1 ( - XNo int unsigned, + x12 int unsigned, Sys_start timestamp(6) generated always as row start, - Sys_end int generated always as row end, + Sys_end bigint unsigned generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning; --error ER_VERS_FIELD_WRONG_TYPE create or replace table t1 ( - XNo int unsigned, - Sys_start timestamp(6) generated always as row start, - Sys_end bigint generated always as row end, - period for system_time (Sys_start, Sys_end) -) with system versioning engine innodb; - ---error ER_VERS_FIELD_WRONG_TYPE -create or replace table t1 ( - XNo int unsigned, + x13 int unsigned, Sys_start bigint generated always as row start, - Sys_end bigint generated always as row end, + Sys_end bigint unsigned generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning engine innodb; --error ER_VERS_FIELD_WRONG_TYPE create or replace table t1 ( - XNo int unsigned, + x14 int unsigned, Sys_start bigint unsigned generated always as row start, Sys_end bigint generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning engine innodb; +# columns with/without system versioning + create or replace table t1 ( - A int with system versioning, + A1 int with system versioning, B int ); +--replace_result InnoDB INNODB_OR_MYISAM MyISAM INNODB_OR_MYISAM "bigint(20) unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE show create table t1; create or replace table t1 ( - A int with system versioning, + A2 int with system versioning, B int ) with system versioning; +--replace_result InnoDB INNODB_OR_MYISAM MyISAM INNODB_OR_MYISAM "bigint(20) unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE show create table t1; --error ER_VERS_WRONG_PARAMS create or replace table t1 ( - A int, + A3 int, B int without system versioning ); create or replace table t1 ( - A int, + A4 int, B int without system versioning ) with system versioning; +--replace_result InnoDB INNODB_OR_MYISAM MyISAM INNODB_OR_MYISAM "bigint(20) unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE show create table t1; create or replace table t1 ( - A int with system versioning, + A5 int with system versioning, B int without system versioning ); +--replace_result InnoDB INNODB_OR_MYISAM MyISAM INNODB_OR_MYISAM "bigint(20) unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE show create table t1; create or replace table t1 ( - A int with system versioning, + A6 int with system versioning, B int without system versioning ) with system versioning; +--replace_result InnoDB INNODB_OR_MYISAM MyISAM INNODB_OR_MYISAM "bigint(20) unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE show create table t1; --error ER_VERS_WRONG_PARAMS create or replace table t1 ( - A int without system versioning + A7 int without system versioning ); --error ER_VERS_WRONG_PARAMS create or replace table t1 ( - A int without system versioning + A8 int without system versioning ) with system versioning; --error ER_VERS_WRONG_PARAMS create or replace table t1 ( - A int without system versioning with system versioning + A9 int without system versioning with system versioning ); --error ER_VERS_WRONG_PARAMS create or replace table t1 ( - A int with system versioning without system versioning + A10 int with system versioning without system versioning ); +# table with/without system versioning + --error ER_VERS_WRONG_PARAMS create table t( - a int + a11 int ) without system versioning; --error ER_VERS_WRONG_PARAMS create or replace table t1 ( - A int + A12 int ) without system versioning with system versioning; --error ER_VERS_WRONG_PARAMS create or replace table t1 ( - A int + A13 int ) with system versioning without system versioning; --error ER_VERS_WRONG_PARAMS create or replace table t1 ( - A int + A14 int ) with system versioning with system versioning; --error ER_VERS_WRONG_PARAMS create or replace table t1 ( - A int + A15 int ) without system versioning without system versioning; create or replace table t1 (a int) with system versioning; create temporary table tmp with system versioning select * from t1; +# CREATE TABLE ... LIKE create or replace table t1 (a int) with system versioning; create table tt1 like t1; +--replace_result InnoDB INNODB_OR_MYISAM MyISAM INNODB_OR_MYISAM "bigint(20) unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE show create table tt1; drop table tt1; +# CREATE TABLE ... SELECT +create or replace table t1 (x int) with system versioning; +create or replace table t2 (y int); +create or replace table t3 select * from t1 for system_time all, t2; +--replace_result InnoDB INNODB_OR_MYISAM MyISAM INNODB_OR_MYISAM "bigint(20) unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE +show create table t3; + +--replace_result "bigint unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE +eval create or replace table t2 ( + y int, + st $sys_datatype generated always as row start, + en $sys_datatype generated always as row end, + period for system_time (st, en) +) with system versioning; +create or replace table t3 select * from t2; +--replace_result InnoDB INNODB_OR_MYISAM MyISAM INNODB_OR_MYISAM "bigint(20) unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE +show create table t3; + +--error ER_VERS_WRONG_PARAMS +create or replace table t3 select x, y, t1.sys_trx_start, t2.en from t1, t2; + +insert into t2 values (1), (2); +delete from t2 where y = 2; + +create or replace table t3 select * from t2 for system_time all; +select st, en from t2 where y = 1 into @st, @en; +select y from t2 for system_time all where st = @st and en = @en; +select st, en from t2 for system_time all where y = 2 into @st, @en; +select y from t2 for system_time all where st = @st and en = @en; + drop table t1; +drop table t2; +drop table t3; + +-- source suite/versioning/common_finish.inc diff --git a/mysql-test/suite/versioning/t/derived_tables.opt b/mysql-test/suite/versioning/t/derived_tables.opt new file mode 100644 index 00000000000..61ababdf408 --- /dev/null +++ b/mysql-test/suite/versioning/t/derived_tables.opt @@ -0,0 +1 @@ +--vers-hide=implicit diff --git a/mysql-test/suite/versioning/t/foreign.opt b/mysql-test/suite/versioning/t/foreign.opt new file mode 100644 index 00000000000..61ababdf408 --- /dev/null +++ b/mysql-test/suite/versioning/t/foreign.opt @@ -0,0 +1 @@ +--vers-hide=implicit diff --git a/mysql-test/suite/versioning/t/partition.opt b/mysql-test/suite/versioning/t/partition.opt new file mode 100644 index 00000000000..61ababdf408 --- /dev/null +++ b/mysql-test/suite/versioning/t/partition.opt @@ -0,0 +1 @@ +--vers-hide=implicit diff --git a/mysql-test/suite/versioning/t/rpl_test.opt b/mysql-test/suite/versioning/t/rpl_test.opt new file mode 100644 index 00000000000..61ababdf408 --- /dev/null +++ b/mysql-test/suite/versioning/t/rpl_test.opt @@ -0,0 +1 @@ +--vers-hide=implicit diff --git a/mysql-test/suite/versioning/t/sysvars.opt b/mysql-test/suite/versioning/t/sysvars.opt new file mode 100644 index 00000000000..61ababdf408 --- /dev/null +++ b/mysql-test/suite/versioning/t/sysvars.opt @@ -0,0 +1 @@ +--vers-hide=implicit diff --git a/mysql-test/suite/versioning/t/sysvars.test b/mysql-test/suite/versioning/t/sysvars.test new file mode 100644 index 00000000000..ba985a92c9a --- /dev/null +++ b/mysql-test/suite/versioning/t/sysvars.test @@ -0,0 +1,62 @@ +create table t (a int) with system versioning; +insert into t values (1); +update t set a= 2; + +select * from t; +show variables where variable_name = "temporal_current_timestamp"; + +set global temporal_current_timestamp = '2031-1-1 0:0:0'; +select * from t; + +set global temporal_current_timestamp = '2011-1-1 0:0:0'; +select * from t; + +set global temporal_current_timestamp = 'all'; +select * from t; +show variables where Variable_name like "temporal_current_timestamp%"; + +create view vt as select * from t; +select * from t; +drop view vt; + +select * from (select * from t) as tt; + +--error ER_GLOBAL_VARIABLE +set session temporal_current_timestamp = 'now'; + +set global temporal_current_timestamp = 'now'; + +show variables where variable_name = "vers_hide"; +select * from t for system_time all; + +set global vers_hide= AUTO; +select * from t; +select * from t for system_time as of timestamp current_timestamp(6); +--replace_regex /\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\.\d{6}/TIMESTAMP/ +select * from t for system_time all; +--replace_regex /\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\.\d{6}/TIMESTAMP/ +select * from t for system_time timestamp from '0-0-0' to current_timestamp(6); +--replace_regex /\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\.\d{6}/TIMESTAMP/ +select * from t for system_time timestamp between '0-0-0' and current_timestamp(6); + +set global vers_hide= NEVER; +--replace_regex /\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\.\d{6}/TIMESTAMP/ +select * from t; + +set global vers_hide= FULL; +create or replace table t ( + x int, + st timestamp(6) generated always as row start, + en timestamp(6) generated always as row end, + period for system_time (st, en)) +with system versioning; + +show create table t; +insert into t values (1); +delete from t; + +select * from t; +select * from t for system_time all; + +drop table t; +set global vers_hide= IMPLICIT; \ No newline at end of file diff --git a/mysql-test/suite/versioning/t/truncate_history.opt b/mysql-test/suite/versioning/t/truncate_history.opt new file mode 100644 index 00000000000..61ababdf408 --- /dev/null +++ b/mysql-test/suite/versioning/t/truncate_history.opt @@ -0,0 +1 @@ +--vers-hide=implicit diff --git a/mysql-test/suite/versioning/t/variables.test b/mysql-test/suite/versioning/t/variables.test deleted file mode 100644 index 7b7b458f642..00000000000 --- a/mysql-test/suite/versioning/t/variables.test +++ /dev/null @@ -1,28 +0,0 @@ -create table t (a int) with system versioning; -insert into t values (1); -update t set a=2; - -select * from t; -show variables where Variable_name like "temporal_current_timestamp%"; - -set global temporal_current_timestamp = '2031-1-1 0:0:0'; -select * from t; - -set global temporal_current_timestamp = '2011-1-1 0:0:0'; -select * from t; - -set global temporal_current_timestamp = 'all'; -select * from t; -show variables where Variable_name like "temporal_current_timestamp%"; - -create view vt as select * from t; -select * from t; -drop view vt; - -select * from (select * from t) as tt; - ---error ER_GLOBAL_VARIABLE -set session temporal_current_timestamp = 'now'; - -drop table t; -set global temporal_current_timestamp = 'now'; diff --git a/mysql-test/suite/versioning/t/view.opt b/mysql-test/suite/versioning/t/view.opt new file mode 100644 index 00000000000..61ababdf408 --- /dev/null +++ b/mysql-test/suite/versioning/t/view.opt @@ -0,0 +1 @@ +--vers-hide=implicit diff --git a/plugin/versioning/versioning.cc b/plugin/versioning/versioning.cc index 44faf85aef7..c1a5a7cd6a5 100644 --- a/plugin/versioning/versioning.cc +++ b/plugin/versioning/versioning.cc @@ -30,7 +30,7 @@ static int forced_versioning_init(void *p __attribute__ ((unused))) DBUG_ENTER("forced_versioning_init"); vers_force= true; - vers_hide= true; + vers_hide= VERS_HIDE_FULL; DBUG_RETURN(0); } @@ -38,7 +38,7 @@ static int forced_versioning_deinit(void *p __attribute__ ((unused))) { DBUG_ENTER("forced_versioning_deinit"); vers_force= false; - vers_hide= false; + vers_hide= VERS_HIDE_AUTO; DBUG_RETURN(0); } diff --git a/sql/handler.cc b/sql/handler.cc index 909e0aa6fee..62091b0f19e 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6599,6 +6599,14 @@ bool Vers_parse_info::is_trx_end(const char *name) const DBUG_ASSERT(name); return generated_as_row.end && !strcmp(generated_as_row.end->c_ptr(), name); } +bool Vers_parse_info::is_trx_start(const Create_field &f) const +{ + return f.flags & VERS_SYS_START_FLAG; +} +bool Vers_parse_info::is_trx_end(const Create_field &f) const +{ + return f.flags & VERS_SYS_END_FLAG; +} static bool create_string(MEM_ROOT *mem_root, String **s, const char *value) { @@ -6675,12 +6683,28 @@ bool Vers_parse_info::check_and_fix_implicit( bool integer_fields= create_info->db_type->flags & HTON_SUPPORTS_SYS_VERSIONING; - if (vers_force) { + SELECT_LEX &slex= thd->lex->select_lex; + int vers_tables= 0; + bool from_select= slex.item_list.elements ? true : false; + + if (from_select) + { + for (TABLE_LIST *table= slex.table_list.first; table; table= table->next_local) + { + if (table->table && table->table->versioned()) + vers_tables++; + } + } + + // CREATE ... SELECT: if at least one table in SELECT is versioned, + // then created table will be versioned. + if (vers_force || vers_tables > 0) + { declared_with_system_versioning= true; create_info->options|= HA_VERSIONED_TABLE; } - if (!need_to_check()) + if (!need_check()) return false; if (declared_without_system_versioning) @@ -6697,11 +6721,43 @@ bool Vers_parse_info::check_and_fix_implicit( return true; } + TABLE *orig_table= NULL; List_iterator it(alter_info->create_list); while (Create_field *f= it++) { - if (is_trx_start(f->field_name) || is_trx_end(f->field_name)) + if (is_trx_start(*f)) + { + if (!generated_as_row.start) // not inited in CREATE ... SELECT + { + DBUG_ASSERT(vers_tables > 0); + if (orig_table && orig_table != f->field->orig_table) + { + err_different_tables: + my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, + "system fields selected from different tables"); + return true; + } + orig_table= f->field->orig_table; + generated_as_row.start= new (thd->mem_root) String(f->field_name, system_charset_info); + period_for_system_time.start= generated_as_row.start; + } continue; + } + if (is_trx_end(*f)) + { + if (!generated_as_row.end) + { + DBUG_ASSERT(vers_tables > 0); + if (orig_table && orig_table != f->field->orig_table) + { + goto err_different_tables; + } + orig_table= f->field->orig_table; + generated_as_row.end= new (thd->mem_root) String(f->field_name, system_charset_info); + period_for_system_time.end= generated_as_row.end; + } + continue; + } if ((f->versioning == Column_definition::VERSIONING_NOT_SET && !declared_with_system_versioning) || @@ -6711,32 +6767,50 @@ bool Vers_parse_info::check_and_fix_implicit( } } - if (fix_implicit(thd, alter_info, integer_fields)) + if (vers_tables > 0) + { + if (!generated_as_row.start && !generated_as_row.end) + { + declared_with_system_versioning= false; + create_info->options&= ~HA_VERSIONED_TABLE; + return false; + } + if (!generated_as_row.start || !generated_as_row.end) + { + my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, + "both ROW START and ROW END system fields required in SELECT resultset"); + return true; + } + } + else if (fix_implicit(thd, alter_info, integer_fields)) return true; - int not_set= 0; - int with= 0; + int plain_cols= 0; // column doesn't have WITH or WITHOUT SYSTEM VERSIONING + int vers_cols= 0; // column has WITH SYSTEM VERSIONING it.rewind(); while (const Create_field *f= it++) { - if (is_trx_start(f->field_name) || is_trx_end(f->field_name)) + if (is_trx_start(*f) || is_trx_end(*f)) continue; if (f->versioning == Column_definition::VERSIONING_NOT_SET) - not_set++; + plain_cols++; else if (f->versioning == Column_definition::WITH_VERSIONING) - with++; + vers_cols++; } bool table_with_system_versioning= generated_as_row.start || generated_as_row.end || period_for_system_time.start || period_for_system_time.end; - if (!thd->lex->tmp_table() && with == 0 && - (not_set == 0 || !table_with_system_versioning)) + if (!thd->lex->tmp_table() && + // CREATE from SELECT (Create_fields are not yet added) + !from_select && + vers_cols == 0 && + (plain_cols == 0 || !table_with_system_versioning)) { my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, - "versioned fields missing"); + "no columns defined with system versioning!"); return true; } @@ -6762,7 +6836,7 @@ bool Vers_parse_info::check_and_fix_alter(THD *thd, Alter_info *alter_info, create_info->db_type->flags & HTON_SUPPORTS_SYS_VERSIONING; const char *table_name= share->table_name.str; - if (!need_to_check() && !share->versioned) + if (!need_check() && !share->versioned) return false; if (declared_without_system_versioning) @@ -6934,7 +7008,7 @@ bool Vers_parse_info::check_generated_type(const char *table_name, List_iterator it(alter_info->create_list); while (Create_field *f= it++) { - if (is_trx_start(f->field_name) || is_trx_end(f->field_name)) + if (is_trx_start(*f) || is_trx_end(*f)) { if (integer_fields) { diff --git a/sql/handler.h b/sql/handler.h index a0da6852da4..76d6bae734f 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1670,6 +1670,7 @@ struct Schema_specification_st } }; +class Create_field; struct Vers_parse_info { @@ -1701,8 +1702,10 @@ struct Vers_parse_info private: bool is_trx_start(const char *name) const; bool is_trx_end(const char *name) const; + bool is_trx_start(const Create_field &f) const; + bool is_trx_end(const Create_field &f) const; bool fix_implicit(THD *thd, Alter_info *alter_info, bool integer_fields); - bool need_to_check() const + bool need_check() const { return has_versioned_fields || diff --git a/sql/mysqld.cc b/sql/mysqld.cc index bb96893e49d..1696f689aab 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -784,7 +784,7 @@ char *opt_logname, *opt_slow_logname, *opt_bin_logname; /* System Versioning */ char *temporal_current_timestamp; my_bool vers_force= false; -my_bool vers_hide= false; +ulong vers_hide= VERS_HIDE_AUTO; /* Static variables */ diff --git a/sql/mysqld.h b/sql/mysqld.h index 20300895fe5..8cf14cc19a5 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -177,7 +177,13 @@ extern const char *log_output_str; extern const char *log_backup_output_str; extern char *temporal_current_timestamp; extern my_bool vers_force; -extern my_bool vers_hide; +enum vers_hide_enum { + VERS_HIDE_AUTO= 0, + VERS_HIDE_IMPLICIT, + VERS_HIDE_FULL, + VERS_HIDE_NEVER +}; +extern ulong vers_hide; extern char *mysql_home_ptr, *pidfile_name_ptr; extern MYSQL_PLUGIN_IMPORT char glob_hostname[FN_REFLEN]; extern char mysql_home[FN_REFLEN]; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 2ca2c9141f3..df50b2a7afa 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7586,10 +7586,27 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, { Item_field *f= static_cast(item); DBUG_ASSERT(f->field); - if (f->field->flags & HIDDEN_FLAG) + uint32 fl= f->field->flags; + bool sys_field= fl & (VERS_SYS_START_FLAG | VERS_SYS_END_FLAG); + SELECT_LEX *slex= thd->lex->current_select; + TABLE *table= f->field->table; + DBUG_ASSERT(table && table->pos_in_table_list); + TABLE_LIST *tl= table->pos_in_table_list; + vers_range_type_t vers_type= + tl->vers_conditions.type == FOR_SYSTEM_TIME_UNSPECIFIED ? + slex->vers_conditions.type : tl->vers_conditions.type; + + if ((sys_field && vers_hide == VERS_HIDE_FULL && + thd->lex->sql_command != SQLCOM_CREATE_TABLE) || + ((fl & HIDDEN_FLAG) && ( + !sys_field || + vers_hide == VERS_HIDE_IMPLICIT || + (vers_hide == VERS_HIDE_AUTO && ( + vers_type == FOR_SYSTEM_TIME_UNSPECIFIED || + vers_type == FOR_SYSTEM_TIME_AS_OF))))) continue; } - if (item->type() == Item::REF_ITEM) + else if (item->type() == Item::REF_ITEM) { Item *i= item; while (i->type() == Item::REF_ITEM) diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 50b98678271..b0e1d06365f 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -4164,6 +4164,12 @@ static TABLE *create_table_from_items(THD *thd, alter_info->create_list.push_back(cr_field, thd->mem_root); } + if (create_info->vers_info.check_and_fix_implicit( + thd, alter_info, create_info, create_table->table_name)) + { + DBUG_RETURN(NULL); + } + DEBUG_SYNC(thd,"create_table_select_before_create"); /* Check if LOCK TABLES + CREATE OR REPLACE of existing normal table*/ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 677dd269722..cc0dcf9a3a8 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3876,13 +3876,6 @@ mysql_execute_command(THD *thd) if (!(create_info.used_fields & HA_CREATE_USED_ENGINE)) create_info.use_default_db_type(thd); - if (!create_info.like() && - create_info.vers_info.check_and_fix_implicit( - thd, &alter_info, &create_info, create_table->table_name)) - { - goto end_with_restore_list; - } - /* If we are using SET CHARSET without DEFAULT, add an implicit DEFAULT to not confuse old users. (This may change). @@ -4069,6 +4062,11 @@ mysql_execute_command(THD *thd) } else { + if (create_info.vers_info.check_and_fix_implicit( + thd, &alter_info, &create_info, create_table->table_name)) + { + goto end_with_restore_list; + } /* In STATEMENT format, we probably have to replicate also temporary tables, like mysql replication does. Also check if the requested diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 7658bb9e2d0..1c57ca2e77a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -16173,7 +16173,12 @@ Field *create_tmp_field_from_field(THD *thd, Field *org_field, item->result_field= new_field; else new_field->field_name= name; - new_field->flags|= (org_field->flags & NO_DEFAULT_VALUE_FLAG); + new_field->flags|= (org_field->flags & ( + NO_DEFAULT_VALUE_FLAG | + HIDDEN_FLAG | + VERS_SYS_START_FLAG | + VERS_SYS_END_FLAG | + VERS_OPTIMIZED_UPDATE_FLAG)); if (org_field->maybe_null() || (item && item->maybe_null)) new_field->flags&= ~NOT_NULL_FLAG; // Because of outer join if (org_field->type() == MYSQL_TYPE_VAR_STRING || diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 0f1098dcede..bedc32d6010 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2064,7 +2064,7 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, { uint flags = field->flags; - if (vers_hide && + if (vers_hide == VERS_HIDE_FULL && (flags & (VERS_SYS_START_FLAG | VERS_SYS_END_FLAG))) continue; @@ -2233,7 +2233,7 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, hton->index_options); } - if (table->versioned() && !vers_hide) + if (table->versioned() && vers_hide != VERS_HIDE_FULL) { const Field *fs = table->vers_start_field(); const Field *fe = table->vers_end_field(); @@ -2282,7 +2282,7 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, add_table_options(thd, table, create_info_arg, table_list->schema_table != 0, 0, packet); - if (table->versioned() && !vers_hide) + if (table->versioned() && vers_hide != VERS_HIDE_FULL) { packet->append(STRING_WITH_LEN(" WITH SYSTEM VERSIONING")); } diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index b6f84e88d07..9fb32174d1c 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -391,9 +391,14 @@ static Sys_var_mybool Sys_vers_force( "vers_force", "Force system versioning for all created tables", GLOBAL_VAR(vers_force), CMD_LINE(OPT_ARG), DEFAULT(FALSE)); -static Sys_var_mybool Sys_vers_hide( - "vers_hide", "Hide system versioning from being displayed in table info", - GLOBAL_VAR(vers_hide), CMD_LINE(OPT_ARG), DEFAULT(FALSE)); +static const char *vers_hide_keywords[]= {"AUTO", "IMPLICIT", "FULL", "NEVER", NullS}; +static Sys_var_enum Sys_vers_hide( + "vers_hide", "Hide system versioning from being displayed in table info. " + "AUTO: hide implicit system fields only in non-versioned and AS OF queries; " + "IMPLICIT: hide implicit system fields in all queries; " + "FULL: hide any system fields in all queries and hide versioning info in SHOW commands; " + "NEVER: don't hide system fields", + GLOBAL_VAR(vers_hide), CMD_LINE(OPT_ARG), vers_hide_keywords, DEFAULT(VERS_HIDE_AUTO)); static Sys_var_ulonglong Sys_binlog_cache_size( "binlog_cache_size", "The size of the transactional cache for " diff --git a/sql/table.cc b/sql/table.cc index b256b3e91b6..6470d5dfa4a 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2563,8 +2563,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, DBUG_PRINT("info", ("Columns with system versioning: [%d, %d]", row_start, row_end)); versioned= true; vers_init(); - row_start_field = row_start; - row_end_field = row_end; + row_start_field= row_start; + row_end_field= row_end; vers_start_field()->flags|= VERS_SYS_START_FLAG; vers_end_field()->flags|= VERS_SYS_END_FLAG; } // if (system_period == NULL) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index aea14e9ca59..ac3e2edf304 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -8717,9 +8717,10 @@ no_commit: innobase_srv_conc_enter_innodb(m_prebuilt); - vers_set_fields = table->versioned() && + vers_set_fields = table->versioned() && ( (sql_command != SQLCOM_DELETE || - (m_int_table_flags & HA_INNOPART_DISABLED_TABLE_FLAGS)) ? + (m_int_table_flags & HA_INNOPART_DISABLED_TABLE_FLAGS)) && + sql_command != SQLCOM_CREATE_TABLE) ? ROW_INS_VERSIONED : ROW_INS_NORMAL; diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 5c1ac9775ee..3631022228b 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -1498,7 +1498,7 @@ row_insert_for_mysql( if (ins_mode == ROW_INS_HISTORICAL) { set_tuple_col_8(node->row, table->vers_row_end, trx->id, node->entry_sys_heap); } - else { + else /* ROW_INS_VERSIONED */ { set_tuple_col_8(node->row, table->vers_row_end, IB_UINT64_MAX, node->entry_sys_heap); int8store(&mysql_rec[t->mysql_col_offset], IB_UINT64_MAX); t = &prebuilt->mysql_template[table->vers_row_start]; -- cgit v1.2.1 From f8b562f5e71bdc1132f9a9b6c2c6a90fca1f006d Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 28 Mar 2017 15:44:48 +0300 Subject: Scripts: capture_warnings.sh missed errors and exit status fix --- BUILD/capture_warnings.sh | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/BUILD/capture_warnings.sh b/BUILD/capture_warnings.sh index 4eeae4e89dc..3413c4226ee 100755 --- a/BUILD/capture_warnings.sh +++ b/BUILD/capture_warnings.sh @@ -1,6 +1,6 @@ #!/bin/bash warn_path=$1 -warn_mode=$2 +warn_mode=$2 # 'late', 'early' or 'both' shift 2 warn_file="$warn_path/compile.warnings" @@ -45,7 +45,7 @@ suppress_warnings() unset from - if [[ $l =~ ^[[:space:]]*\^~*$ ]] + if [[ $l =~ ^[[:space:]]*~*\^~*$ ]] then cat "$suppress_file" | tr '\n' 'X' | /bin/grep -Gq "$m" || echo "$w" @@ -68,18 +68,19 @@ suppress_warnings() } exec 3>&1 -cmderr=$("$@" 2>&1 1>&3 | suppress_warnings) || { - error=${PIPESTATUS} - echo "$cmderr" >&2 - exit $error -} - -if [[ -n "$cmderr" ]]; then - [[ "$warn_mode" != "late" || "$cmderr" =~ error: ]] && - echo "$cmderr" >&2 - [[ "$warn_mode" != "early" && "$cmderr" =~ (warning|note): ]] && - echo "$cmderr" >> "$warn_file" -fi +"$@" 2>&1 1>&3 | suppress_warnings | ( + cmderr=`cat` -true + if [[ -n "$cmderr" ]]; then + if [[ "$cmderr" =~ error: ]]; then + echo "$cmderr" >&2 + exit + fi + [[ "$warn_mode" != "late" ]] && + echo "$cmderr" >&2 + [[ "$warn_mode" != "early" && "$cmderr" =~ (warning|note): ]] && + echo "$cmderr" >> "$warn_file" + fi +) +exit ${PIPESTATUS} -- cgit v1.2.1 From f77a4135bf9deffa7220fd4d4e4c597313e886d7 Mon Sep 17 00:00:00 2001 From: kevg Date: Thu, 30 Mar 2017 15:32:31 +0300 Subject: SQL: parsing of QUERY FOR [fixes #159] Reverts 46e36bbffa7cd8d9eb861a22755025ffe8751449 - SQL: fix assertion failure in parser --- mysql-test/suite/versioning/r/select.result | 15 ++++++++++++++- mysql-test/suite/versioning/t/select.test | 9 ++++++++- sql/sql_lex.cc | 15 +++++++++++++++ sql/sql_yacc.yy | 27 +++++++++++---------------- 4 files changed, 48 insertions(+), 18 deletions(-) diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index 34ce9e3976e..dda7c08e64c 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -426,9 +426,19 @@ a a 2 3 3 3 1 NULL +create or replace table t1 (x int) with system versioning; +create or replace table t2 (y int) with system versioning; +insert into t1 values (1), (2), (3); +delete from t1 where x = 3; +insert into t2 values (1); +select * from t1, t2 query for system_time all; +x y +1 1 +2 1 +3 1 drop view v1; drop table t1, t2; -call innodb_verify_vtq(24); +call innodb_verify_vtq(27); No A B C D 1 1 1 1 1 2 1 1 1 1 @@ -454,6 +464,9 @@ No A B C D 22 1 1 1 1 23 1 1 1 1 24 1 1 1 1 +25 1 1 1 1 +26 1 1 1 1 +27 1 1 1 1 drop procedure test_01; drop procedure test_02; drop procedure verify_vtq; diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index fb086b0060d..3f92546d1e4 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -190,10 +190,17 @@ insert into t1 values (2); insert into t1 values (3); select * from t1 left outer join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; +create or replace table t1 (x int) with system versioning; +create or replace table t2 (y int) with system versioning; +insert into t1 values (1), (2), (3); +delete from t1 where x = 3; +insert into t2 values (1); +select * from t1, t2 query for system_time all; + drop view v1; drop table t1, t2; -call innodb_verify_vtq(24); +call innodb_verify_vtq(27); drop procedure test_01; drop procedure test_02; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 5260e81ff8b..5f3c83eed71 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1368,6 +1368,21 @@ int MYSQLlex(YYSTYPE *yylval, THD *thd) return FOR_SYM; } break; + case QUERY_SYM: + { + CHARSET_INFO *cs= thd->charset(); + const char *p= lip->get_ptr(); + while (my_isspace(cs, *p)) + ++p; + if (lip->get_end_of_query() - p > 3 && my_isspace(cs, p[3]) && + 0 == strncasecmp(p, "for", 3)) + { + token= lex_one_token(yylval, thd); + lip->add_digest_token(token, yylval); + return QUERY_FOR_SYM; + } + return QUERY_SYM; + } default: break; } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 5eab752df3f..4abe1dbc24a 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -861,10 +861,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %parse-param { THD *thd } %lex-param { THD *thd } /* - Currently there are 106 shift/reduce conflicts. + Currently there are 103 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 106 +%expect 103 /* Comments for TOKENS. @@ -1353,6 +1353,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token PURGE %token QUARTER_SYM %token QUERY_SYM +%token QUERY_FOR_SYM /* INTERNAL */ %token QUICK %token RAISE_SYM /* Oracle-PLSQL-R */ %token RANGE_SYM /* SQL-2003-R */ @@ -8828,7 +8829,7 @@ trans_or_timestamp: opt_query_for_system_time_clause: /* empty */ {} - | QUERY_SYM FOR_SYSTEM_TIME_SYM for_system_time_expr + | QUERY_FOR_SYM SYSTEM_TIME_SYM for_system_time_expr { DBUG_ASSERT(Select); Select->vers_conditions= Lex->vers_conditions; @@ -11705,21 +11706,15 @@ date_time_type: | TIMESTAMP {$$=MYSQL_TIMESTAMP_DATETIME;} ; +table_alias: + /* empty */ + | AS + | '=' + ; + opt_table_alias: /* empty */ { $$=0; } - | ident - { - $$= (LEX_STRING*) thd->memdup(&$1,sizeof(LEX_STRING)); - if ($$ == NULL) - MYSQL_YYABORT; - } - | AS ident - { - $$= (LEX_STRING*) thd->memdup(&$2,sizeof(LEX_STRING)); - if ($$ == NULL) - MYSQL_YYABORT; - } - | '=' ident + | table_alias ident { $$= (LEX_STRING*) thd->memdup(&$2,sizeof(LEX_STRING)); if ($$ == NULL) -- cgit v1.2.1 From b240671c04248400ec7954e56dacfeab45ee5343 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Thu, 30 Mar 2017 23:13:09 +0300 Subject: Tests: sys_vars.sysvars_server_notembedded result (2) Related to #157 --- mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result index d2036f830be..a4d7265e06e 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result @@ -5149,16 +5149,16 @@ READ_ONLY NO COMMAND_LINE_ARGUMENT OPTIONAL VARIABLE_NAME VERS_HIDE SESSION_VALUE NULL -GLOBAL_VALUE OFF +GLOBAL_VALUE AUTO GLOBAL_VALUE_ORIGIN COMPILE-TIME -DEFAULT_VALUE OFF +DEFAULT_VALUE AUTO VARIABLE_SCOPE GLOBAL -VARIABLE_TYPE BOOLEAN -VARIABLE_COMMENT Hide system versioning from being displayed in table info +VARIABLE_TYPE ENUM +VARIABLE_COMMENT Hide system versioning from being displayed in table info. AUTO: hide implicit system fields only in non-versioned and AS OF queries; IMPLICIT: hide implicit system fields in all queries; FULL: hide any system fields in all queries and hide versioning info in SHOW commands; NEVER: don't hide system fields NUMERIC_MIN_VALUE NULL NUMERIC_MAX_VALUE NULL NUMERIC_BLOCK_SIZE NULL -ENUM_VALUE_LIST OFF,ON +ENUM_VALUE_LIST AUTO,IMPLICIT,FULL,NEVER READ_ONLY NO COMMAND_LINE_ARGUMENT OPTIONAL VARIABLE_NAME WAIT_TIMEOUT -- cgit v1.2.1 From 9e9af76eaf4eec4f105e029975ec5a142ec7e8f2 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Thu, 30 Mar 2017 12:57:31 +0300 Subject: SQL: vers_current_time refactoring [closes #117] * session sysvars; * moved value parsing to set variable phase; * renamed 'temporal_current_timestamp' to 'vers_current_time'. --- .../sys_vars/r/sysvars_server_notembedded.result | 36 ++--- mysql-test/suite/versioning/r/sysvars.result | 92 ++++++++++-- mysql-test/suite/versioning/t/sysvars.test | 73 ++++++++-- plugin/versioning/versioning.cc | 13 +- sql/handler.cc | 2 +- sql/mysqld.cc | 16 +- sql/mysqld.h | 26 +++- sql/set_var.h | 7 + sql/sql_base.cc | 1 + sql/sql_class.h | 4 + sql/sql_select.cc | 27 ++-- sql/sql_show.cc | 1 + sql/sys_vars.cc | 10 +- sql/sys_vars.ic | 162 +++++++++++++++++++++ sql/table.h | 10 -- 15 files changed, 391 insertions(+), 89 deletions(-) diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result index a4d7265e06e..5e8bacbc4d0 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result @@ -4769,20 +4769,6 @@ NUMERIC_BLOCK_SIZE 1 ENUM_VALUE_LIST NULL READ_ONLY YES COMMAND_LINE_ARGUMENT REQUIRED -VARIABLE_NAME TEMPORAL_CURRENT_TIMESTAMP -SESSION_VALUE NULL -GLOBAL_VALUE now -GLOBAL_VALUE_ORIGIN COMPILE-TIME -DEFAULT_VALUE now -VARIABLE_SCOPE GLOBAL -VARIABLE_TYPE VARCHAR -VARIABLE_COMMENT Default AS OF value for versioned tables -NUMERIC_MIN_VALUE NULL -NUMERIC_MAX_VALUE NULL -NUMERIC_BLOCK_SIZE NULL -ENUM_VALUE_LIST NULL -READ_ONLY NO -COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME THREAD_CACHE_SIZE SESSION_VALUE NULL GLOBAL_VALUE 151 @@ -5133,12 +5119,26 @@ NUMERIC_BLOCK_SIZE NULL ENUM_VALUE_LIST NEVER,COMPLEMENTARY,PREFERABLY READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED +VARIABLE_NAME VERS_CURRENT_TIME +SESSION_VALUE NOW +GLOBAL_VALUE NOW +GLOBAL_VALUE_ORIGIN COMPILE-TIME +DEFAULT_VALUE now +VARIABLE_SCOPE SESSION +VARIABLE_TYPE VARCHAR +VARIABLE_COMMENT Default AS OF value for versioned tables +NUMERIC_MIN_VALUE NULL +NUMERIC_MAX_VALUE NULL +NUMERIC_BLOCK_SIZE NULL +ENUM_VALUE_LIST NULL +READ_ONLY NO +COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME VERS_FORCE -SESSION_VALUE NULL +SESSION_VALUE OFF GLOBAL_VALUE OFF GLOBAL_VALUE_ORIGIN COMPILE-TIME DEFAULT_VALUE OFF -VARIABLE_SCOPE GLOBAL +VARIABLE_SCOPE SESSION VARIABLE_TYPE BOOLEAN VARIABLE_COMMENT Force system versioning for all created tables NUMERIC_MIN_VALUE NULL @@ -5148,11 +5148,11 @@ ENUM_VALUE_LIST OFF,ON READ_ONLY NO COMMAND_LINE_ARGUMENT OPTIONAL VARIABLE_NAME VERS_HIDE -SESSION_VALUE NULL +SESSION_VALUE AUTO GLOBAL_VALUE AUTO GLOBAL_VALUE_ORIGIN COMPILE-TIME DEFAULT_VALUE AUTO -VARIABLE_SCOPE GLOBAL +VARIABLE_SCOPE SESSION VARIABLE_TYPE ENUM VARIABLE_COMMENT Hide system versioning from being displayed in table info. AUTO: hide implicit system fields only in non-versioned and AS OF queries; IMPLICIT: hide implicit system fields in all queries; FULL: hide any system fields in all queries and hide versioning info in SHOW commands; NEVER: don't hide system fields NUMERIC_MIN_VALUE NULL diff --git a/mysql-test/suite/versioning/r/sysvars.result b/mysql-test/suite/versioning/r/sysvars.result index 120a3583754..dbab7f2c910 100644 --- a/mysql-test/suite/versioning/r/sysvars.result +++ b/mysql-test/suite/versioning/r/sysvars.result @@ -1,27 +1,36 @@ create table t (a int) with system versioning; insert into t values (1); update t set a= 2; +show global variables like 'vers_current_time'; +Variable_name Value +vers_current_time NOW +show variables like 'vers_current_time'; +Variable_name Value +vers_current_time NOW select * from t; a 2 -show variables where variable_name = "temporal_current_timestamp"; +set vers_current_time = '2031-1-1 0:0:0'; +show variables like 'vers_current_time'; Variable_name Value -temporal_current_timestamp now -set global temporal_current_timestamp = '2031-1-1 0:0:0'; +vers_current_time 2031-01-01 00:00:00.000000 select * from t; a 2 -set global temporal_current_timestamp = '2011-1-1 0:0:0'; +set vers_current_time = '2011-1-1 0:0:0'; +show variables like 'vers_current_time'; +Variable_name Value +vers_current_time 2011-01-01 00:00:00.000000 select * from t; a -set global temporal_current_timestamp = 'all'; +set vers_current_time = 'all'; +show variables like 'vers_current_time'; +Variable_name Value +vers_current_time ALL select * from t; a 2 1 -show variables where Variable_name like "temporal_current_timestamp%"; -Variable_name Value -temporal_current_timestamp all create view vt as select * from t; select * from t; a @@ -32,9 +41,62 @@ select * from (select * from t) as tt; a 2 1 -set session temporal_current_timestamp = 'now'; -ERROR HY000: Variable 'temporal_current_timestamp' is a GLOBAL variable and should be set with SET GLOBAL -set global temporal_current_timestamp = 'now'; +set global vers_current_time= 'alley'; +ERROR 42000: Variable 'vers_current_time' can't be set to the value of 'alley' +set global vers_current_time= null; +ERROR 42000: Variable 'vers_current_time' can't be set to the value of 'NULL' +set global vers_current_time= 1; +ERROR 42000: Incorrect argument type to variable 'vers_current_time' +set global vers_current_time= 1.1; +ERROR 42000: Incorrect argument type to variable 'vers_current_time' +set vers_current_time= 'alley'; +ERROR 42000: Variable 'vers_current_time' can't be set to the value of 'alley' +set vers_current_time= null; +ERROR 42000: Variable 'vers_current_time' can't be set to the value of 'NULL' +set vers_current_time= 1; +ERROR 42000: Incorrect argument type to variable 'vers_current_time' +set vers_current_time= 1.1; +ERROR 42000: Incorrect argument type to variable 'vers_current_time' +set global vers_current_time= '1911-11-11 11:11:11.1111119'; +show global variables like 'vers_current_time'; +Variable_name Value +vers_current_time 1911-11-11 11:11:11.111111 +set global vers_current_time= '1900-01-01 00:00:00'; +show global variables like 'vers_current_time'; +Variable_name Value +vers_current_time 1900-01-01 00:00:00.000000 +set global vers_current_time= timestamp'1911-11-11 11:11:11.1111119'; +Warnings: +Note 1292 Truncated incorrect datetime value: '1911-11-11 11:11:11.1111119' +show global variables like 'vers_current_time'; +Variable_name Value +vers_current_time 1911-11-11 11:11:11.111111 +set @ts= timestamp'1900-01-01 00:00:00'; +set global vers_current_time= @ts; +show global variables like 'vers_current_time'; +Variable_name Value +vers_current_time 1900-01-01 00:00:00.000000 +set vers_current_time= '1911-11-11 11:11:11.1111119'; +show variables like 'vers_current_time'; +Variable_name Value +vers_current_time 1911-11-11 11:11:11.111111 +set vers_current_time= '1900-01-01 00:00:00'; +show variables like 'vers_current_time'; +Variable_name Value +vers_current_time 1900-01-01 00:00:00.000000 +set vers_current_time= timestamp'1911-11-11 11:11:11.1111119'; +Warnings: +Note 1292 Truncated incorrect datetime value: '1911-11-11 11:11:11.1111119' +show variables like 'vers_current_time'; +Variable_name Value +vers_current_time 1911-11-11 11:11:11.111111 +set @ts= timestamp'1900-01-01 00:00:00'; +set vers_current_time= @ts; +show variables like 'vers_current_time'; +Variable_name Value +vers_current_time 1900-01-01 00:00:00.000000 +set global vers_current_time= 'now'; +set vers_current_time= 'now'; show variables where variable_name = "vers_hide"; Variable_name Value vers_hide IMPLICIT @@ -42,7 +104,7 @@ select * from t for system_time all; a 2 1 -set global vers_hide= AUTO; +set vers_hide= AUTO; select * from t; a 2 @@ -61,11 +123,11 @@ select * from t for system_time timestamp between '0-0-0' and current_timestamp( a sys_trx_start sys_trx_end 2 TIMESTAMP TIMESTAMP 1 TIMESTAMP TIMESTAMP -set global vers_hide= NEVER; +set vers_hide= NEVER; select * from t; a sys_trx_start sys_trx_end 2 TIMESTAMP TIMESTAMP -set global vers_hide= FULL; +set vers_hide= FULL; create or replace table t ( x int, st timestamp(6) generated always as row start, @@ -85,4 +147,4 @@ select * from t for system_time all; x 1 drop table t; -set global vers_hide= IMPLICIT; +set vers_hide= IMPLICIT; diff --git a/mysql-test/suite/versioning/t/sysvars.test b/mysql-test/suite/versioning/t/sysvars.test index ba985a92c9a..b6deadb8470 100644 --- a/mysql-test/suite/versioning/t/sysvars.test +++ b/mysql-test/suite/versioning/t/sysvars.test @@ -2,18 +2,21 @@ create table t (a int) with system versioning; insert into t values (1); update t set a= 2; +show global variables like 'vers_current_time'; +show variables like 'vers_current_time'; select * from t; -show variables where variable_name = "temporal_current_timestamp"; -set global temporal_current_timestamp = '2031-1-1 0:0:0'; +set vers_current_time = '2031-1-1 0:0:0'; +show variables like 'vers_current_time'; select * from t; -set global temporal_current_timestamp = '2011-1-1 0:0:0'; +set vers_current_time = '2011-1-1 0:0:0'; +show variables like 'vers_current_time'; select * from t; -set global temporal_current_timestamp = 'all'; +set vers_current_time = 'all'; +show variables like 'vers_current_time'; select * from t; -show variables where Variable_name like "temporal_current_timestamp%"; create view vt as select * from t; select * from t; @@ -21,15 +24,61 @@ drop view vt; select * from (select * from t) as tt; ---error ER_GLOBAL_VARIABLE -set session temporal_current_timestamp = 'now'; +# global +--error ER_WRONG_VALUE_FOR_VAR +set global vers_current_time= 'alley'; +--error ER_WRONG_VALUE_FOR_VAR +set global vers_current_time= null; +--error ER_WRONG_TYPE_FOR_VAR +set global vers_current_time= 1; +--error ER_WRONG_TYPE_FOR_VAR +set global vers_current_time= 1.1; -set global temporal_current_timestamp = 'now'; +# session +--error ER_WRONG_VALUE_FOR_VAR +set vers_current_time= 'alley'; +--error ER_WRONG_VALUE_FOR_VAR +set vers_current_time= null; +--error ER_WRONG_TYPE_FOR_VAR +set vers_current_time= 1; +--error ER_WRONG_TYPE_FOR_VAR +set vers_current_time= 1.1; + +# global +set global vers_current_time= '1911-11-11 11:11:11.1111119'; +show global variables like 'vers_current_time'; + +set global vers_current_time= '1900-01-01 00:00:00'; +show global variables like 'vers_current_time'; + +set global vers_current_time= timestamp'1911-11-11 11:11:11.1111119'; +show global variables like 'vers_current_time'; + +set @ts= timestamp'1900-01-01 00:00:00'; +set global vers_current_time= @ts; +show global variables like 'vers_current_time'; + +# session +set vers_current_time= '1911-11-11 11:11:11.1111119'; +show variables like 'vers_current_time'; + +set vers_current_time= '1900-01-01 00:00:00'; +show variables like 'vers_current_time'; + +set vers_current_time= timestamp'1911-11-11 11:11:11.1111119'; +show variables like 'vers_current_time'; + +set @ts= timestamp'1900-01-01 00:00:00'; +set vers_current_time= @ts; +show variables like 'vers_current_time'; + +set global vers_current_time= 'now'; +set vers_current_time= 'now'; show variables where variable_name = "vers_hide"; select * from t for system_time all; -set global vers_hide= AUTO; +set vers_hide= AUTO; select * from t; select * from t for system_time as of timestamp current_timestamp(6); --replace_regex /\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\.\d{6}/TIMESTAMP/ @@ -39,11 +88,11 @@ select * from t for system_time timestamp from '0-0-0' to current_timestamp(6); --replace_regex /\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\.\d{6}/TIMESTAMP/ select * from t for system_time timestamp between '0-0-0' and current_timestamp(6); -set global vers_hide= NEVER; +set vers_hide= NEVER; --replace_regex /\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\.\d{6}/TIMESTAMP/ select * from t; -set global vers_hide= FULL; +set vers_hide= FULL; create or replace table t ( x int, st timestamp(6) generated always as row start, @@ -59,4 +108,4 @@ select * from t; select * from t for system_time all; drop table t; -set global vers_hide= IMPLICIT; \ No newline at end of file +set vers_hide= IMPLICIT; diff --git a/plugin/versioning/versioning.cc b/plugin/versioning/versioning.cc index c1a5a7cd6a5..016367f89f4 100644 --- a/plugin/versioning/versioning.cc +++ b/plugin/versioning/versioning.cc @@ -17,6 +17,7 @@ #include #include #include "sql_plugin.h" // st_plugin_int +#include "sql_class.h" /* Disable __attribute__() on non-gcc compilers. @@ -29,16 +30,20 @@ static int forced_versioning_init(void *p __attribute__ ((unused))) { DBUG_ENTER("forced_versioning_init"); - vers_force= true; - vers_hide= VERS_HIDE_FULL; + mysql_mutex_lock(&LOCK_global_system_variables); + global_system_variables.vers_force= true; + global_system_variables.vers_hide= VERS_HIDE_FULL; + mysql_mutex_unlock(&LOCK_global_system_variables); DBUG_RETURN(0); } static int forced_versioning_deinit(void *p __attribute__ ((unused))) { DBUG_ENTER("forced_versioning_deinit"); - vers_force= false; - vers_hide= VERS_HIDE_AUTO; + mysql_mutex_lock(&LOCK_global_system_variables); + global_system_variables.vers_force= false; + global_system_variables.vers_hide= VERS_HIDE_AUTO; + mysql_mutex_unlock(&LOCK_global_system_variables); DBUG_RETURN(0); } diff --git a/sql/handler.cc b/sql/handler.cc index 62091b0f19e..13c4031b02d 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6698,7 +6698,7 @@ bool Vers_parse_info::check_and_fix_implicit( // CREATE ... SELECT: if at least one table in SELECT is versioned, // then created table will be versioned. - if (vers_force || vers_tables > 0) + if (thd->variables.vers_force || vers_tables > 0) { declared_with_system_versioning= true; create_info->options|= HA_VERSIONED_TABLE; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 1696f689aab..454b5d10965 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -781,11 +781,6 @@ char *relay_log_info_file, *report_user, *report_password, *report_host; char *opt_relay_logname = 0, *opt_relaylog_index_name=0; char *opt_logname, *opt_slow_logname, *opt_bin_logname; -/* System Versioning */ -char *temporal_current_timestamp; -my_bool vers_force= false; -ulong vers_hide= VERS_HIDE_AUTO; - /* Static variables */ static volatile sig_atomic_t kill_in_progress; @@ -9315,6 +9310,17 @@ mysqld_get_one_option(int optid, const struct my_option *opt, char *argument) WSREP_SYNC_WAIT_BEFORE_READ); break; #endif /* WITH_WSREP */ + case OPT_VERS_CURRENT_TIME: + sys_var *var= static_cast(opt->app_type); + DBUG_ASSERT(var); + if (var->option_updated()) + { + sql_print_error("Can't start server: " + "cannot process --vers-current-time=%.*s", + FN_REFLEN, argument); + return 1; + } + break; } return 0; } diff --git a/sql/mysqld.h b/sql/mysqld.h index 8cf14cc19a5..e8a72b0b063 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -175,15 +175,34 @@ extern char *opt_backup_history_logname, *opt_backup_progress_logname, *opt_backup_settings_name; extern const char *log_output_str; extern const char *log_backup_output_str; -extern char *temporal_current_timestamp; -extern my_bool vers_force; + +enum vers_range_type_t +{ + FOR_SYSTEM_TIME_UNSPECIFIED = 0, + FOR_SYSTEM_TIME_AS_OF, + FOR_SYSTEM_TIME_FROM_TO, + FOR_SYSTEM_TIME_BETWEEN, + FOR_SYSTEM_TIME_ALL, + FOR_SYSTEM_TIME_BEFORE +}; + +struct st_vers_current_time +{ // This struct must be POD, so no virtual-anything! + char *str_value; // must be first + vers_range_type_t type; + MYSQL_TIME ltime; + st_vers_current_time() : + str_value(NULL), + type(FOR_SYSTEM_TIME_UNSPECIFIED) + {} +}; + enum vers_hide_enum { VERS_HIDE_AUTO= 0, VERS_HIDE_IMPLICIT, VERS_HIDE_FULL, VERS_HIDE_NEVER }; -extern ulong vers_hide; extern char *mysql_home_ptr, *pidfile_name_ptr; extern MYSQL_PLUGIN_IMPORT char glob_hostname[FN_REFLEN]; extern char mysql_home[FN_REFLEN]; @@ -652,6 +671,7 @@ enum options_mysqld OPT_SSL_KEY, OPT_THREAD_CONCURRENCY, OPT_WANT_CORE, + OPT_VERS_CURRENT_TIME, #ifdef WITH_WSREP OPT_WSREP_CAUSAL_READS, OPT_WSREP_SYNC_WAIT, diff --git a/sql/set_var.h b/sql/set_var.h index ddd6a225eb8..9c7d7f1135b 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -223,6 +223,13 @@ private: virtual bool session_update(THD *thd, set_var *var) = 0; virtual bool global_update(THD *thd, set_var *var) = 0; +public: + virtual bool option_updated() + { + DBUG_ASSERT(false); + return true; + } + protected: /** A pointer to a value of the variable for SHOW. diff --git a/sql/sql_base.cc b/sql/sql_base.cc index df50b2a7afa..d0c723af397 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7478,6 +7478,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, Field_iterator_table_ref field_iterator; bool found; char name_buff[SAFE_NAME_LEN+1]; + ulong vers_hide= thd->variables.vers_hide; DBUG_ENTER("insert_fields"); DBUG_PRINT("arena", ("stmt arena: 0x%lx", (ulong)thd->stmt_arena)); diff --git a/sql/sql_class.h b/sql/sql_class.h index 49f62f9ea4e..e3601f141fa 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -706,6 +706,10 @@ typedef struct system_variables uint idle_transaction_timeout; uint idle_readonly_transaction_timeout; uint idle_readwrite_transaction_timeout; + + st_vers_current_time vers_current_time; + my_bool vers_force; + ulong vers_hide; } SV; /** diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1c57ca2e77a..6739d51f360 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -670,24 +670,19 @@ setup_without_group(THD *thd, Ref_ptr_array ref_pointer_array, bool vers_select_conds_t::init_from_sysvar(THD *thd) { - const char var[]= "temporal_current_timestamp"; - sys_var *sv= intern_find_sys_var(var, sizeof(var) - 1); - DBUG_ASSERT(sv); - const char *data= *(char **)sv->option.value; - DBUG_ASSERT(data); - if (0 == strcmp(data, "all")) - { - init(FOR_SYSTEM_TIME_ALL, UNIT_TIMESTAMP); - } - else if (0 != strcmp(data, "now")) - { - Item *ts= - create_temporal_literal(thd, data, strlen(data), system_charset_info, - MYSQL_TYPE_DATETIME, true); - if (!ts) + st_vers_current_time &in= thd->variables.vers_current_time; + type= in.type; + unit= UNIT_TIMESTAMP; + if (type != FOR_SYSTEM_TIME_UNSPECIFIED && type != FOR_SYSTEM_TIME_ALL) + { + DBUG_ASSERT(type == FOR_SYSTEM_TIME_AS_OF); + start= new (thd->mem_root) Item_datetime_literal(thd, &in.ltime, 6); + if (!start) return true; - init(FOR_SYSTEM_TIME_AS_OF, UNIT_TIMESTAMP, ts); } + else + start= NULL; + end= NULL; return false; } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index bedc32d6010..a3ce1fd19c6 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1986,6 +1986,7 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, TABLE *table= table_list->table; TABLE_SHARE *share= table->s; sql_mode_t sql_mode= thd->variables.sql_mode; + ulong vers_hide= thd->variables.vers_hide; bool foreign_db_mode= sql_mode & (MODE_POSTGRESQL | MODE_ORACLE | MODE_MSSQL | MODE_DB2 | MODE_MAXDB | MODE_ANSI); diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 9fb32174d1c..0b80684cd77 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -382,14 +382,14 @@ static Sys_var_charptr Sys_basedir( READ_ONLY GLOBAL_VAR(mysql_home_ptr), CMD_LINE(REQUIRED_ARG, 'b'), IN_FS_CHARSET, DEFAULT(0)); -static Sys_var_charptr sys_temporal_current_timestamp( - "temporal_current_timestamp", "Default AS OF value for versioned tables", - GLOBAL_VAR(temporal_current_timestamp), CMD_LINE(REQUIRED_ARG, 'b'), +static Sys_var_vers_asof Sys_vers_current_time( + "vers_current_time", "Default AS OF value for versioned tables", + SESSION_VAR(vers_current_time), CMD_LINE(REQUIRED_ARG, OPT_VERS_CURRENT_TIME), IN_FS_CHARSET, DEFAULT("now")); static Sys_var_mybool Sys_vers_force( "vers_force", "Force system versioning for all created tables", - GLOBAL_VAR(vers_force), CMD_LINE(OPT_ARG), DEFAULT(FALSE)); + SESSION_VAR(vers_force), CMD_LINE(OPT_ARG), DEFAULT(FALSE)); static const char *vers_hide_keywords[]= {"AUTO", "IMPLICIT", "FULL", "NEVER", NullS}; static Sys_var_enum Sys_vers_hide( @@ -398,7 +398,7 @@ static Sys_var_enum Sys_vers_hide( "IMPLICIT: hide implicit system fields in all queries; " "FULL: hide any system fields in all queries and hide versioning info in SHOW commands; " "NEVER: don't hide system fields", - GLOBAL_VAR(vers_hide), CMD_LINE(OPT_ARG), vers_hide_keywords, DEFAULT(VERS_HIDE_AUTO)); + SESSION_VAR(vers_hide), CMD_LINE(OPT_ARG), vers_hide_keywords, DEFAULT(VERS_HIDE_AUTO)); static Sys_var_ulonglong Sys_binlog_cache_size( "binlog_cache_size", "The size of the transactional cache for " diff --git a/sql/sys_vars.ic b/sql/sys_vars.ic index 780450b484b..76bf8631630 100644 --- a/sql/sys_vars.ic +++ b/sql/sys_vars.ic @@ -2485,3 +2485,165 @@ public: bool global_update(THD *thd, set_var *var); uchar *global_value_ptr(THD *thd, const LEX_STRING *base); }; + + +class Sys_var_vers_asof: public sys_var +{ +public: + Sys_var_vers_asof( + const char *name_arg, + const char *comment, + int flag_args, + ptrdiff_t off, + size_t size, + CMD_LINE getopt, + enum charset_enum is_os_charset_arg, + const char *def_val, + on_check_function on_check_func=0, + on_update_function on_update_func=0) : + sys_var( + &all_sys_vars, + name_arg, + comment, + flag_args, + off, + getopt.id, + getopt.arg_type, + SHOW_CHAR, + (intptr) def_val, + 0, + VARIABLE_NOT_IN_BINLOG, + on_check_func, + on_update_func, + 0) + { + option.var_type|= GET_STR; + if (global_update(def_val)) + { + DBUG_ASSERT(false); + } + } + + bool do_check(THD *thd, set_var *var) + { return false; } + + bool update(String &in, st_vers_current_time &out) + { + if (in.length() == 3 && + 0 == my_strcasecmp( + in.charset(), + "ALL", + in.ptr())) + { + out.type= FOR_SYSTEM_TIME_ALL; + } + else if (in.length() == 3 && + 0 == my_strcasecmp( + in.charset(), + "NOW", + in.ptr())) + { + out.type= FOR_SYSTEM_TIME_UNSPECIFIED; + } + else + { + MYSQL_TIME_STATUS status; + if (str_to_datetime( + in.ptr(), + in.length(), + &out.ltime, + flags, + &status) || + out.ltime.time_type != MYSQL_TIMESTAMP_DATETIME || + (status.warnings & ~MYSQL_TIME_NOTE_TRUNCATED) != 0) + { + return true; + } + out.type= FOR_SYSTEM_TIME_AS_OF; + } + return false; + } + bool update(THD *thd, set_var *var, st_vers_current_time &out) + { + Item *item= var->value; + + switch (item->result_type()) + { + case TIME_RESULT: + { + if (item->get_date(&out.ltime, 0)) + break; + out.type= FOR_SYSTEM_TIME_AS_OF; + return false; + } + + case STRING_RESULT: + { + String *str= item->val_str(); + if (!str || update(*str, out)) + break; + return false; + } + default: + break; + } + String *str= item->val_str(); + const char *cstr= str ? str->c_ptr_safe() : "NULL"; + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, cstr); + return true; + } + bool global_update(const char *in) + { + String s(in, &my_charset_utf8_general_ci); + return update(s, global_var(st_vers_current_time)); + } + bool option_updated() + { + return global_update(global_var(st_vers_current_time).str_value); + } + bool global_update(THD *thd, set_var *var) + { + return update(thd, var, global_var(st_vers_current_time)); + } + bool session_update(THD *thd, set_var *var) + { + return update(thd, var, session_var(thd, st_vers_current_time)); + } + uchar *valptr(THD *thd, st_vers_current_time &val) + { + switch (val.type) + { + case FOR_SYSTEM_TIME_UNSPECIFIED: + return (uchar*) thd->strdup("NOW"); + case FOR_SYSTEM_TIME_ALL: + return (uchar*) thd->strdup("ALL"); + case FOR_SYSTEM_TIME_AS_OF: + { + uchar *buf= (uchar*) thd->alloc(MAX_DATE_STRING_REP_LENGTH); + if (buf) + { + if (!my_datetime_to_str(&val.ltime, (char*) buf, 6)) + { + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "vers_current_time", "NULL (wrong datetime)"); + return (uchar*) thd->strdup("Error: wrong datetime"); + } + } + return buf; + } + default: + break; + } + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "vers_current_time", "NULL (wrong range type)"); + return (uchar*) thd->strdup("Error: wrong range type"); + } + void session_save_default(THD *thd, set_var *var) + { DBUG_ASSERT(false); } + void global_save_default(THD *thd, set_var *var) + { DBUG_ASSERT(false); } + uchar *session_value_ptr(THD *thd, const LEX_STRING *base) + { return valptr(thd, session_var(thd, st_vers_current_time)); } + uchar *global_value_ptr(THD *thd, const LEX_STRING *base) + { return valptr(thd, global_var(st_vers_current_time)); } + uchar *default_value_ptr(THD *thd) + { return (uchar *)option.def_value; } +}; diff --git a/sql/table.h b/sql/table.h index ba497f1c365..f6736658674 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1841,16 +1841,6 @@ class Item_in_subselect; 4) jtbm semi-join (jtbm_subselect != NULL) */ -enum vers_range_type_t -{ - FOR_SYSTEM_TIME_UNSPECIFIED = 0, - FOR_SYSTEM_TIME_AS_OF, - FOR_SYSTEM_TIME_FROM_TO, - FOR_SYSTEM_TIME_BETWEEN, - FOR_SYSTEM_TIME_ALL, - FOR_SYSTEM_TIME_BEFORE -}; - enum vers_range_unit_t { UNIT_TIMESTAMP = 0, -- cgit v1.2.1 From d85fa886768001e9bb4bd5f63eee9641aa8abc92 Mon Sep 17 00:00:00 2001 From: kevg Date: Fri, 31 Mar 2017 13:21:30 +0300 Subject: Misc: disable clang warning 'offset for non-POD type' --- sql/sys_vars.ic | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sql/sys_vars.ic b/sql/sys_vars.ic index 76bf8631630..27987a8d8b8 100644 --- a/sql/sys_vars.ic +++ b/sql/sys_vars.ic @@ -77,6 +77,11 @@ #define GET_HA_ROWS GET_ULONG #endif +// Disable warning caused by SESSION_VAR() macro +#ifdef __clang__ +#pragma clang diagnostic ignored "-Winvalid-offsetof" +#endif + /* special assert for sysvars. Tells the name of the variable, and fails even in non-debug builds. -- cgit v1.2.1 From 994cdf1b7ac2d6f375aade57d72f3c26d0da0376 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 17 Apr 2017 11:22:52 +0300 Subject: Parser: Oracle mode fix --- sql/sql_yacc_ora.yy | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index b30e47dca8f..f989e3b93ff 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -505,6 +505,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token FORCE_SYM %token FOREIGN /* SQL-2003-R */ %token FOR_SYM /* SQL-2003-R */ +%token FOR_SYSTEM_TIME_SYM /* INTERNAL */ %token FORMAT_SYM %token FOUND_SYM /* SQL-2003-R */ %token FROM @@ -735,6 +736,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token PARTITIONING_SYM %token PASSWORD_SYM %token PERCENT_RANK_SYM +%token PERIOD_SYM /* 32N2439 */ %token PERSISTENT_SYM %token PHASE_SYM %token PLUGINS_SYM @@ -761,6 +763,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token PURGE %token QUARTER_SYM %token QUERY_SYM +%token QUERY_FOR_SYM /* INTERNAL */ %token QUICK %token RAISE_SYM /* Oracle-PLSQL-R */ %token RANGE_SYM /* SQL-2003-R */ @@ -899,6 +902,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token SWAPS_SYM %token SWITCHES_SYM %token SYSDATE +%token SYSTEM /* 32N2439 */ +%token SYSTEM_TIME_SYM /* 32N2439 */ %token TABLES %token TABLESPACE %token TABLE_REF_PRIORITY @@ -967,6 +972,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token VARIANCE_SYM %token VARYING /* SQL-2003-R */ %token VAR_SAMP_SYM +%token VERSIONING_SYM /* 32N2439 */ %token VIA_SYM %token VIEW_SYM /* SQL-2003-N */ %token VIRTUAL_SYM @@ -979,8 +985,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token WINDOW_SYM %token WHILE_SYM %token WITH /* SQL-2003-R */ +%token WITHOUT /* SQL-2003-R */ %token WITH_CUBE_SYM /* INTERNAL */ %token WITH_ROLLUP_SYM /* INTERNAL */ +%token WITH_SYSTEM_SYM /* INTERNAL */ %token WORK_SYM /* SQL-2003-N */ %token WRAPPER_SYM %token WRITE_SYM /* SQL-2003-N */ -- cgit v1.2.1 From 4af3cb82e6767c087fc7a10f5d51c86f04bf86ee Mon Sep 17 00:00:00 2001 From: kevg Date: Wed, 5 Apr 2017 18:51:31 +0300 Subject: IB: MIN/MAX trx_id by querying VTQ with commit ts [closes #168] --- storage/innobase/vers/vers0vtq.cc | 59 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/storage/innobase/vers/vers0vtq.cc b/storage/innobase/vers/vers0vtq.cc index 66ffc69829a..41be8bf7801 100644 --- a/storage/innobase/vers/vers0vtq.cc +++ b/storage/innobase/vers/vers0vtq.cc @@ -201,6 +201,14 @@ operator== (const timeval &a, const timeval &b) return a.tv_sec == b.tv_sec && a.tv_usec == b.tv_usec; } +static +inline +bool +operator!= (const timeval &a, const timeval &b) +{ + return !(a == b); +} + static inline bool @@ -217,6 +225,52 @@ operator< (const timeval &a, const timeval &b) return b > a; } +static +trx_id_t +read_trx_id(const rec_t *rec) { + ulong len = 0; + const rec_t *field = rec_get_nth_field_old(rec, 1, &len); + DBUG_ASSERT(len == 8); + return mach_read_from_8(field); +} + +/** Find a row with given commit_ts but MAX()/MIN() trx_id +@param[in] mtr mini-transaction handler +@param[in, out] pcur btree cursor which may be changed by this function +@param[in] backwards search direction +@param[in] commit_ts target timestamp for records +@param[in] rec record buffer for pcur +*/ +static +void +find_best_match(mtr_t &mtr, btr_pcur_t &pcur, bool backwards, + timeval commit_ts, const rec_t *rec) { + btr_pcur_t best; + btr_pcur_init(&best); + btr_pcur_copy_stored_position(&best, &pcur); + trx_id_t best_trx_id = read_trx_id(rec); + + while (true) { + if (backwards ? !btr_pcur_move_to_prev_user_rec(&pcur, &mtr) + : !btr_pcur_move_to_next_user_rec(&pcur, &mtr)) + break; + + timeval tv; + rec = btr_pcur_get_rec(&pcur); + rec_get_timeval(rec, 0, tv); + if (tv != commit_ts) + break; + + trx_id_t trx_id = read_trx_id(rec); + if (backwards ? trx_id < best_trx_id : trx_id > best_trx_id) { + best_trx_id = trx_id; + btr_pcur_copy_stored_position(&best, &pcur); + } + } + + btr_pcur_copy_stored_position(&pcur, &best); + btr_pcur_free(&best); +} /** Query VTQ by COMMIT_TS. @param[in] thd MySQL thread @@ -298,9 +352,10 @@ vtq_query_commit_ts( rec = btr_pcur_get_rec(&pcur); rec_get_timeval(rec, 0, rec_ts); - if (rec_ts.tv_sec == commit_ts.tv_sec - && rec_ts.tv_usec == commit_ts.tv_usec) + if (rec_ts == commit_ts) { + find_best_match(mtr, pcur, backwards, commit_ts, rec); goto found; + } } else { rec_ts = commit_ts; } -- cgit v1.2.1 From ecd18bc099bceabe309a7d4a954f2f49bddb8604 Mon Sep 17 00:00:00 2001 From: kevg Date: Wed, 5 Apr 2017 21:37:31 +0300 Subject: SQL: allow FOR SYSTEM_TIME BEFORE for SELECT queries [closes #170] --- mysql-test/suite/versioning/r/truncate_history.result | 11 +++++++++-- mysql-test/suite/versioning/t/truncate_history.test | 6 +++--- sql/sql_select.cc | 8 -------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/mysql-test/suite/versioning/r/truncate_history.result b/mysql-test/suite/versioning/r/truncate_history.result index 667fb002d4b..4194406fa16 100644 --- a/mysql-test/suite/versioning/r/truncate_history.result +++ b/mysql-test/suite/versioning/r/truncate_history.result @@ -122,6 +122,9 @@ a 22 1 2 +select * from t for system_time before timestamp @ts1; +a +1 truncate t for system_time before timestamp @ts1; select * from t for system_time all; a @@ -144,6 +147,12 @@ a 22 1 2 +select * from t for system_time before timestamp @ts1; +a +select * from t for system_time before transaction 2000; +a +1 +2 truncate t for system_time before timestamp @ts1; select * from t for system_time all; a @@ -157,7 +166,5 @@ a 11 22 2 -select * from t for system_time before timestamp now(); -ERROR HY000: `FOR SYSTEM_TIME BEFORE` works only with `TRUNCATE` query type drop table t; drop procedure truncate_history_of_t; diff --git a/mysql-test/suite/versioning/t/truncate_history.test b/mysql-test/suite/versioning/t/truncate_history.test index d112af63df3..a512c432651 100644 --- a/mysql-test/suite/versioning/t/truncate_history.test +++ b/mysql-test/suite/versioning/t/truncate_history.test @@ -96,6 +96,7 @@ update t set a=11 where a=1; set @ts1=now(6); update t set a=22 where a=2; select * from t for system_time all; +select * from t for system_time before timestamp @ts1; truncate t for system_time before timestamp @ts1; select * from t for system_time all; truncate t for system_time before timestamp now(6); @@ -107,13 +108,12 @@ update t set a=11 where a=1; set @ts1=now(6); update t set a=22 where a=2; select * from t for system_time all; +select * from t for system_time before timestamp @ts1; +select * from t for system_time before transaction 2000; truncate t for system_time before timestamp @ts1; select * from t for system_time all; truncate t for system_time before timestamp now(6); select * from t for system_time all; ---error ER_VERS_WRONG_QUERY_TYPE -select * from t for system_time before timestamp now(); - drop table t; drop procedure truncate_history_of_t; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 6739d51f360..47de223d590 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -786,14 +786,6 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, table->vers_conditions.type == FOR_SYSTEM_TIME_UNSPECIFIED ? slex->vers_conditions : table->vers_conditions; - if (vers_conditions.type == FOR_SYSTEM_TIME_BEFORE && - thd->lex->sql_command != SQLCOM_TRUNCATE) - { - my_error(ER_VERS_WRONG_QUERY_TYPE, MYF(0), "FOR SYSTEM_TIME BEFORE", - "TRUNCATE"); - DBUG_RETURN(-1); - } - if (vers_conditions.type == FOR_SYSTEM_TIME_UNSPECIFIED) { if (vers_conditions.init_from_sysvar(thd)) -- cgit v1.2.1 From d64702d43a0913c0710347cc1c7f9a48293719df Mon Sep 17 00:00:00 2001 From: kevg Date: Tue, 11 Apr 2017 17:58:56 +0300 Subject: SQL: different results when querying a VIEW from PREPARED STATEMENT and without it [fixes #176] --- mysql-test/suite/versioning/r/view.result | 3 --- sql/sql_select.cc | 9 ++------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/mysql-test/suite/versioning/r/view.result b/mysql-test/suite/versioning/r/view.result index 258a2dcb92c..17ac0bc04e8 100644 --- a/mysql-test/suite/versioning/r/view.result +++ b/mysql-test/suite/versioning/r/view.result @@ -39,8 +39,6 @@ x drop prepare stmt; select * from vt1; x -2 -1 prepare stmt from 'select * from vt1'; execute stmt; x @@ -50,7 +48,6 @@ x 1 select * from vt1 for system_time as of timestamp @t1; x -2 1 prepare stmt from 'select * from vt1 for system_time as of timestamp @t1'; execute stmt; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 47de223d590..45dc3ea4583 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -703,11 +703,6 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, DBUG_RETURN(0); } - while (tables && tables->is_view() && !thd->stmt_arena->is_stmt_prepare()) - { - tables= tables->view->select_lex.table_list.first; - } - for (table= tables; table; table= table->next_local) { if (table->table && table->table->versioned()) @@ -16879,9 +16874,9 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List &fields, continue; // Some kind of const item } - if (type == Item::FIELD_ITEM) + if (type == Item::FIELD_ITEM || type == Item::REF_ITEM) { - Item_field *item_field= (Item_field *)item; + Item_field *item_field= (Item_field *)item->real_item(); Field *field= item_field->field; TABLE_SHARE *s= field->table->s; if (s->versioned) -- cgit v1.2.1 From 06ad9c01a618dc793fc4388c49a4a24204389276 Mon Sep 17 00:00:00 2001 From: kevg Date: Tue, 11 Apr 2017 18:19:01 +0300 Subject: Misc: unneeded code after c17b5a3c973dff544613043b74db7d131e0cb55a --- sql/handler.cc | 7 ------- 1 file changed, 7 deletions(-) diff --git a/sql/handler.cc b/sql/handler.cc index 13c4031b02d..b66e616dfda 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6038,9 +6038,6 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data) DBUG_ASSERT(new_data == table->record[0]); DBUG_ASSERT(old_data == table->record[1]); - // it is important to keep 'old_data' intact for versioning to work correctly on slave side - if (table->file->check_table_binlog_row_based(1) && table->versioned()) - memcpy(table->record[2], table->record[1], table->s->reclength); MYSQL_UPDATE_ROW_START(table_share->db.str, table_share->table_name.str); mark_trx_read_write(); increment_statistics(&SSV::ha_update_count); @@ -6053,11 +6050,7 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data) { rows_changed++; if (table->file->check_table_binlog_row_based(1)) - { - if (table->versioned()) - memcpy(table->record[1], table->record[2], table->s->reclength); error= binlog_log_row(table, old_data, new_data, log_func); - } } return error; } -- cgit v1.2.1 From a1d42a6f205bbac25c26e4776e1592369f54b391 Mon Sep 17 00:00:00 2001 From: kevg Date: Tue, 11 Apr 2017 18:28:24 +0300 Subject: Misc: code cleanup --- sql/sql_update.cc | 3 ++- storage/innobase/vers/vers0vtq.cc | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/sql/sql_update.cc b/sql/sql_update.cc index c6e2736f4ce..b5f4d593a10 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -366,7 +366,8 @@ int mysql_update(THD *thd, { DBUG_RETURN(1); } - bool has_vers_fields= check_has_vers_fields(fields); + bool has_vers_fields= + table->versioned() ? check_has_vers_fields(fields) : false; if (check_key_in_view(thd, table_list)) { my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "UPDATE"); diff --git a/storage/innobase/vers/vers0vtq.cc b/storage/innobase/vers/vers0vtq.cc index 41be8bf7801..0e500234008 100644 --- a/storage/innobase/vers/vers0vtq.cc +++ b/storage/innobase/vers/vers0vtq.cc @@ -243,8 +243,13 @@ read_trx_id(const rec_t *rec) { */ static void -find_best_match(mtr_t &mtr, btr_pcur_t &pcur, bool backwards, - timeval commit_ts, const rec_t *rec) { +find_best_match( + mtr_t &mtr, + btr_pcur_t &pcur, + bool backwards, + timeval commit_ts, + const rec_t *rec) +{ btr_pcur_t best; btr_pcur_init(&best); btr_pcur_copy_stored_position(&best, &pcur); -- cgit v1.2.1 From ecc6cd95c455b5cff25db1e2825a238d73256fd8 Mon Sep 17 00:00:00 2001 From: kevg Date: Tue, 11 Apr 2017 19:37:48 +0300 Subject: SQL: Default 'simple' algorithm for InnoDB 'AS OF' [closes #175] --- .../suite/versioning/r/truncate_history.result | 3 +-- sql/sql_class.h | 1 + sql/sql_select.cc | 24 +++++++++++----------- sql/sys_vars.cc | 6 ++++++ storage/heap/ha_heap.cc | 5 +++++ 5 files changed, 25 insertions(+), 14 deletions(-) diff --git a/mysql-test/suite/versioning/r/truncate_history.result b/mysql-test/suite/versioning/r/truncate_history.result index 4194406fa16..e0bf8816483 100644 --- a/mysql-test/suite/versioning/r/truncate_history.result +++ b/mysql-test/suite/versioning/r/truncate_history.result @@ -149,6 +149,7 @@ a 2 select * from t for system_time before timestamp @ts1; a +1 select * from t for system_time before transaction 2000; a 1 @@ -158,13 +159,11 @@ select * from t for system_time all; a 11 22 -1 2 truncate t for system_time before timestamp now(6); select * from t for system_time all; a 11 22 -2 drop table t; drop procedure truncate_history_of_t; diff --git a/sql/sql_class.h b/sql/sql_class.h index e3601f141fa..303992c40d8 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -710,6 +710,7 @@ typedef struct system_variables st_vers_current_time vers_current_time; my_bool vers_force; ulong vers_hide; + my_bool vers_innodb_algorithm_simple; } SV; /** diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 45dc3ea4583..578fdc753a7 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -771,8 +771,6 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, } } - const static bool vers_simple_select= false; - for (table= tables; table; table= table->next_local) { if (table->table && table->table->versioned()) @@ -831,7 +829,10 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, newx Item_field(thd, &slex->context, table->db, table->alias, fend); Item *row_end2= row_end; - if (table->table->versioned_by_sql()) + bool tmp_from_ib= + table->table->s->table_category == TABLE_CATEGORY_TEMPORARY && + table->table->vers_start_field()->type() == MYSQL_TYPE_LONGLONG; + if (table->table->versioned_by_sql() && !tmp_from_ib) { if (vers_conditions.unit == UNIT_TRX_ID) { @@ -839,8 +840,9 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, DBUG_RETURN(-1); } } - else if (vers_simple_select && vers_conditions.unit == UNIT_TIMESTAMP - && vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED) + else if (thd->variables.vers_innodb_algorithm_simple && + vers_conditions.unit == UNIT_TIMESTAMP && + vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED) { DBUG_ASSERT(table->table->s && table->table->s->db_plugin); handlerton *hton= plugin_hton(table->table->s->db_plugin); @@ -859,19 +861,17 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, } Item *cond1= 0, *cond2= 0, *curr= 0; - // Temporary tables of type HEAP can be created from INNODB tables and - // thus will have uint64 type of sys_trx_(start|end) field. + // Temporary tables of can be created from INNODB tables and thus will + // have uint64 type of sys_trx_(start|end) field. // They need special handling. TABLE *t= table->table; - if ((t->s->table_category == TABLE_CATEGORY_TEMPORARY - ? t->vers_start_field()->type() != MYSQL_TYPE_LONGLONG - : t->versioned_by_sql()) || - vers_simple_select) + if (tmp_from_ib || t->versioned_by_sql() || + thd->variables.vers_innodb_algorithm_simple) { switch (vers_conditions.type) { case FOR_SYSTEM_TIME_UNSPECIFIED: - if (table->table->versioned_by_sql()) + if (table->table->versioned_by_sql() && !tmp_from_ib) { MYSQL_TIME max_time; thd->variables.time_zone->gmt_sec_to_TIME(&max_time, TIMESTAMP_MAX_VALUE); diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 0b80684cd77..f1a674388fc 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -400,6 +400,12 @@ static Sys_var_enum Sys_vers_hide( "NEVER: don't hide system fields", SESSION_VAR(vers_hide), CMD_LINE(OPT_ARG), vers_hide_keywords, DEFAULT(VERS_HIDE_AUTO)); +static Sys_var_mybool Sys_vers_innodb_algorithm_simple( + "vers_innodb_algorithm_simple", + "Use simple algorithm of timestamp handling in InnoDB instead of TRX_SEES", + SESSION_VAR(vers_innodb_algorithm_simple), CMD_LINE(OPT_ARG), + DEFAULT(TRUE)); + static Sys_var_ulonglong Sys_binlog_cache_size( "binlog_cache_size", "The size of the transactional cache for " "updates to transactional engines for the binary log. " diff --git a/storage/heap/ha_heap.cc b/storage/heap/ha_heap.cc index e87c878d11b..b37ddd1bcb7 100644 --- a/storage/heap/ha_heap.cc +++ b/storage/heap/ha_heap.cc @@ -27,6 +27,9 @@ #include "heapdef.h" #include "sql_base.h" // enum_tdc_remove_table_type +bool vtq_query_trx_id(THD *thd, void *out, ulonglong in_trx_id, + vtq_field_t field); + static handler *heap_create_handler(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root); @@ -56,6 +59,8 @@ int heap_init(void *p) heap_hton->panic= heap_panic; heap_hton->flags= HTON_CAN_RECREATE; + heap_hton->vers_query_trx_id = vtq_query_trx_id; + return 0; } -- cgit v1.2.1 From e72e3cd01f38ed51c7c7b8228d01b593b330de7f Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 12 Apr 2017 23:19:13 +0300 Subject: IB: redundant btr_pcur_move_to_prev_page() removed --- storage/innobase/btr/btr0pcur.cc | 60 ------------------------------------- storage/innobase/include/btr0pcur.h | 11 ------- 2 files changed, 71 deletions(-) diff --git a/storage/innobase/btr/btr0pcur.cc b/storage/innobase/btr/btr0pcur.cc index 1fc2c99bde4..fea46590853 100644 --- a/storage/innobase/btr/btr0pcur.cc +++ b/storage/innobase/btr/btr0pcur.cc @@ -452,66 +452,6 @@ btr_pcur_move_to_next_page( ut_d(page_check_dir(next_page)); } -/*********************************************************//** -Moves the persistent cursor to the last record on the previous page. Releases the -latch on the current page, and bufferunfixes it. Note that there must not be -modifications on the current page, as then the x-latch can be released only in -mtr_commit. */ -UNIV_INTERN -void -btr_pcur_move_to_prev_page( -/*=======================*/ - btr_pcur_t* cursor, /*!< in: persistent cursor; must be on the - last record of the current page */ - mtr_t* mtr) /*!< in: mtr */ -{ - ulint prev_page_no; - page_t* page; - buf_block_t* prev_block; - page_t* prev_page; - ulint mode; - - ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED); - ut_ad(cursor->latch_mode != BTR_NO_LATCHES); - ut_ad(btr_pcur_is_before_first_on_page(cursor)); - - cursor->old_stored = false; - - page = btr_pcur_get_page(cursor); - prev_page_no = btr_page_get_prev(page, mtr); - - ut_ad(prev_page_no != FIL_NULL); - - mode = cursor->latch_mode; - switch (mode) { - case BTR_SEARCH_TREE: - mode = BTR_SEARCH_LEAF; - break; - case BTR_MODIFY_TREE: - mode = BTR_MODIFY_LEAF; - } - - buf_block_t* block = btr_pcur_get_block(cursor); - - prev_block = btr_block_get( - page_id_t(block->page.id.space(), prev_page_no), - block->page.size, mode, - btr_pcur_get_btr_cur(cursor)->index, mtr); - - prev_page = buf_block_get_frame(prev_block); -#ifdef UNIV_BTR_DEBUG - ut_a(page_is_comp(prev_page) == page_is_comp(page)); - ut_a(btr_page_get_next(prev_page, mtr) - == btr_pcur_get_block(cursor)->page.id.page_no()); -#endif /* UNIV_BTR_DEBUG */ - - btr_leaf_page_release(btr_pcur_get_block(cursor), mode, mtr); - - page_cur_set_after_last(prev_block, btr_pcur_get_page_cur(cursor)); - - ut_d(page_check_dir(prev_page)); -} - /*********************************************************//** Moves the persistent cursor backward if it is on the first record of the page. Commits mtr. Note that to prevent a possible deadlock, the operation diff --git a/storage/innobase/include/btr0pcur.h b/storage/innobase/include/btr0pcur.h index 6e85d01c19f..3b75f3e176b 100644 --- a/storage/innobase/include/btr0pcur.h +++ b/storage/innobase/include/btr0pcur.h @@ -359,17 +359,6 @@ btr_pcur_move_to_next_page( last record of the current page */ mtr_t* mtr); /*!< in: mtr */ /*********************************************************//** -Moves the persistent cursor to the last record on the previous page. -Releases the latch on the current page, and bufferunfixes it. -Note that there must not be modifications on the current page, -as then the x-latch can be released only in mtr_commit. */ -void -btr_pcur_move_to_prev_page( -/*=======================*/ - btr_pcur_t* cursor, /*!< in: persistent cursor; must be on the - last record of the current page */ - mtr_t* mtr); /*!< in: mtr */ -/*********************************************************//** Moves the persistent cursor backward if it is on the first record of the page. Releases the latch on the current page, and bufferunfixes it. Note that to prevent a possible deadlock, the operation first -- cgit v1.2.1 From 915963ba306b209c9428bee3a548e7a07ac81094 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Fri, 14 Apr 2017 11:07:58 +0300 Subject: SQL: SIGABRT fix on versioned partitioning error [fixes #177] --- sql/table.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/table.cc b/sql/table.cc index 6470d5dfa4a..c4f3a05f5c5 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -3448,6 +3448,7 @@ partititon_err: if (err) { + outparam->file->ha_close(); error= OPEN_FRM_OPEN_ERROR; error_reported= true; goto err; -- cgit v1.2.1 From 6ac4dfedf4c60c2780e2271f4d135089df39d4aa Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 17 Apr 2017 12:42:49 +0300 Subject: Tests: sys_vars.sysvars_server_notembedded result (3) Related to #175 --- .../suite/sys_vars/r/sysvars_server_notembedded.result | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result index 5e8bacbc4d0..5a9734c73a4 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result @@ -5161,6 +5161,20 @@ NUMERIC_BLOCK_SIZE NULL ENUM_VALUE_LIST AUTO,IMPLICIT,FULL,NEVER READ_ONLY NO COMMAND_LINE_ARGUMENT OPTIONAL +VARIABLE_NAME VERS_INNODB_ALGORITHM_SIMPLE +SESSION_VALUE ON +GLOBAL_VALUE ON +GLOBAL_VALUE_ORIGIN COMPILE-TIME +DEFAULT_VALUE ON +VARIABLE_SCOPE SESSION +VARIABLE_TYPE BOOLEAN +VARIABLE_COMMENT Use simple algorithm of timestamp handling in InnoDB instead of TRX_SEES +NUMERIC_MIN_VALUE NULL +NUMERIC_MAX_VALUE NULL +NUMERIC_BLOCK_SIZE NULL +ENUM_VALUE_LIST OFF,ON +READ_ONLY NO +COMMAND_LINE_ARGUMENT OPTIONAL VARIABLE_NAME WAIT_TIMEOUT SESSION_VALUE 28800 GLOBAL_VALUE 28800 -- cgit v1.2.1 From 7d2ed77e31c18c28fa891699ae4dafcb3b087afe Mon Sep 17 00:00:00 2001 From: kevg Date: Mon, 17 Apr 2017 20:35:39 +0300 Subject: SQL: SIGSEGV in create_tmp_table() [fixes #179] tests are in main,rpl suites --- sql/sql_select.cc | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 578fdc753a7..d1d0d08d69a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -16876,15 +16876,18 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List &fields, if (type == Item::FIELD_ITEM || type == Item::REF_ITEM) { - Item_field *item_field= (Item_field *)item->real_item(); - Field *field= item_field->field; - TABLE_SHARE *s= field->table->s; - if (s->versioned) + if (item->real_item()->type() == Item::FIELD_ITEM) { - if (field->flags & VERS_SYS_START_FLAG) - sys_trx_start= new_field; - else if (field->flags & VERS_SYS_END_FLAG) - sys_trx_end= new_field; + Item_field *item_field= (Item_field *)item->real_item(); + Field *field= item_field->field; + TABLE_SHARE *s= field->table->s; + if (s->versioned) + { + if (field->flags & VERS_SYS_START_FLAG) + sys_trx_start= new_field; + else if (field->flags & VERS_SYS_END_FLAG) + sys_trx_end= new_field; + } } } if (type == Item::TYPE_HOLDER) -- cgit v1.2.1 From 27a6ef0a9e3185db5bb59e2706fc3f3324c37b27 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 19 Apr 2017 16:34:36 +0300 Subject: IB,SQL: Innopart UPDATE [fixes #178] --- mysql-test/suite/versioning/r/partition.result | 146 +++++++++++++++++++-- .../suite/versioning/t/partition.combinations | 3 - mysql-test/suite/versioning/t/partition.test | 58 +++++++- sql/partition_info.cc | 1 + storage/innobase/handler/ha_innodb.cc | 8 +- storage/innobase/handler/ha_innodb.h | 5 + storage/innobase/handler/ha_innopart.h | 40 ++++++ 7 files changed, 236 insertions(+), 25 deletions(-) diff --git a/mysql-test/suite/versioning/r/partition.result b/mysql-test/suite/versioning/r/partition.result index f4c8ce3b286..ff9f583042a 100644 --- a/mysql-test/suite/versioning/r/partition.result +++ b/mysql-test/suite/versioning/r/partition.result @@ -1,3 +1,65 @@ +set @@session.time_zone='+00:00'; +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +create procedure if not exists verify_vtq() +begin +set @i= 0; +select +@i:= @i + 1 as No, +trx_id > 0 as A, +commit_id >= trx_id as B, +begin_ts > '1-1-1 0:0:0' as C, +commit_ts > begin_ts as D +from information_schema.innodb_vtq +where trx_id > @start_trx_id; +select ifnull(max(trx_id), 0) +into @start_trx_id +from information_schema.innodb_vtq; +end~~ +create function if not exists default_engine() +returns varchar(255) +deterministic +begin +declare e varchar(255); +select lower(engine) from information_schema.engines where support='DEFAULT' into e; +return e; +end~~ +create function if not exists sys_datatype() +returns varchar(255) +deterministic +begin +if default_engine() = 'innodb' then +return 'bigint unsigned'; +elseif default_engine() = 'myisam' then +return 'timestamp(6)'; +end if; +return NULL; +end~~ +create function if not exists sys_commit_ts(sys_field varchar(255)) +returns varchar(255) +deterministic +begin +if default_engine() = 'innodb' then +return concat('vtq_commit_ts(', sys_field, ')'); +elseif default_engine() = 'myisam' then +return sys_field; +end if; +return NULL; +end~~ +create procedure if not exists innodb_verify_vtq(recs int) +begin +declare i int default 1; +if default_engine() = 'innodb' then +call verify_vtq; +elseif default_engine() = 'myisam' then +create temporary table tmp (No int, A bool, B bool, C bool, D bool); +while i <= recs do +insert into tmp values (i, 1, 1, 1, 1); +set i= i + 1; +end while; +select * from tmp; +drop table tmp; +end if; +end~~ create table t1 (x int) with system versioning partition by range columns (x) ( @@ -90,21 +152,78 @@ ERROR HY000: Wrong parameters for `BY SYSTEM_TIME`: `AS OF NOW` partition can no alter table t1 drop partition p1; alter table t1 drop partition p0; ERROR HY000: Wrong parameters for `BY SYSTEM_TIME`: one `AS OF NOW` and at least one `VERSIONING` partition required +set @now= now(6); insert into t1 values (1); -select * from t1; -x +set @ts_start= sys_commit_ts('sys_trx_start'); +set @ts_end= sys_commit_ts('sys_trx_end'); +set @str= concat('select x, ', @ts_start, ' < @now as A, ', @ts_end, ' > @now as B from t1 partition (p0) for system_time all'); +prepare select_p0 from @str; +set @str= concat('select x, ', @ts_start, ' > @now as C, ', @ts_end, ' = timestamp\'2038-01-19 03:14:07\' as D from t1 partition (pn) for system_time all'); +prepare select_pn from @str; +execute select_p0; +x A B +execute select_pn; +x C D +1 1 1 +set @str= concat('select ', @ts_start, ' from t1 partition (pn) into @ts0'); +prepare stmt from @str; +execute stmt; +drop prepare stmt; +set @now= now(6); +delete from t1; +execute select_p0; +x A B +1 1 1 +execute select_pn; +x C D +set @str= concat('select ', @ts_start, ' from t1 partition (p0) for system_time all into @ts1'); +prepare stmt from @str; +execute stmt; +drop prepare stmt; +select @ts0 = @ts1; +@ts0 = @ts1 1 -select * from t1 partition (p0); -x -select * from t1 partition (pn); -x +set @now= now(6); +insert into t1 values (2); +execute select_p0; +x A B +1 1 0 +execute select_pn; +x C D +2 1 1 +set @str= concat('select ', @ts_start, ' from t1 partition (pn) into @ts0'); +prepare stmt from @str; +execute stmt; +drop prepare stmt; +set @now= now(6); +update t1 set x = x + 1; +execute select_p0; +x A B +1 1 0 +2 1 1 +execute select_pn; +x C D +3 1 1 +drop prepare select_p0; +drop prepare select_pn; +set @str= concat('select ', @ts_start, ' from t1 partition (p0) for system_time all where x = 2 into @ts1'); +prepare stmt from @str; +execute stmt; +drop prepare stmt; +set @str= concat('select ', @ts_end, ' from t1 partition (p0) for system_time all where x = 2 into @ts2'); +prepare stmt from @str; +execute stmt; +drop prepare stmt; +set @str= concat('select ', @ts_start, ' from t1 partition (pn) into @ts3'); +prepare stmt from @str; +execute stmt; +drop prepare stmt; +select @ts0 = @ts1; +@ts0 = @ts1 1 -delete from t1; -select * from t1 partition (p0) for system_time all; -x +select @ts2 = @ts3; +@ts2 = @ts3 1 -select * from t1 partition (pn) for system_time all; -x create or replace table t1 (x int) with system versioning partition by system_time limit 1 ( @@ -190,3 +309,8 @@ select * from t1 partition (p1sp1) for system_time all; x 2 drop table t1; +drop procedure verify_vtq; +drop procedure innodb_verify_vtq; +drop function default_engine; +drop function sys_commit_ts; +drop function sys_datatype; diff --git a/mysql-test/suite/versioning/t/partition.combinations b/mysql-test/suite/versioning/t/partition.combinations index 4c1c009e7be..d79429f34f7 100644 --- a/mysql-test/suite/versioning/t/partition.combinations +++ b/mysql-test/suite/versioning/t/partition.combinations @@ -1,10 +1,7 @@ [innodb] -innodb partition default-storage-engine=innodb [myisam] -skip-innodb partition default-storage-engine=myisam - diff --git a/mysql-test/suite/versioning/t/partition.test b/mysql-test/suite/versioning/t/partition.test index e0500284a6f..6dc7f56923b 100644 --- a/mysql-test/suite/versioning/t/partition.test +++ b/mysql-test/suite/versioning/t/partition.test @@ -1,3 +1,5 @@ +-- source suite/versioning/common.inc + ### check System Versioning and conventional partitioning create table t1 (x int) @@ -83,15 +85,57 @@ alter table t1 drop partition p1; --error ER_VERS_WRONG_PARAMS alter table t1 drop partition p0; -# insertion, deletion +# insert, delete, update +set @now= now(6); insert into t1 values (1); -select * from t1; -select * from t1 partition (p0); -select * from t1 partition (pn); +set @ts_start= sys_commit_ts('sys_trx_start'); +set @ts_end= sys_commit_ts('sys_trx_end'); +set @str= concat('select x, ', @ts_start, ' < @now as A, ', @ts_end, ' > @now as B from t1 partition (p0) for system_time all'); +prepare select_p0 from @str; +set @str= concat('select x, ', @ts_start, ' > @now as C, ', @ts_end, ' = timestamp\'2038-01-19 03:14:07\' as D from t1 partition (pn) for system_time all'); +prepare select_pn from @str; +execute select_p0; +execute select_pn; + +set @str= concat('select ', @ts_start, ' from t1 partition (pn) into @ts0'); +prepare stmt from @str; execute stmt; drop prepare stmt; + +set @now= now(6); delete from t1; -select * from t1 partition (p0) for system_time all; -select * from t1 partition (pn) for system_time all; +execute select_p0; +execute select_pn; + +set @str= concat('select ', @ts_start, ' from t1 partition (p0) for system_time all into @ts1'); +prepare stmt from @str; execute stmt; drop prepare stmt; + +select @ts0 = @ts1; + +set @now= now(6); +insert into t1 values (2); +execute select_p0; +execute select_pn; + +set @str= concat('select ', @ts_start, ' from t1 partition (pn) into @ts0'); +prepare stmt from @str; execute stmt; drop prepare stmt; + +set @now= now(6); +update t1 set x = x + 1; +execute select_p0; +execute select_pn; + +drop prepare select_p0; +drop prepare select_pn; + +set @str= concat('select ', @ts_start, ' from t1 partition (p0) for system_time all where x = 2 into @ts1'); +prepare stmt from @str; execute stmt; drop prepare stmt; +set @str= concat('select ', @ts_end, ' from t1 partition (p0) for system_time all where x = 2 into @ts2'); +prepare stmt from @str; execute stmt; drop prepare stmt; +set @str= concat('select ', @ts_start, ' from t1 partition (pn) into @ts3'); +prepare stmt from @str; execute stmt; drop prepare stmt; + +select @ts0 = @ts1; +select @ts2 = @ts3; # rotation by LIMIT create or replace table t1 (x int) @@ -150,3 +194,5 @@ select * from t1 partition (p1sp0) for system_time all; select * from t1 partition (p1sp1) for system_time all; drop table t1; + +-- source suite/versioning/common_finish.inc diff --git a/sql/partition_info.cc b/sql/partition_info.cc index c1a792c87e0..2b1bc41931d 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -1211,6 +1211,7 @@ bool partition_info::vers_setup_2(THD * thd, bool is_create_table_ind) } else if (vers_scan_min_max(thd, el)) { + table->s->stat_trx= NULL; // may be a leak on endless table open error= true; break; } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index ac3e2edf304..bd8eb6b4d88 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -8718,8 +8718,7 @@ no_commit: innobase_srv_conc_enter_innodb(m_prebuilt); vers_set_fields = table->versioned() && ( - (sql_command != SQLCOM_DELETE || - (m_int_table_flags & HA_INNOPART_DISABLED_TABLE_FLAGS)) && + !is_innopart() && sql_command != SQLCOM_CREATE_TABLE) ? ROW_INS_VERSIONED : ROW_INS_NORMAL; @@ -9527,8 +9526,7 @@ ha_innobase::update_row( innobase_srv_conc_enter_innodb(m_prebuilt); - vers_set_fields = m_prebuilt->upd_node->versioned && - (m_int_table_flags & HA_INNOPART_DISABLED_TABLE_FLAGS); + vers_set_fields = m_prebuilt->upd_node->versioned && !is_innopart(); error = row_update_for_mysql((byte*) old_row, m_prebuilt, vers_set_fields); @@ -9652,7 +9650,7 @@ ha_innobase::delete_row( bool vers_set_fields = table->versioned() && - (m_int_table_flags & HA_INNOPART_DISABLED_TABLE_FLAGS) && + !is_innopart() && table->vers_end_field()->is_max(); error = row_update_for_mysql( diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index f4600a6415b..94155fdf18b 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -519,6 +519,11 @@ protected: /** If mysql has locked with external_lock() */ bool m_mysql_has_locked; + + bool is_innopart() + { + return m_share == NULL; + } }; diff --git a/storage/innobase/handler/ha_innopart.h b/storage/innobase/handler/ha_innopart.h index ab445cf25ca..ef66420acb1 100644 --- a/storage/innobase/handler/ha_innopart.h +++ b/storage/innobase/handler/ha_innopart.h @@ -1119,6 +1119,19 @@ private: write_row( uchar* record) { + if (table->versioned()) + { + trx_t* trx = thd_to_trx(ha_thd()); + if (!trx->id) + trx_start_if_not_started_xa(trx, true); + ut_a(trx->id); + ut_a(table->record[0] == record); + bitmap_set_bit(table->write_set, table->vers_start_field()->field_index); + bitmap_set_bit(table->write_set, table->vers_end_field()->field_index); + table->vers_start_field()->set_notnull(); + table->vers_start_field()->store(trx->id, true); + table->vers_end_field()->set_max(); + } return(Partition_helper::ph_write_row(record)); } @@ -1127,6 +1140,31 @@ private: const uchar* old_record, uchar* new_record) { + int err; + if (table->versioned() && table->vers_end_field()->is_max()) { + trx_t* trx = thd_to_trx(ha_thd()); + if (!trx->id) + trx_start_if_not_started_xa(trx, true); + ut_a(trx->id); + ut_a(table->record[0] == new_record); + ut_a(table->record[1] == old_record); + store_record(table, record[2]); // store new_record + restore_record(table, record[1]); // restore old_record + // modify and insert old_record + bitmap_set_bit(table->write_set, table->vers_end_field()->field_index); + table->vers_end_field()->set_notnull(); + table->vers_end_field()->store(trx->id, true); + err = Partition_helper::ph_write_row(const_cast(table->record[0])); + restore_record(table, record[2]); // restore new_record + if (err) + return err; + table->vers_start_field()->store(trx->id, true); + } + if (unlikely(get_part_for_delete(old_record, + new_record, + m_part_info, + &m_last_part))) + return HA_ERR_INTERNAL_ERROR; return(Partition_helper::ph_update_row(old_record, new_record)); } @@ -1145,6 +1183,8 @@ private: ut_a(table->record[0] == record); store_record(table, record[1]); ut_a(trx->id); + bitmap_set_bit(table->write_set, table->vers_end_field()->field_index); + table->vers_end_field()->set_notnull(); table->vers_end_field()->store(trx->id, true); return Partition_helper::ph_update_row(table->record[1], table->record[0]); } -- cgit v1.2.1 From 1e8a81dea67a66e49dcfe048f4339159c851c46d Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 25 Apr 2017 15:02:48 +0300 Subject: SQL: CREATE VIEW and misc improvements [fixes #183] --- mysql-test/suite/versioning/r/select.result | 2 + mysql-test/suite/versioning/r/view.result | 46 +++++----- mysql-test/suite/versioning/t/select.test | 3 + mysql-test/suite/versioning/t/view.test | 37 ++++---- sql/share/errmsg-utf8.txt | 9 ++ sql/sql_base.cc | 5 +- sql/sql_lex.cc | 22 +++++ sql/sql_lex.h | 3 +- sql/sql_select.cc | 29 +++--- sql/sql_view.cc | 137 +++++++++++++++++++++++----- sql/table.h | 22 ++++- 11 files changed, 233 insertions(+), 82 deletions(-) diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index dda7c08e64c..de92274e17f 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -436,6 +436,8 @@ x y 1 1 2 1 3 1 +select * from t1 for system_time all, t2 for system_time all query for system_time all; +ERROR HY000: Wrong versioned query: unused `QUERY FOR SYSTEM_TIME` clause! drop view v1; drop table t1, t2; call innodb_verify_vtq(27); diff --git a/mysql-test/suite/versioning/r/view.result b/mysql-test/suite/versioning/r/view.result index 17ac0bc04e8..3065b244cda 100644 --- a/mysql-test/suite/versioning/r/view.result +++ b/mysql-test/suite/versioning/r/view.result @@ -8,7 +8,7 @@ set @vt1= concat("create view vt1 as select * from t1 for system_time as of time prepare stmt from @vt1; execute stmt; drop prepare stmt; -set @vt2= concat("create view vt2 as select * from t1 for system_time as of timestamp '", @t2, "'"); +set @vt2= concat("create view vt2 as select *, sys_trx_end from t1 for system_time as of timestamp '", @t2, "'"); prepare stmt from @vt2; execute stmt; drop prepare stmt; @@ -76,10 +76,6 @@ x select * from vt1 for system_time all; x 3 -create view error_view as select *, sys_trx_start from t1; -ERROR 42S21: Duplicate column name 'sys_trx_start' -create view error_view as select *, sys_trx_end from t1; -ERROR 42S21: Duplicate column name 'sys_trx_end' create or replace table t1 (x int) with system versioning; insert into t1 values (1), (2); set @t1=now(6); @@ -91,27 +87,14 @@ set @tmp= concat("create or replace view vt1 as select * from t1 for system_time prepare stmt from @tmp; execute stmt; drop prepare stmt; -set @tmp= concat("create or replace view vvt1 as select * from vt1 for system_time as of timestamp '", @t2, "'"); -prepare stmt from @tmp; -execute stmt; -drop prepare stmt; -set @tmp= concat("create or replace view vvvt1 as select * from vvt1 for system_time as of timestamp '", @t3, "'"); -prepare stmt from @tmp; -execute stmt; -drop prepare stmt; select * from vt1 for system_time all; x 1 2 -select * from vvt1 for system_time all; -x -1 -select * from vvvt1 for system_time all; -x create or replace table t1 (x int) with system versioning; create or replace view vt1(c) as select x from t1; -create or replace table t1 (a int) with system versioning; -create or replace table t2 (b int) with system versioning; +create or replace table t1 (a int) with system versioning engine innodb; +create or replace table t2 (b int) with system versioning engine innodb; insert into t1 values (1); insert into t2 values (2); create or replace view vt12 as select * from t1 cross join t2; @@ -121,5 +104,24 @@ a b create or replace view vt12 as select * from t1 for system_time as of timestamp '0-0-0' cross join t2; select * from vt12; a b -drop view vt1, vvt1, vvvt1, vt12; -drop table t1, t2; +create or replace view vt1 as select a, t1.sys_trx_start, t2.sys_trx_end from t1, t2; +ERROR HY000: Creating VIEW `vt1` is prohibited: system fields from multiple tables `t1`, `t2` in query! +create or replace view vt1 as select a, t1.sys_trx_end, t2.sys_trx_end from t1, t2; +ERROR HY000: Creating VIEW `vt1` is prohibited: multiple end system fields `t1.sys_trx_end`, `t2.sys_trx_end` in query! +create or replace table t3 (x int); +create or replace view vt1 as select * from t1, t2, t3; +show create view vt1; +View Create View character_set_client collation_connection +vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`a` AS `a`,`t2`.`b` AS `b`,`t3`.`x` AS `x`,`t1`.`sys_trx_start` AS `sys_trx_start`,`t1`.`sys_trx_end` AS `sys_trx_end` from ((`t1` FOR SYSTEM_TIME ALL join `t2` FOR SYSTEM_TIME ALL) join `t3`) where `t1`.`sys_trx_end` = 18446744073709551615 and `t2`.`sys_trx_end` = 18446744073709551615 latin1 latin1_swedish_ci +create or replace view vt1 as select * from t3, t2, t1; +show create view vt1; +View Create View character_set_client collation_connection +vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t3`.`x` AS `x`,`t2`.`b` AS `b`,`t1`.`a` AS `a`,`t2`.`sys_trx_start` AS `sys_trx_start`,`t2`.`sys_trx_end` AS `sys_trx_end` from ((`t3` join `t2` FOR SYSTEM_TIME ALL) join `t1` FOR SYSTEM_TIME ALL) where `t2`.`sys_trx_end` = 18446744073709551615 and `t1`.`sys_trx_end` = 18446744073709551615 latin1 latin1_swedish_ci +create or replace view vt1 as select a, t2.sys_trx_end as endo from t3, t1, t2; +show create view vt1; +View Create View character_set_client collation_connection +vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`a` AS `a`,`t2`.`sys_trx_end` AS `endo`,`t2`.`sys_trx_start` AS `sys_trx_start` from ((`t3` join `t1` FOR SYSTEM_TIME ALL) join `t2` FOR SYSTEM_TIME ALL) where `t1`.`sys_trx_end` = 18446744073709551615 and `t2`.`sys_trx_end` = 18446744073709551615 latin1 latin1_swedish_ci +create or replace view vvt1 as select * from t1, t2, vt1; +ERROR HY000: Creating VIEW `vvt1` is prohibited: versioned VIEW `vt1` in query! +drop view vt1, vt12; +drop table t1, t2, t3; diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index 3f92546d1e4..37b6b8be89d 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -197,6 +197,9 @@ delete from t1 where x = 3; insert into t2 values (1); select * from t1, t2 query for system_time all; +--error ER_VERS_WRONG_QUERY +select * from t1 for system_time all, t2 for system_time all query for system_time all; + drop view v1; drop table t1, t2; diff --git a/mysql-test/suite/versioning/t/view.test b/mysql-test/suite/versioning/t/view.test index c284df3ec5e..64be35f70c0 100644 --- a/mysql-test/suite/versioning/t/view.test +++ b/mysql-test/suite/versioning/t/view.test @@ -12,7 +12,7 @@ delete from t1; set @vt1= concat("create view vt1 as select * from t1 for system_time as of timestamp '", @t1, "'"); prepare stmt from @vt1; execute stmt; drop prepare stmt; -set @vt2= concat("create view vt2 as select * from t1 for system_time as of timestamp '", @t2, "'"); +set @vt2= concat("create view vt2 as select *, sys_trx_end from t1 for system_time as of timestamp '", @t2, "'"); prepare stmt from @vt2; execute stmt; drop prepare stmt; select * from vt1 for system_time all; @@ -46,11 +46,6 @@ select * from vt1; select * from t1 for system_time all; select * from vt1 for system_time all; ---error ER_DUP_FIELDNAME -create view error_view as select *, sys_trx_start from t1; ---error ER_DUP_FIELDNAME -create view error_view as select *, sys_trx_end from t1; - create or replace table t1 (x int) with system versioning; insert into t1 values (1), (2); set @t1=now(6); @@ -61,20 +56,14 @@ set @t3=now(6); set @tmp= concat("create or replace view vt1 as select * from t1 for system_time as of timestamp '", @t1, "'"); prepare stmt from @tmp; execute stmt; drop prepare stmt; -set @tmp= concat("create or replace view vvt1 as select * from vt1 for system_time as of timestamp '", @t2, "'"); -prepare stmt from @tmp; execute stmt; drop prepare stmt; -set @tmp= concat("create or replace view vvvt1 as select * from vvt1 for system_time as of timestamp '", @t3, "'"); -prepare stmt from @tmp; execute stmt; drop prepare stmt; select * from vt1 for system_time all; -select * from vvt1 for system_time all; -select * from vvvt1 for system_time all; create or replace table t1 (x int) with system versioning; create or replace view vt1(c) as select x from t1; -create or replace table t1 (a int) with system versioning; -create or replace table t2 (b int) with system versioning; +create or replace table t1 (a int) with system versioning engine innodb; +create or replace table t2 (b int) with system versioning engine innodb; insert into t1 values (1); insert into t2 values (2); create or replace view vt12 as select * from t1 cross join t2; @@ -82,5 +71,21 @@ select * from vt12; create or replace view vt12 as select * from t1 for system_time as of timestamp '0-0-0' cross join t2; select * from vt12; -drop view vt1, vvt1, vvvt1, vt12; -drop table t1, t2; +--error ER_VERS_VIEW_PROHIBITED +create or replace view vt1 as select a, t1.sys_trx_start, t2.sys_trx_end from t1, t2; +--error ER_VERS_VIEW_PROHIBITED +create or replace view vt1 as select a, t1.sys_trx_end, t2.sys_trx_end from t1, t2; + +create or replace table t3 (x int); +create or replace view vt1 as select * from t1, t2, t3; +show create view vt1; +create or replace view vt1 as select * from t3, t2, t1; +show create view vt1; +create or replace view vt1 as select a, t2.sys_trx_end as endo from t3, t1, t2; +show create view vt1; + +--error ER_VERS_VIEW_PROHIBITED +create or replace view vvt1 as select * from t1, t2, vt1; + +drop view vt1, vt12; +drop table t1, t2, t3; diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 0aeaa058cf9..81651071c05 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7535,5 +7535,14 @@ ER_VERS_NOT_ALLOWED ER_VERS_WRONG_QUERY_TYPE eng "%`s works only with %`s query type" +ER_VERS_VIEW_PROHIBITED + eng "Creating VIEW %`s is prohibited!" + +ER_VERS_WRONG_QUERY + eng "Wrong versioned query: %s" + +WARN_VERS_ALIAS_TOO_LONG + eng "Auto generated alias for `%s.%s` is too long; using `%s`." + ER_WRONG_TABLESPACE_NAME 42000 eng "Incorrect tablespace name `%-.192s`" diff --git a/sql/sql_base.cc b/sql/sql_base.cc index d0c723af397..8cdced1cb09 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7582,7 +7582,6 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, if (!(item= field_iterator.create_item(thd))) DBUG_RETURN(TRUE); - /* This will be deprecated when HIDDEN feature will come to MariaDB. */ if (item->type() == Item::FIELD_ITEM) { Item_field *f= static_cast(item); @@ -7597,8 +7596,8 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, tl->vers_conditions.type == FOR_SYSTEM_TIME_UNSPECIFIED ? slex->vers_conditions.type : tl->vers_conditions.type; - if ((sys_field && vers_hide == VERS_HIDE_FULL && - thd->lex->sql_command != SQLCOM_CREATE_TABLE) || + if ((sys_field && (thd->lex->sql_command == SQLCOM_CREATE_VIEW || + vers_hide == VERS_HIDE_FULL && thd->lex->sql_command != SQLCOM_CREATE_TABLE)) || ((fl & HIDDEN_FLAG) && ( !sys_field || vers_hide == VERS_HIDE_IMPLICIT || diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 5f3c83eed71..7b61efa8fb8 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -7044,3 +7044,25 @@ bool LEX::sp_add_cfetch(THD *thd, const LEX_STRING &name) return true; return false; } + + +bool SELECT_LEX::vers_push_field(THD *thd, TABLE_LIST *table, const char* field_name) +{ + char buf[MAX_FIELD_NAME]; + Item_field *fld= new (thd->mem_root) Item_field(thd, &context, + table->db, table->alias, field_name); + if (!fld) + return true; + + item_list.push_back(fld); + + if (thd->lex->view_list.elements) + { + if (LEX_STRING *l= thd->make_lex_string(field_name, strlen(field_name))) + thd->lex->view_list.push_back(l); + else + return true; + } + + return false; +} diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 06aa248ee02..158130b5ddc 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -991,8 +991,9 @@ public: /* it is for correct printing SELECT options */ thr_lock_type lock_type; - /* System Versioning conditions */ + /* System Versioning */ vers_select_conds_t vers_conditions; + bool vers_push_field(THD *thd, TABLE_LIST *table, const char* field_name); void init_query(); void init_select(); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index d1d0d08d69a..5901d1d4d6f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -694,6 +694,7 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, TABLE_LIST *table; int versioned_tables= 0; + int slex_conds_used= 0; Query_arena *arena= 0, backup; if (!thd->stmt_arena->is_conventional() && @@ -707,7 +708,7 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, { if (table->table && table->table->versioned()) versioned_tables++; - else if (table->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED) + else if (table->vers_conditions) { my_error(ER_VERSIONING_REQUIRED, MYF(0), "`FOR SYSTEM_TIME` query"); DBUG_RETURN(-1); @@ -716,7 +717,7 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, if (versioned_tables == 0) { - if (slex->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED) + if (slex->vers_conditions) { my_error(ER_VERSIONING_REQUIRED, MYF(0), "`FOR SYSTEM_TIME` query"); DBUG_RETURN(-1); @@ -775,17 +776,17 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, { if (table->table && table->table->versioned()) { - vers_select_conds_t &vers_conditions= - table->vers_conditions.type == FOR_SYSTEM_TIME_UNSPECIFIED ? - slex->vers_conditions : table->vers_conditions; + vers_select_conds_t &vers_conditions= !table->vers_conditions? + (++slex_conds_used, slex->vers_conditions) : + table->vers_conditions; - if (vers_conditions.type == FOR_SYSTEM_TIME_UNSPECIFIED) + if (!vers_conditions) { if (vers_conditions.init_from_sysvar(thd)) DBUG_RETURN(-1); } - if (vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED) + if (vers_conditions) { switch (slex->lock_type) { @@ -804,9 +805,9 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, break; } - if (vers_conditions.type == FOR_SYSTEM_TIME_ALL) + if (vers_conditions == FOR_SYSTEM_TIME_ALL) continue; - } + } // if (vers_conditions) COND** dst_cond= where_expr; if (table->on_expr) @@ -979,6 +980,12 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, if (arena) thd->restore_active_arena(arena, &backup); + if (!slex_conds_used && slex->vers_conditions) + { + my_error(ER_VERS_WRONG_QUERY, MYF(0), "unused `QUERY FOR SYSTEM_TIME` clause!"); + DBUG_RETURN(-1); + } + DBUG_RETURN(0); #undef newx } @@ -16985,8 +16992,8 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List &fields, sys_trx_end->flags|= VERS_SYS_END_FLAG | HIDDEN_FLAG; share->versioned= true; share->field= table->field; - share->row_start_field= field_count - 2; - share->row_end_field= field_count - 1; + share->row_start_field= sys_trx_start->field_index; + share->row_end_field= sys_trx_end->field_index; } DBUG_ASSERT(fieldnr == (uint) (reg_field - table->field)); diff --git a/sql/sql_view.cc b/sql/sql_view.cc index d542a5710f6..37703a2bc11 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -453,38 +453,125 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, goto err; } - /* Implicitly add versioning fields if needed */ - { - TABLE_LIST *tl = tables; - while (tl && tl->is_view()) - tl = tl->view->select_lex.table_list.first; - if (tl && tl->table) + { /* System Versioning begin */ + TABLE_LIST *impli_table= NULL, *expli_table= NULL; + const char *impli_start, *impli_end; + Item_field *expli_start= NULL, *expli_end= NULL; + + for (TABLE_LIST *table= tables; table; table= table->next_local) { - TABLE_SHARE *s= tl->table->s; - if (s->versioned) + DBUG_ASSERT(!table->is_view() || table->view); + + // Any versioned table in VIEW will add `FOR SYSTEM_TIME ALL` + WHERE: + // if there are at least one versioned table then VIEW will contain FOR_SYSTEM_TIME_ALL + // (because it is in fact LEX used to parse its SELECT). + if (table->is_view() && table->view->vers_conditions == FOR_SYSTEM_TIME_ALL) { - const char *start= s->vers_start_field()->field_name; - const char *end = s->vers_end_field()->field_name; + my_printf_error( + ER_VERS_VIEW_PROHIBITED, + "Creating VIEW %`s is prohibited: versioned VIEW %`s in query!", MYF(0), + view->table_name, + table->table_name); + res= true; + goto err; + } + + if (!table->table || !table->table->versioned()) + continue; - select_lex->item_list.push_back(new (thd->mem_root) Item_field( - thd, &select_lex->context, tables->db, tables->alias, start)); - select_lex->item_list.push_back(new (thd->mem_root) Item_field( - thd, &select_lex->context, tables->db, tables->alias, end)); + const char *table_start= table->table->vers_start_field()->field_name; + const char *table_end= table->table->vers_end_field()->field_name; - if (lex->view_list.elements) + if (!impli_table) + { + impli_table= table; + impli_start= table_start; + impli_end= table_end; + } + + /* Implicitly add versioning fields if needed */ + Item *item; + List_iterator_fast it(select_lex->item_list); + + DBUG_ASSERT(table->alias); + while ((item= it++)) + { + if (item->real_item()->type() != Item::FIELD_ITEM) + continue; + Item_field *fld= (Item_field*) (item->real_item()); + if (fld->table_name && 0 != my_strcasecmp(table_alias_charset, table->alias, fld->table_name)) + continue; + DBUG_ASSERT(fld->field_name); + if (0 == my_strcasecmp(system_charset_info, table_start, fld->field_name)) { - if (LEX_STRING *s= thd->make_lex_string(start, strlen(start))) - lex->view_list.push_back(s); - else + if (expli_start) + { + my_printf_error( + ER_VERS_VIEW_PROHIBITED, + "Creating VIEW %`s is prohibited: multiple start system fields `%s.%s`, `%s.%s` in query!", MYF(0), + view->table_name, + expli_table->alias, + expli_start->field_name, + table->alias, + fld->field_name); + res= true; goto err; - if (LEX_STRING *s= thd->make_lex_string(end, strlen(end))) - lex->view_list.push_back(s); + } + if (expli_table) + { + if (expli_table != table) + { +expli_table_err: + my_printf_error( + ER_VERS_VIEW_PROHIBITED, + "Creating VIEW %`s is prohibited: system fields from multiple tables %`s, %`s in query!", MYF(0), + view->table_name, + expli_table->alias, + table->alias); + res= true; + goto err; + } + } else + expli_table= table; + expli_start= fld; + impli_end= table_end; + } + else if (0 == my_strcasecmp(system_charset_info, table_end, fld->field_name)) + { + if (expli_end) + { + my_printf_error( + ER_VERS_VIEW_PROHIBITED, + "Creating VIEW %`s is prohibited: multiple end system fields `%s.%s`, `%s.%s` in query!", MYF(0), + view->table_name, + expli_table->alias, + expli_end->field_name, + table->alias, + fld->field_name); + res= true; goto err; + } + if (expli_table) + { + if (expli_table != table) + goto expli_table_err; + } + else + expli_table= table; + expli_end= fld; + impli_start= table_start; } - } - } - } + } // while ((item= it++)) + } // for (TABLE_LIST *table) + + if (expli_table) + impli_table= expli_table; + if (!expli_start && select_lex->vers_push_field(thd, impli_table, impli_start)) + goto err; + if (!expli_end && select_lex->vers_push_field(thd, impli_table, impli_end)) + goto err; + } /* System Versioning end */ view= lex->unlink_first_table(&link_to_local); @@ -2071,8 +2158,8 @@ bool insert_view_fields(THD *thd, List *list, TABLE_LIST *view) { TABLE_SHARE *s= fld->context->table_list->table->s; if (s->versioned && - (!strcmp(fld->name, s->vers_start_field()->field_name) || - !strcmp(fld->name, s->vers_end_field()->field_name))) + (!strcmp(fld->field_name, s->vers_start_field()->field_name) || + !strcmp(fld->field_name, s->vers_end_field()->field_name))) continue; list->push_back(fld, thd->mem_root); } diff --git a/sql/table.h b/sql/table.h index f6736658674..68f3a2dfe75 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1512,31 +1512,32 @@ public: bool versioned() const { + DBUG_ASSERT(s); return s->versioned; } /* Versioned by SQL layer */ bool versioned_by_sql() const { - DBUG_ASSERT(file); + DBUG_ASSERT(s && file); return s->versioned && !file->versioned(); } bool versioned_by_engine() const { - DBUG_ASSERT(file); + DBUG_ASSERT(s && file); return s->versioned && file->versioned(); } Field *vers_start_field() const { - DBUG_ASSERT(s->versioned); + DBUG_ASSERT(s && s->versioned); return field[s->row_start_field]; } Field *vers_end_field() const { - DBUG_ASSERT(s->versioned); + DBUG_ASSERT(s && s->versioned); return field[s->row_end_field]; } @@ -1874,6 +1875,19 @@ struct vers_select_conds_t } bool init_from_sysvar(THD *thd); + + bool operator== (vers_range_type_t b) + { + return type == b; + } + bool operator!= (vers_range_type_t b) + { + return type != b; + } + operator bool() + { + return type != FOR_SYSTEM_TIME_UNSPECIFIED; + } }; struct LEX; -- cgit v1.2.1 From 122ffa22112ebc78a63e39cc2fcc7b9da3675926 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Thu, 27 Apr 2017 10:24:16 +0300 Subject: SQL(misc): Query_arena_stmt RAII --- sql/sql_class.cc | 13 +++++++++++++ sql/sql_class.h | 16 ++++++++++++++++ sql/sql_derived.cc | 5 +---- sql/sql_select.cc | 10 ++-------- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 1a422fd9966..052e5ae136d 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -7425,3 +7425,16 @@ bool Discrete_intervals_list::append(Discrete_interval *new_interval) } #endif /* !defined(MYSQL_CLIENT) */ + + +Query_arena_stmt::Query_arena_stmt(THD *_thd) : + thd(_thd) +{ + arena= thd->activate_stmt_arena_if_needed(&backup); +} + +Query_arena_stmt::~Query_arena_stmt() +{ + if (arena) + thd->restore_active_arena(arena, &backup); +} diff --git a/sql/sql_class.h b/sql/sql_class.h index 303992c40d8..b76b5cd6e60 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1024,6 +1024,22 @@ public: }; +class Query_arena_stmt +{ + THD *thd; + Query_arena backup; + Query_arena *arena; + +public: + Query_arena_stmt(THD *_thd); + ~Query_arena_stmt(); + bool arena_replaced() + { + return arena != NULL; + } +}; + + class Server_side_cursor; /** diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 43302498d57..eb99544ea0b 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -723,14 +723,11 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived) TABLE_SHARE *s= tl->table->s; const char *db= tl->db; const char *alias= tl->alias; - Query_arena backup; - Query_arena *arena= thd->activate_stmt_arena_if_needed(&backup); + Query_arena_stmt on_stmt_arena(thd); sl->item_list.push_back(new (thd->mem_root) Item_field( thd, &sl->context, db, alias, s->vers_start_field()->field_name)); sl->item_list.push_back(new (thd->mem_root) Item_field( thd, &sl->context, db, alias, s->vers_end_field()->field_name)); - if (arena) - thd->restore_active_arena(arena, &backup); } } } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 5901d1d4d6f..5ebd3126a23 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -695,7 +695,6 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, TABLE_LIST *table; int versioned_tables= 0; int slex_conds_used= 0; - Query_arena *arena= 0, backup; if (!thd->stmt_arena->is_conventional() && !thd->stmt_arena->is_stmt_prepare() && !thd->stmt_arena->is_sp_execute()) @@ -727,7 +726,7 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, /* For prepared statements we create items on statement arena, because they must outlive execution phase for multiple executions. */ - arena= thd->activate_stmt_arena_if_needed(&backup); + Query_arena_stmt on_stmt_arena(thd); if (slex->saved_where) { @@ -798,8 +797,6 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, case TL_WRITE: case TL_WRITE_ONLY: my_error(ER_VERS_WRONG_PARAMS, MYF(0), "FOR SYSTEM_TIME query", "write-locking of historic rows"); - if (arena) - thd->restore_active_arena(arena, &backup); DBUG_RETURN(-1); default: break; @@ -969,7 +966,7 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, cond2, cond1)); - if (arena) + if (on_stmt_arena.arena_replaced()) *dst_cond= cond1; else thd->change_item_tree(dst_cond, cond1); @@ -977,9 +974,6 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, } // if (... table->table->versioned()) } // for (table= tables; ...) - if (arena) - thd->restore_active_arena(arena, &backup); - if (!slex_conds_used && slex->vers_conditions) { my_error(ER_VERS_WRONG_QUERY, MYF(0), "unused `QUERY FOR SYSTEM_TIME` clause!"); -- cgit v1.2.1 From b19645caf58244f25f5e10a87f3a443803ca401d Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Thu, 27 Apr 2017 10:50:23 +0300 Subject: Tests: verify_vtq() fix --- mysql-test/suite/versioning/common.inc | 4 ++-- mysql-test/suite/versioning/r/alter.result | 4 ++-- mysql-test/suite/versioning/r/auto_increment.result | 4 ++-- mysql-test/suite/versioning/r/commit_id.result | 4 ++-- mysql-test/suite/versioning/r/create.result | 4 ++-- mysql-test/suite/versioning/r/delete.result | 4 ++-- mysql-test/suite/versioning/r/insert.result | 4 ++-- mysql-test/suite/versioning/r/partition.result | 4 ++-- mysql-test/suite/versioning/r/select.result | 4 ++-- mysql-test/suite/versioning/r/update.result | 4 ++-- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/mysql-test/suite/versioning/common.inc b/mysql-test/suite/versioning/common.inc index 9e26903c03b..d9f83f5fea9 100644 --- a/mysql-test/suite/versioning/common.inc +++ b/mysql-test/suite/versioning/common.inc @@ -8,9 +8,9 @@ begin select @i:= @i + 1 as No, trx_id > 0 as A, - commit_id >= trx_id as B, + commit_id > trx_id as B, begin_ts > '1-1-1 0:0:0' as C, - commit_ts > begin_ts as D + commit_ts >= begin_ts as D from information_schema.innodb_vtq where trx_id > @start_trx_id; select ifnull(max(trx_id), 0) diff --git a/mysql-test/suite/versioning/r/alter.result b/mysql-test/suite/versioning/r/alter.result index 13932ea1805..882d15f7b88 100644 --- a/mysql-test/suite/versioning/r/alter.result +++ b/mysql-test/suite/versioning/r/alter.result @@ -239,9 +239,9 @@ set @i= 0; select @i:= @i + 1 as No, trx_id > 0 as A, -commit_id >= trx_id as B, +commit_id > trx_id as B, begin_ts > '1-1-1 0:0:0' as C, -commit_ts > begin_ts as D +commit_ts >= begin_ts as D from information_schema.innodb_vtq where trx_id > @start_trx_id; select ifnull(max(trx_id), 0) diff --git a/mysql-test/suite/versioning/r/auto_increment.result b/mysql-test/suite/versioning/r/auto_increment.result index ae06e9348bf..e9e487c40a3 100644 --- a/mysql-test/suite/versioning/r/auto_increment.result +++ b/mysql-test/suite/versioning/r/auto_increment.result @@ -6,9 +6,9 @@ set @i= 0; select @i:= @i + 1 as No, trx_id > 0 as A, -commit_id >= trx_id as B, +commit_id > trx_id as B, begin_ts > '1-1-1 0:0:0' as C, -commit_ts > begin_ts as D +commit_ts >= begin_ts as D from information_schema.innodb_vtq where trx_id > @start_trx_id; select ifnull(max(trx_id), 0) diff --git a/mysql-test/suite/versioning/r/commit_id.result b/mysql-test/suite/versioning/r/commit_id.result index 9a41c0f3eb1..c18f06c7abb 100644 --- a/mysql-test/suite/versioning/r/commit_id.result +++ b/mysql-test/suite/versioning/r/commit_id.result @@ -6,9 +6,9 @@ set @i= 0; select @i:= @i + 1 as No, trx_id > 0 as A, -commit_id >= trx_id as B, +commit_id > trx_id as B, begin_ts > '1-1-1 0:0:0' as C, -commit_ts > begin_ts as D +commit_ts >= begin_ts as D from information_schema.innodb_vtq where trx_id > @start_trx_id; select ifnull(max(trx_id), 0) diff --git a/mysql-test/suite/versioning/r/create.result b/mysql-test/suite/versioning/r/create.result index ef78a693268..74bf5beb710 100644 --- a/mysql-test/suite/versioning/r/create.result +++ b/mysql-test/suite/versioning/r/create.result @@ -6,9 +6,9 @@ set @i= 0; select @i:= @i + 1 as No, trx_id > 0 as A, -commit_id >= trx_id as B, +commit_id > trx_id as B, begin_ts > '1-1-1 0:0:0' as C, -commit_ts > begin_ts as D +commit_ts >= begin_ts as D from information_schema.innodb_vtq where trx_id > @start_trx_id; select ifnull(max(trx_id), 0) diff --git a/mysql-test/suite/versioning/r/delete.result b/mysql-test/suite/versioning/r/delete.result index 784a0a8ad0c..2c5e4138c00 100644 --- a/mysql-test/suite/versioning/r/delete.result +++ b/mysql-test/suite/versioning/r/delete.result @@ -6,9 +6,9 @@ set @i= 0; select @i:= @i + 1 as No, trx_id > 0 as A, -commit_id >= trx_id as B, +commit_id > trx_id as B, begin_ts > '1-1-1 0:0:0' as C, -commit_ts > begin_ts as D +commit_ts >= begin_ts as D from information_schema.innodb_vtq where trx_id > @start_trx_id; select ifnull(max(trx_id), 0) diff --git a/mysql-test/suite/versioning/r/insert.result b/mysql-test/suite/versioning/r/insert.result index 8619ce3a916..0332018ff9b 100644 --- a/mysql-test/suite/versioning/r/insert.result +++ b/mysql-test/suite/versioning/r/insert.result @@ -6,9 +6,9 @@ set @i= 0; select @i:= @i + 1 as No, trx_id > 0 as A, -commit_id >= trx_id as B, +commit_id > trx_id as B, begin_ts > '1-1-1 0:0:0' as C, -commit_ts > begin_ts as D +commit_ts >= begin_ts as D from information_schema.innodb_vtq where trx_id > @start_trx_id; select ifnull(max(trx_id), 0) diff --git a/mysql-test/suite/versioning/r/partition.result b/mysql-test/suite/versioning/r/partition.result index ff9f583042a..2f203ba68ec 100644 --- a/mysql-test/suite/versioning/r/partition.result +++ b/mysql-test/suite/versioning/r/partition.result @@ -6,9 +6,9 @@ set @i= 0; select @i:= @i + 1 as No, trx_id > 0 as A, -commit_id >= trx_id as B, +commit_id > trx_id as B, begin_ts > '1-1-1 0:0:0' as C, -commit_ts > begin_ts as D +commit_ts >= begin_ts as D from information_schema.innodb_vtq where trx_id > @start_trx_id; select ifnull(max(trx_id), 0) diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index de92274e17f..bc32db7114a 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -6,9 +6,9 @@ set @i= 0; select @i:= @i + 1 as No, trx_id > 0 as A, -commit_id >= trx_id as B, +commit_id > trx_id as B, begin_ts > '1-1-1 0:0:0' as C, -commit_ts > begin_ts as D +commit_ts >= begin_ts as D from information_schema.innodb_vtq where trx_id > @start_trx_id; select ifnull(max(trx_id), 0) diff --git a/mysql-test/suite/versioning/r/update.result b/mysql-test/suite/versioning/r/update.result index 0b998dde300..c0e7a87f03b 100644 --- a/mysql-test/suite/versioning/r/update.result +++ b/mysql-test/suite/versioning/r/update.result @@ -6,9 +6,9 @@ set @i= 0; select @i:= @i + 1 as No, trx_id > 0 as A, -commit_id >= trx_id as B, +commit_id > trx_id as B, begin_ts > '1-1-1 0:0:0' as C, -commit_ts > begin_ts as D +commit_ts >= begin_ts as D from information_schema.innodb_vtq where trx_id > @start_trx_id; select ifnull(max(trx_id), 0) -- cgit v1.2.1 From 642525b9ad92f0b7f928e83600d493e6b2363d64 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Fri, 28 Apr 2017 09:46:00 +0300 Subject: Tests: cte_recursive, simple (new plans) Author: Alvin Richards --- mysql-test/suite/versioning/r/cte_recursive.result | 68 +++++++++++++++++++++ mysql-test/suite/versioning/r/simple.result | 71 ++++++++++++++++++++++ mysql-test/suite/versioning/t/cte_recursive.opt | 1 + mysql-test/suite/versioning/t/cte_recursive.test | 69 +++++++++++++++++++++ mysql-test/suite/versioning/t/simple.opt | 1 + mysql-test/suite/versioning/t/simple.test | 70 +++++++++++++++++++++ 6 files changed, 280 insertions(+) create mode 100644 mysql-test/suite/versioning/r/cte_recursive.result create mode 100644 mysql-test/suite/versioning/r/simple.result create mode 100644 mysql-test/suite/versioning/t/cte_recursive.opt create mode 100644 mysql-test/suite/versioning/t/cte_recursive.test create mode 100644 mysql-test/suite/versioning/t/simple.opt create mode 100644 mysql-test/suite/versioning/t/simple.test diff --git a/mysql-test/suite/versioning/r/cte_recursive.result b/mysql-test/suite/versioning/r/cte_recursive.result new file mode 100644 index 00000000000..91f95e561e3 --- /dev/null +++ b/mysql-test/suite/versioning/r/cte_recursive.result @@ -0,0 +1,68 @@ +create or replace table dept ( +dept_id int(10) primary key, +name varchar(100) +) +with system versioning; +create or replace table emp ( +emp_id int(10) primary key, +dept_id int(10) not null, +name varchar(100) not null, +mgr int(10), +salary int(10) not null, +constraint `dept-emp-fk` + foreign key (dept_id) references dept (dept_id) +on delete cascade +on update restrict, +constraint `mgr-fk` + foreign key (mgr) references emp (emp_id) +on delete restrict +on update restrict +) +with system versioning; +insert into dept (dept_id, name) values (10, "accounting"); +insert into emp (emp_id, name, salary, dept_id, mgr) values +(1, "bill", 1000, 10, null), +(20, "john", 500, 10, 1), +(30, "jane", 750, 10,1 ); +select vtq_commit_ts(max(sys_trx_start)) into @ts_1 from emp; +update emp set mgr=30 where name ="john"; +select vtq_commit_ts(sys_trx_start) into @ts_2 from emp where name="john"; +/* All report to 'Bill' */ +with recursive +ancestors +as +( +select e.emp_id, e.name, e.mgr, e.salary +from emp as e for system_time as of timestamp @ts_1 +where name = 'bill' + union +select e.emp_id, e.name, e.mgr, e.salary +from emp as e for system_time as of timestamp @ts_1, +ancestors as a +where e.mgr = a.emp_id +) +select * from ancestors; +emp_id name mgr salary +1 bill NULL 1000 +30 jane 1 750 +/* Expected 3 rows */ +with recursive +ancestors +as +( +select e.emp_id, e.name, e.mgr, e.salary +from emp as e for system_time as of timestamp @ts_2 +where name = 'bill' + union +select e.emp_id, e.name, e.mgr, e.salary +from emp as e for system_time as of timestamp @ts_2, +ancestors as a +where e.mgr = a.emp_id +) +select * from ancestors for system_time as of timestamp @ts_2; +emp_id name mgr salary +1 bill NULL 1000 +30 jane 1 750 +20 john 30 500 +drop table emp; +drop table dept; diff --git a/mysql-test/suite/versioning/r/simple.result b/mysql-test/suite/versioning/r/simple.result new file mode 100644 index 00000000000..9454d487293 --- /dev/null +++ b/mysql-test/suite/versioning/r/simple.result @@ -0,0 +1,71 @@ +create or replace table dept ( +dept_id int(10) primary key, +name varchar(100) +) +with system versioning; +create or replace table emp ( +emp_id int(10) primary key, +dept_id int(10), +name varchar(100), +salary int(10), +constraint `dept-emp-fk` + foreign key (dept_id) references dept (dept_id) +on delete cascade +on update restrict +) +with system versioning; +select now() into @ts_0; +insert into dept (dept_id, name) values (10, "accounting"); +commit; +select vtq_commit_ts(sys_trx_start) into @ts_1 from dept where dept_id=10; +insert into emp (emp_id, name, salary, dept_id) values (1, "bill", 1000, 10); +commit; +select vtq_commit_ts(sys_trx_start) into @ts_2 from emp where name="bill"; +select * from emp; +emp_id dept_id name salary +1 10 bill 1000 +update emp set salary=2000 where name="bill"; +commit; +select vtq_commit_ts(sys_trx_start) into @ts_3 from emp where name="bill"; +select * from emp; +emp_id dept_id name salary +1 10 bill 2000 +select * from emp for system_time as of timestamp @ts_2; +emp_id dept_id name salary +1 10 bill 1000 +select * from emp for system_time as of timestamp @ts_3; +emp_id dept_id name salary +1 10 bill 2000 +select * from emp e, dept d +where d.dept_id = 10 +and d.dept_id = e.dept_id; +emp_id dept_id name salary dept_id name +1 10 bill 2000 10 accounting +select * from emp e, dept d +where d.dept_id = 10 +and d.dept_id = e.dept_id +query for system_time from timestamp @ts_1 to timestamp @ts_2; +emp_id dept_id name salary sys_trx_start sys_trx_end dept_id name sys_trx_start sys_trx_end +select * from emp e, dept d +where d.dept_id = 10 +and d.dept_id = e.dept_id +query for system_time as of timestamp @ts_0; +emp_id dept_id name salary dept_id name +select * from emp e, dept d +where d.dept_id = 10 +and d.dept_id = e.dept_id +query for system_time as of timestamp @ts_1; +emp_id dept_id name salary dept_id name +select * from emp e, dept d +where d.dept_id = 10 +and d.dept_id = e.dept_id +query for system_time as of timestamp @ts_2; +emp_id dept_id name salary dept_id name +1 10 bill 1000 10 accounting +select * from emp e, dept d +where d.dept_id = 10 +and d.dept_id = e.dept_id +query for system_time as of timestamp @ts_3; +emp_id dept_id name salary dept_id name +1 10 bill 2000 10 accounting +drop table emp, dept; diff --git a/mysql-test/suite/versioning/t/cte_recursive.opt b/mysql-test/suite/versioning/t/cte_recursive.opt new file mode 100644 index 00000000000..3596fc4d3bd --- /dev/null +++ b/mysql-test/suite/versioning/t/cte_recursive.opt @@ -0,0 +1 @@ +--innodb --default-storage-engine=innodb diff --git a/mysql-test/suite/versioning/t/cte_recursive.test b/mysql-test/suite/versioning/t/cte_recursive.test new file mode 100644 index 00000000000..fcddb5971e7 --- /dev/null +++ b/mysql-test/suite/versioning/t/cte_recursive.test @@ -0,0 +1,69 @@ +create or replace table dept ( + dept_id int(10) primary key, + name varchar(100) +) +with system versioning; + +create or replace table emp ( + emp_id int(10) primary key, + dept_id int(10) not null, + name varchar(100) not null, + mgr int(10), + salary int(10) not null, + constraint `dept-emp-fk` + foreign key (dept_id) references dept (dept_id) + on delete cascade + on update restrict, + constraint `mgr-fk` + foreign key (mgr) references emp (emp_id) + on delete restrict + on update restrict +) +with system versioning; + +insert into dept (dept_id, name) values (10, "accounting"); + +insert into emp (emp_id, name, salary, dept_id, mgr) values +(1, "bill", 1000, 10, null), +(20, "john", 500, 10, 1), +(30, "jane", 750, 10,1 ); + +select vtq_commit_ts(max(sys_trx_start)) into @ts_1 from emp; + +update emp set mgr=30 where name ="john"; +select vtq_commit_ts(sys_trx_start) into @ts_2 from emp where name="john"; + +/* All report to 'Bill' */ +with recursive +ancestors +as +( + select e.emp_id, e.name, e.mgr, e.salary + from emp as e for system_time as of timestamp @ts_1 + where name = 'bill' + union + select e.emp_id, e.name, e.mgr, e.salary + from emp as e for system_time as of timestamp @ts_1, + ancestors as a + where e.mgr = a.emp_id +) +select * from ancestors; + +/* Expected 3 rows */ +with recursive +ancestors +as +( + select e.emp_id, e.name, e.mgr, e.salary + from emp as e for system_time as of timestamp @ts_2 + where name = 'bill' + union + select e.emp_id, e.name, e.mgr, e.salary + from emp as e for system_time as of timestamp @ts_2, + ancestors as a + where e.mgr = a.emp_id +) +select * from ancestors for system_time as of timestamp @ts_2; + +drop table emp; +drop table dept; diff --git a/mysql-test/suite/versioning/t/simple.opt b/mysql-test/suite/versioning/t/simple.opt new file mode 100644 index 00000000000..3596fc4d3bd --- /dev/null +++ b/mysql-test/suite/versioning/t/simple.opt @@ -0,0 +1 @@ +--innodb --default-storage-engine=innodb diff --git a/mysql-test/suite/versioning/t/simple.test b/mysql-test/suite/versioning/t/simple.test new file mode 100644 index 00000000000..bb540f05c26 --- /dev/null +++ b/mysql-test/suite/versioning/t/simple.test @@ -0,0 +1,70 @@ +create or replace table dept ( + dept_id int(10) primary key, + name varchar(100) +) +with system versioning; + +create or replace table emp ( + emp_id int(10) primary key, + dept_id int(10), + name varchar(100), + salary int(10), + constraint `dept-emp-fk` + foreign key (dept_id) references dept (dept_id) + on delete cascade + on update restrict +) +with system versioning; + +select now() into @ts_0; + +insert into dept (dept_id, name) values (10, "accounting"); +commit; + +select vtq_commit_ts(sys_trx_start) into @ts_1 from dept where dept_id=10; + +insert into emp (emp_id, name, salary, dept_id) values (1, "bill", 1000, 10); +commit; + +select vtq_commit_ts(sys_trx_start) into @ts_2 from emp where name="bill"; + +select * from emp; + +update emp set salary=2000 where name="bill"; +commit; + +select vtq_commit_ts(sys_trx_start) into @ts_3 from emp where name="bill"; + +select * from emp; +select * from emp for system_time as of timestamp @ts_2; +select * from emp for system_time as of timestamp @ts_3; +select * from emp e, dept d +where d.dept_id = 10 + and d.dept_id = e.dept_id; + +select * from emp e, dept d +where d.dept_id = 10 + and d.dept_id = e.dept_id +query for system_time from timestamp @ts_1 to timestamp @ts_2; + +select * from emp e, dept d +where d.dept_id = 10 + and d.dept_id = e.dept_id +query for system_time as of timestamp @ts_0; + +select * from emp e, dept d +where d.dept_id = 10 + and d.dept_id = e.dept_id +query for system_time as of timestamp @ts_1; + +select * from emp e, dept d +where d.dept_id = 10 + and d.dept_id = e.dept_id +query for system_time as of timestamp @ts_2; + +select * from emp e, dept d +where d.dept_id = 10 + and d.dept_id = e.dept_id +query for system_time as of timestamp @ts_3; + +drop table emp, dept; -- cgit v1.2.1 From 79688b0546594cc2c50425ec0fe848069b50d8cc Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Fri, 28 Apr 2017 15:49:09 +0300 Subject: IB: missed start_time_micro in minor ways of trx start --- storage/innobase/trx/trx0purge.cc | 3 ++- storage/innobase/trx/trx0trx.cc | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index f83d9377852..39e042d3756 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -183,7 +183,8 @@ trx_purge_graph_build(sess_t* sess) ut_ad(trx->sess == sess); trx->id = 0; - trx->start_time = ut_time(); + ut_usectime((ulong *)&trx->start_time, + (ulong *)&trx->start_time_micro); trx->state = TRX_STATE_ACTIVE; trx->op_info = "purge trx"; diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 8192c816c4c..aaa8a610bf0 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -880,7 +880,8 @@ trx_resurrect_insert( if (trx->state == TRX_STATE_ACTIVE || trx->state == TRX_STATE_PREPARED) { - trx->start_time = ut_time(); + ut_usectime((ulong *)&trx->start_time, + (ulong *)&trx->start_time_micro); } if (undo->dict_operation) { @@ -980,7 +981,8 @@ trx_resurrect_update( start time here.*/ if (trx->state == TRX_STATE_ACTIVE || trx->state == TRX_STATE_PREPARED) { - trx->start_time = ut_time(); + ut_usectime((ulong *)&trx->start_time, + (ulong *)&trx->start_time_micro); } if (undo->dict_operation) { -- cgit v1.2.1 From 7153ff85a18a252f4e8454614de643fb32df8c49 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Fri, 28 Apr 2017 12:07:04 +0300 Subject: SQL: derived tables improvements [closes #185] --- mysql-test/suite/versioning/r/derived.result | 165 +++++++++++++++++++++ .../suite/versioning/r/derived_tables.result | 129 ---------------- mysql-test/suite/versioning/t/derived.test | 125 ++++++++++++++++ mysql-test/suite/versioning/t/derived_tables.opt | 1 - mysql-test/suite/versioning/t/derived_tables.test | 91 ------------ sql/share/errmsg-utf8.txt | 3 + sql/sql_base.cc | 1 + sql/sql_derived.cc | 130 ++++++++++++++-- sql/sql_lex.cc | 2 +- sql/sql_lex.h | 1 + sql/sql_select.cc | 24 ++- sql/sql_view.cc | 18 ++- sql/table.h | 4 + 13 files changed, 453 insertions(+), 241 deletions(-) create mode 100644 mysql-test/suite/versioning/r/derived.result delete mode 100644 mysql-test/suite/versioning/r/derived_tables.result create mode 100644 mysql-test/suite/versioning/t/derived.test delete mode 100644 mysql-test/suite/versioning/t/derived_tables.opt delete mode 100644 mysql-test/suite/versioning/t/derived_tables.test diff --git a/mysql-test/suite/versioning/r/derived.result b/mysql-test/suite/versioning/r/derived.result new file mode 100644 index 00000000000..6b26b18adc0 --- /dev/null +++ b/mysql-test/suite/versioning/r/derived.result @@ -0,0 +1,165 @@ +create table emp +( +emp_id int, +name varchar(127), +mgr int +) with system versioning; +insert into emp values (1, 'bill', 0), +(2, 'bill', 1), +(3, 'kate', 1); +set @ts=now(6); +delete from emp; +insert into emp values (4, 'john', 1); +with ancestors as (select * from emp) select * from ancestors; +emp_id name mgr +4 john 1 +set @tmp= "with ancestors as (select * from emp) select * from ancestors"; +prepare stmt from @tmp; +execute stmt; +emp_id name mgr +4 john 1 +drop prepare stmt; +with ancestors as (select * from emp for system_time all) select * from ancestors; +emp_id name mgr +1 bill 0 +2 bill 1 +3 kate 1 +4 john 1 +set @tmp= "with ancestors as (select * from emp for system_time all) select * from ancestors"; +prepare stmt from @tmp; +execute stmt; +emp_id name mgr +1 bill 0 +2 bill 1 +3 kate 1 +4 john 1 +drop prepare stmt; +with recursive ancestors as (select * from emp) select * from ancestors; +emp_id name mgr +4 john 1 +set @tmp= "with recursive ancestors as (select * from emp) select * from ancestors"; +prepare stmt from @tmp; +execute stmt; +emp_id name mgr +4 john 1 +drop prepare stmt; +select emp_id from (select emp_id from emp where sys_trx_end>'2031-1-1') as tmp; +emp_id +4 +set @tmp= "select emp_id from (select emp_id from emp where sys_trx_end>'2031-1-1') as tmp"; +prepare stmt from @tmp; +execute stmt; +emp_id +4 +drop prepare stmt; +with recursive +ancestors +as +( +select e.emp_id, e.name, e.mgr +from emp as e +where name = 'john' + union +select ee.emp_id, ee.name, ee.mgr +from emp as ee, ancestors as a +where ee.mgr = a.emp_id +) +select * from ancestors; +emp_id name mgr +4 john 1 +set @tmp= " +with recursive +ancestors +as +( + select e.emp_id, e.name, e.mgr + from emp as e + where name = 'john' + union + select ee.emp_id, ee.name, ee.mgr + from emp as ee, ancestors as a + where ee.mgr = a.emp_id +) +select * from ancestors"; +prepare stmt from @tmp; +execute stmt; +emp_id name mgr +4 john 1 +drop prepare stmt; +with recursive +ancestors +as +( +select e.emp_id, e.name, e.mgr +from emp as e for system_time as of timestamp @ts +where name = 'bill' + union +select ee.emp_id, ee.name, ee.mgr +from emp as ee for system_time as of timestamp @ts, ancestors as a for system_time as of timestamp @ts +where ee.mgr = a.emp_id +) +select * from ancestors; +emp_id name mgr +1 bill 0 +2 bill 1 +3 kate 1 +set @tmp= " +with recursive +ancestors +as +( + select e.emp_id, e.name, e.mgr + from emp as e for system_time as of timestamp @ts + where name = 'bill' + union + select ee.emp_id, ee.name, ee.mgr + from emp as ee for system_time as of timestamp @ts, ancestors as a for system_time as of timestamp @ts + where ee.mgr = a.emp_id +) +select * from ancestors"; +prepare stmt from @tmp; +execute stmt; +emp_id name mgr +1 bill 0 +2 bill 1 +3 kate 1 +drop prepare stmt; +drop table emp; +create or replace table t1 (x int) with system versioning; +create or replace table t2 (y int) with system versioning; +insert into t1 values (1); +set @t0= now(6); +insert into t1 values (2); +delete from t1 where x = 1; +insert into t2 values (10); +select * from (select *, t1.sys_trx_end, t1.sys_trx_end as endo from t1) as s0; +ERROR HY000: Derived table is prohibited: multiple end system fields `t1.sys_trx_end`, `t1.sys_trx_end` in query! +select * from (select *, t1.sys_trx_end, t2.sys_trx_start from t1, t2) as s0; +ERROR HY000: Derived table is prohibited: system fields from multiple tables `t1`, `t2` in query! +select * from (select * from t1 for system_time as of timestamp @t0, t2) as s0; +x y +1 10 +select * from (select *, t1.sys_trx_end from t2, t1 for system_time as of timestamp @t0) as s0; +y x +10 1 +select * from (select *, t1.sys_trx_start from t2 for system_time as of now, t1) as s0 query for system_time as of timestamp @t0; +y x +10 1 +set @q= concat("create view vt1 as select * from t1 for system_time as of timestamp '", @t0, "'"); +prepare q from @q; +execute q; +drop prepare q; +select * from vt1; +x +1 +select * from (select * from vt1, t2) as s0; +x y +1 10 +select * from (select *, vt1.sys_trx_end from t2, vt1) as s0; +y x +10 1 +select * from (select *, vt1.sys_trx_start from t2 for system_time as of now, vt1) as s0 query for system_time as of timestamp @t0; +y x +10 1 +drop table t1, t2; +drop view vt1; diff --git a/mysql-test/suite/versioning/r/derived_tables.result b/mysql-test/suite/versioning/r/derived_tables.result deleted file mode 100644 index 638f5da665a..00000000000 --- a/mysql-test/suite/versioning/r/derived_tables.result +++ /dev/null @@ -1,129 +0,0 @@ -create table emp -( -emp_id int, -name varchar(127), -mgr int -) with system versioning; -insert into emp values (1, 'bill', 0), -(2, 'bill', 1), -(3, 'kate', 1); -set @ts=now(6); -delete from emp; -insert into emp values (4, 'john', 1); -with ancestors as (select * from emp) select * from ancestors; -emp_id name mgr -4 john 1 -set @tmp= "with ancestors as (select * from emp) select * from ancestors"; -prepare stmt from @tmp; -execute stmt; -emp_id name mgr -4 john 1 -drop prepare stmt; -with ancestors as (select * from emp for system_time all) select * from ancestors for system_time all; -emp_id name mgr -1 bill 0 -2 bill 1 -3 kate 1 -4 john 1 -set @tmp= "with ancestors as (select * from emp for system_time all) select * from ancestors for system_time all"; -prepare stmt from @tmp; -execute stmt; -emp_id name mgr -1 bill 0 -2 bill 1 -3 kate 1 -4 john 1 -drop prepare stmt; -with recursive ancestors as (select * from emp) select * from ancestors; -emp_id name mgr -4 john 1 -set @tmp= "with recursive ancestors as (select * from emp) select * from ancestors"; -prepare stmt from @tmp; -execute stmt; -emp_id name mgr -4 john 1 -drop prepare stmt; -select emp_id from (select emp_id from emp where sys_trx_end>'2031-1-1') as tmp; -emp_id -4 -set @tmp= "select emp_id from (select emp_id from emp where sys_trx_end>'2031-1-1') as tmp"; -prepare stmt from @tmp; -execute stmt; -emp_id -4 -drop prepare stmt; -with recursive -ancestors -as -( -select e.emp_id, e.name, e.mgr -from emp as e -where name = 'john' - union -select ee.emp_id, ee.name, ee.mgr -from emp as ee, ancestors as a -where ee.mgr = a.emp_id -) -select * from ancestors; -emp_id name mgr -4 john 1 -set @tmp= " -with recursive -ancestors -as -( - select e.emp_id, e.name, e.mgr - from emp as e - where name = 'john' - union - select ee.emp_id, ee.name, ee.mgr - from emp as ee, ancestors as a - where ee.mgr = a.emp_id -) -select * from ancestors -"; -prepare stmt from @tmp; -execute stmt; -emp_id name mgr -4 john 1 -drop prepare stmt; -with recursive -ancestors -as -( -select e.emp_id, e.name, e.mgr -from emp as e for system_time as of timestamp @ts -where name = 'bill' - union -select ee.emp_id, ee.name, ee.mgr -from emp as ee for system_time as of timestamp @ts, ancestors as a for system_time as of timestamp @ts -where ee.mgr = a.emp_id -) -select * from ancestors for system_time as of timestamp @ts; -emp_id name mgr -1 bill 0 -2 bill 1 -3 kate 1 -set @tmp= " -with recursive -ancestors -as -( - select e.emp_id, e.name, e.mgr - from emp as e for system_time as of timestamp @ts - where name = 'bill' - union - select ee.emp_id, ee.name, ee.mgr - from emp as ee for system_time as of timestamp @ts, ancestors as a for system_time as of timestamp @ts - where ee.mgr = a.emp_id -) -select * from ancestors for system_time as of timestamp @ts; -"; -prepare stmt from @tmp; -execute stmt; -emp_id name mgr -1 bill 0 -2 bill 1 -3 kate 1 -drop prepare stmt; -drop table emp; diff --git a/mysql-test/suite/versioning/t/derived.test b/mysql-test/suite/versioning/t/derived.test new file mode 100644 index 00000000000..867973aee7e --- /dev/null +++ b/mysql-test/suite/versioning/t/derived.test @@ -0,0 +1,125 @@ +create table emp +( + emp_id int, + name varchar(127), + mgr int +) with system versioning; + +insert into emp values (1, 'bill', 0), + (2, 'bill', 1), + (3, 'kate', 1); +set @ts=now(6); +delete from emp; +insert into emp values (4, 'john', 1); + +with ancestors as (select * from emp) select * from ancestors; +set @tmp= "with ancestors as (select * from emp) select * from ancestors"; +prepare stmt from @tmp; execute stmt; drop prepare stmt; + +with ancestors as (select * from emp for system_time all) select * from ancestors; +set @tmp= "with ancestors as (select * from emp for system_time all) select * from ancestors"; +prepare stmt from @tmp; execute stmt; drop prepare stmt; + +with recursive ancestors as (select * from emp) select * from ancestors; +set @tmp= "with recursive ancestors as (select * from emp) select * from ancestors"; +prepare stmt from @tmp; execute stmt; drop prepare stmt; + +select emp_id from (select emp_id from emp where sys_trx_end>'2031-1-1') as tmp; +set @tmp= "select emp_id from (select emp_id from emp where sys_trx_end>'2031-1-1') as tmp"; +prepare stmt from @tmp; execute stmt; drop prepare stmt; + +with recursive +ancestors +as +( + select e.emp_id, e.name, e.mgr + from emp as e + where name = 'john' + union + select ee.emp_id, ee.name, ee.mgr + from emp as ee, ancestors as a + where ee.mgr = a.emp_id +) +select * from ancestors; +set @tmp= " +with recursive +ancestors +as +( + select e.emp_id, e.name, e.mgr + from emp as e + where name = 'john' + union + select ee.emp_id, ee.name, ee.mgr + from emp as ee, ancestors as a + where ee.mgr = a.emp_id +) +select * from ancestors"; +prepare stmt from @tmp; execute stmt; drop prepare stmt; + +with recursive +ancestors +as +( + select e.emp_id, e.name, e.mgr + from emp as e for system_time as of timestamp @ts + where name = 'bill' + union + select ee.emp_id, ee.name, ee.mgr + from emp as ee for system_time as of timestamp @ts, ancestors as a for system_time as of timestamp @ts + where ee.mgr = a.emp_id +) +select * from ancestors; +set @tmp= " +with recursive +ancestors +as +( + select e.emp_id, e.name, e.mgr + from emp as e for system_time as of timestamp @ts + where name = 'bill' + union + select ee.emp_id, ee.name, ee.mgr + from emp as ee for system_time as of timestamp @ts, ancestors as a for system_time as of timestamp @ts + where ee.mgr = a.emp_id +) +select * from ancestors"; +prepare stmt from @tmp; execute stmt; drop prepare stmt; + +drop table emp; + +create or replace table t1 (x int) with system versioning; +create or replace table t2 (y int) with system versioning; +insert into t1 values (1); +set @t0= now(6); +insert into t1 values (2); +delete from t1 where x = 1; +insert into t2 values (10); + +--error ER_VERS_DERIVED_PROHIBITED +select * from (select *, t1.sys_trx_end, t1.sys_trx_end as endo from t1) as s0; +--error ER_VERS_DERIVED_PROHIBITED +select * from (select *, t1.sys_trx_end, t2.sys_trx_start from t1, t2) as s0; + +# system_time propagation from inner to outer +select * from (select * from t1 for system_time as of timestamp @t0, t2) as s0; +# leading table selection +select * from (select *, t1.sys_trx_end from t2, t1 for system_time as of timestamp @t0) as s0; +# system_time propagation from outer to inner +select * from (select *, t1.sys_trx_start from t2 for system_time as of now, t1) as s0 query for system_time as of timestamp @t0; + +# VIEW instead of t1 +set @q= concat("create view vt1 as select * from t1 for system_time as of timestamp '", @t0, "'"); +prepare q from @q; execute q; drop prepare q; + +# system_time propagation from view +select * from vt1; +# system_time propagation from inner to outer +select * from (select * from vt1, t2) as s0; +# leading table selection +select * from (select *, vt1.sys_trx_end from t2, vt1) as s0; +# system_time propagation from outer to inner +select * from (select *, vt1.sys_trx_start from t2 for system_time as of now, vt1) as s0 query for system_time as of timestamp @t0; + +drop table t1, t2; +drop view vt1; diff --git a/mysql-test/suite/versioning/t/derived_tables.opt b/mysql-test/suite/versioning/t/derived_tables.opt deleted file mode 100644 index 61ababdf408..00000000000 --- a/mysql-test/suite/versioning/t/derived_tables.opt +++ /dev/null @@ -1 +0,0 @@ ---vers-hide=implicit diff --git a/mysql-test/suite/versioning/t/derived_tables.test b/mysql-test/suite/versioning/t/derived_tables.test deleted file mode 100644 index e847a126ea4..00000000000 --- a/mysql-test/suite/versioning/t/derived_tables.test +++ /dev/null @@ -1,91 +0,0 @@ -create table emp -( - emp_id int, - name varchar(127), - mgr int -) with system versioning; - -insert into emp values (1, 'bill', 0), - (2, 'bill', 1), - (3, 'kate', 1); -set @ts=now(6); -delete from emp; -insert into emp values (4, 'john', 1); - -with ancestors as (select * from emp) select * from ancestors; -set @tmp= "with ancestors as (select * from emp) select * from ancestors"; -prepare stmt from @tmp; execute stmt; drop prepare stmt; - -with ancestors as (select * from emp for system_time all) select * from ancestors for system_time all; -set @tmp= "with ancestors as (select * from emp for system_time all) select * from ancestors for system_time all"; -prepare stmt from @tmp; execute stmt; drop prepare stmt; - -with recursive ancestors as (select * from emp) select * from ancestors; -set @tmp= "with recursive ancestors as (select * from emp) select * from ancestors"; -prepare stmt from @tmp; execute stmt; drop prepare stmt; - -select emp_id from (select emp_id from emp where sys_trx_end>'2031-1-1') as tmp; -set @tmp= "select emp_id from (select emp_id from emp where sys_trx_end>'2031-1-1') as tmp"; -prepare stmt from @tmp; execute stmt; drop prepare stmt; - -with recursive -ancestors -as -( - select e.emp_id, e.name, e.mgr - from emp as e - where name = 'john' - union - select ee.emp_id, ee.name, ee.mgr - from emp as ee, ancestors as a - where ee.mgr = a.emp_id -) -select * from ancestors; -set @tmp= " -with recursive -ancestors -as -( - select e.emp_id, e.name, e.mgr - from emp as e - where name = 'john' - union - select ee.emp_id, ee.name, ee.mgr - from emp as ee, ancestors as a - where ee.mgr = a.emp_id -) -select * from ancestors -"; -prepare stmt from @tmp; execute stmt; drop prepare stmt; - -with recursive -ancestors -as -( - select e.emp_id, e.name, e.mgr - from emp as e for system_time as of timestamp @ts - where name = 'bill' - union - select ee.emp_id, ee.name, ee.mgr - from emp as ee for system_time as of timestamp @ts, ancestors as a for system_time as of timestamp @ts - where ee.mgr = a.emp_id -) -select * from ancestors for system_time as of timestamp @ts; -set @tmp= " -with recursive -ancestors -as -( - select e.emp_id, e.name, e.mgr - from emp as e for system_time as of timestamp @ts - where name = 'bill' - union - select ee.emp_id, ee.name, ee.mgr - from emp as ee for system_time as of timestamp @ts, ancestors as a for system_time as of timestamp @ts - where ee.mgr = a.emp_id -) -select * from ancestors for system_time as of timestamp @ts; -"; -prepare stmt from @tmp; execute stmt; drop prepare stmt; - -drop table emp; diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 81651071c05..13408634738 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7538,6 +7538,9 @@ ER_VERS_WRONG_QUERY_TYPE ER_VERS_VIEW_PROHIBITED eng "Creating VIEW %`s is prohibited!" +ER_VERS_DERIVED_PROHIBITED + eng "Derived table is prohibited!" + ER_VERS_WRONG_QUERY eng "Wrong versioned query: %s" diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 8cdced1cb09..bf6f2c3931e 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7597,6 +7597,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, slex->vers_conditions.type : tl->vers_conditions.type; if ((sys_field && (thd->lex->sql_command == SQLCOM_CREATE_VIEW || + slex->nest_level > 0 || vers_hide == VERS_HIDE_FULL && thd->lex->sql_command != SQLCOM_CREATE_TABLE)) || ((fl & HIDDEN_FLAG) && ( !sys_field || diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index eb99544ea0b..f159708b932 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -713,23 +713,127 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived) cursor= cursor->next_local) cursor->outer_join|= JOIN_TYPE_OUTER; } - if ((thd->stmt_arena->is_stmt_prepare() || - !thd->stmt_arena->is_stmt_execute()) && - !derived->is_view() && sl->table_list.elements > 0) + + // System Versioning begin +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" +#pragma GCC diagnostic ignored "-Wformat-extra-args" + if ((thd->stmt_arena->is_stmt_prepare() || !thd->stmt_arena->is_stmt_execute()) + && sl->table_list.elements > 0) { - TABLE_LIST *tl= sl->table_list.first; - if (tl->table && tl->table->versioned()) + // Similar logic as in mysql_create_view() + TABLE_LIST *impli_table= NULL, *expli_table= NULL; + const char *impli_start, *impli_end; + Item_field *expli_start= NULL, *expli_end= NULL; + + for (TABLE_LIST *table= sl->table_list.first; table; table= table->next_local) + { + if (!table->table || !table->table->versioned()) + continue; + + const char *table_start= table->table->vers_start_field()->field_name; + const char *table_end= table->table->vers_end_field()->field_name; + if (!impli_table) + { + impli_table= table; + impli_start= table_start; + impli_end= table_end; + } + + /* Implicitly add versioning fields if needed */ + Item *item; + List_iterator_fast it(sl->item_list); + + DBUG_ASSERT(table->alias); + while ((item= it++)) + { + if (item->real_item()->type() != Item::FIELD_ITEM) + continue; + Item_field *fld= (Item_field*) (item->real_item()); + if (fld->table_name && 0 != my_strcasecmp(table_alias_charset, table->alias, fld->table_name)) + continue; + DBUG_ASSERT(fld->field_name); + if (0 == my_strcasecmp(system_charset_info, table_start, fld->field_name)) + { + if (expli_start) + { + my_printf_error( + ER_VERS_DERIVED_PROHIBITED, + "Derived table is prohibited: multiple start system fields `%s.%s`, `%s.%s` in query!", MYF(0), + expli_table->alias, + expli_start->field_name, + table->alias, + fld->field_name); + res= true; + goto exit; + } + if (expli_table) + { + if (expli_table != table) + { +expli_table_err: + my_printf_error( + ER_VERS_DERIVED_PROHIBITED, + "Derived table is prohibited: system fields from multiple tables %`s, %`s in query!", MYF(0), + expli_table->alias, + table->alias); + res= true; + goto exit; + } + } + else + expli_table= table; + expli_start= fld; + impli_end= table_end; + } + else if (0 == my_strcasecmp(system_charset_info, table_end, fld->field_name)) + { + if (expli_end) + { + my_printf_error( + ER_VERS_DERIVED_PROHIBITED, + "Derived table is prohibited: multiple end system fields `%s.%s`, `%s.%s` in query!", MYF(0), + expli_table->alias, + expli_end->field_name, + table->alias, + fld->field_name); + res= true; + goto exit; + } + if (expli_table) + { + if (expli_table != table) + goto expli_table_err; + } + else + expli_table= table; + expli_end= fld; + impli_start= table_start; + } + } // while ((item= it++)) + } // for (TABLE_LIST *table) + + if (expli_table) + impli_table= expli_table; + + if (impli_table) { - TABLE_SHARE *s= tl->table->s; - const char *db= tl->db; - const char *alias= tl->alias; Query_arena_stmt on_stmt_arena(thd); - sl->item_list.push_back(new (thd->mem_root) Item_field( - thd, &sl->context, db, alias, s->vers_start_field()->field_name)); - sl->item_list.push_back(new (thd->mem_root) Item_field( - thd, &sl->context, db, alias, s->vers_end_field()->field_name)); + if (!expli_start && (res= sl->vers_push_field(thd, impli_table, impli_start))) + goto exit; + if (!expli_end && (res= sl->vers_push_field(thd, impli_table, impli_end))) + goto exit; + + if (impli_table->vers_conditions) + sl->vers_derived_conds= impli_table->vers_conditions; + else if (sl->vers_conditions) + sl->vers_derived_conds= sl->vers_conditions; + else + sl->vers_conditions.import_outer= true; } - } + } // if (sl->table_list.elements > 0) +#pragma GCC diagnostic pop + // System Versioning end } unit->derived= derived; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 7b61efa8fb8..7c334d7ce67 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2298,6 +2298,7 @@ void st_select_lex::init_select() join= 0; lock_type= TL_READ_DEFAULT; vers_conditions.empty(); + vers_derived_conds.empty(); } /* @@ -7048,7 +7049,6 @@ bool LEX::sp_add_cfetch(THD *thd, const LEX_STRING &name) bool SELECT_LEX::vers_push_field(THD *thd, TABLE_LIST *table, const char* field_name) { - char buf[MAX_FIELD_NAME]; Item_field *fld= new (thd->mem_root) Item_field(thd, &context, table->db, table->alias, field_name); if (!fld) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 158130b5ddc..66f943e9f17 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -993,6 +993,7 @@ public: /* System Versioning */ vers_select_conds_t vers_conditions; + vers_select_conds_t vers_derived_conds; bool vers_push_field(THD *thd, TABLE_LIST *table, const char* field_name); void init_query(); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 5ebd3126a23..9ebe9ddf31b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -771,6 +771,28 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, } } + SELECT_LEX *outer_slex= slex->next_select_in_list(); + if (outer_slex) + { + if (slex->vers_derived_conds) + { + // Propagate derived conditions to outer SELECT_LEX: + if (!outer_slex->vers_conditions) + { + (outer_slex->vers_conditions= slex->vers_derived_conds). + from_inner= true; + } + } + else if (slex->vers_conditions.import_outer) + { + // Propagate query conditions from nearest outer SELECT_LEX: + while (outer_slex && (!outer_slex->vers_conditions || outer_slex->vers_conditions.from_inner)) + outer_slex= outer_slex->next_select_in_list(); + if (outer_slex) + slex->vers_conditions= outer_slex->vers_conditions; + } + } + for (table= tables; table; table= table->next_local) { if (table->table && table->table->versioned()) @@ -1059,7 +1081,7 @@ JOIN::prepare(TABLE_LIST *tables_init, remove_redundant_subquery_clauses(select_lex); } - /* Handle FOR SYSTEM_TIME clause. */ + /* System Versioning: handle FOR SYSTEM_TIME clause. */ if (vers_setup_select(thd, tables_list, &conds, select_lex) < 0) DBUG_RETURN(-1); diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 37703a2bc11..46dd7570874 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -454,6 +454,9 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, } { /* System Versioning begin */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" +#pragma GCC diagnostic ignored "-Wformat-extra-args" TABLE_LIST *impli_table= NULL, *expli_table= NULL; const char *impli_start, *impli_end; Item_field *expli_start= NULL, *expli_end= NULL; @@ -498,7 +501,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, { if (item->real_item()->type() != Item::FIELD_ITEM) continue; - Item_field *fld= (Item_field*) (item->real_item()); + Item_field *fld= (Item_field*) item->real_item(); if (fld->table_name && 0 != my_strcasecmp(table_alias_charset, table->alias, fld->table_name)) continue; DBUG_ASSERT(fld->field_name); @@ -567,10 +570,15 @@ expli_table_err: if (expli_table) impli_table= expli_table; - if (!expli_start && select_lex->vers_push_field(thd, impli_table, impli_start)) - goto err; - if (!expli_end && select_lex->vers_push_field(thd, impli_table, impli_end)) - goto err; + + if (impli_table) + { + if (!expli_start && select_lex->vers_push_field(thd, impli_table, impli_start)) + goto err; + if (!expli_end && select_lex->vers_push_field(thd, impli_table, impli_end)) + goto err; + } +#pragma GCC diagnostic pop } /* System Versioning end */ view= lex->unlink_first_table(&link_to_local); diff --git a/sql/table.h b/sql/table.h index 68f3a2dfe75..e03ea37226a 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1853,12 +1853,15 @@ struct vers_select_conds_t { vers_range_type_t type; vers_range_unit_t unit; + bool import_outer:1; + bool from_inner:1; Item *start, *end; void empty() { type= FOR_SYSTEM_TIME_UNSPECIFIED; unit= UNIT_TIMESTAMP; + import_outer= from_inner= false; start= end= NULL; } @@ -1872,6 +1875,7 @@ struct vers_select_conds_t unit= u; start= s; end= e; + import_outer= from_inner= false; } bool init_from_sysvar(THD *thd); -- cgit v1.2.1 From f43726a15da3525f48698db256c24a999585c941 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Sat, 29 Apr 2017 22:28:32 +0300 Subject: Scipts: --tail-lines option for mtr --- mysql-test/mysql-test-run.pl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 04203a2a84f..9833747c75a 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -220,6 +220,7 @@ our @opt_extra_mysqld_opt; our @opt_mysqld_envs; my $opt_stress; +my $opt_tail_lines= 20; my $opt_dry_run; @@ -1205,6 +1206,7 @@ sub command_line_setup { 'report-times' => \$opt_report_times, 'result-file' => \$opt_resfile, 'stress=s' => \$opt_stress, + 'tail-lines=i' => \$opt_tail_lines, 'dry-run' => \$opt_dry_run, 'help|h' => \$opt_usage, @@ -4856,7 +4858,7 @@ sub report_failure_and_restart ($) { $tinfo->{comment}.= "The result from queries just before the failure was:". "\n< snip >\n". - mtr_lastlinesfromfile($log_file_name, 20)."\n"; + mtr_lastlinesfromfile($log_file_name, $opt_tail_lines)."\n"; } } } @@ -5538,7 +5540,7 @@ sub start_mysqltest ($) { mtr_add_arg($args, "--test-file=%s", $tinfo->{'path'}); # Number of lines of resut to include in failure report - mtr_add_arg($args, "--tail-lines=20"); + mtr_add_arg($args, "--tail-lines=%d", $opt_tail_lines); if ( defined $tinfo->{'result_file'} ) { mtr_add_arg($args, "--result-file=%s", $tinfo->{'result_file'}); @@ -6186,6 +6188,8 @@ Misc options phases of test execution. stress=ARGS Run stress test, providing options to mysql-stress-test.pl. Options are separated by comma. + tail-lines=N Number of lines of the result to include in a failure + report. Some options that control enabling a feature for normal test runs, can be turned off by prepending 'no' to the option, e.g. --notimer. -- cgit v1.2.1 From 8a11f9b243ad049e8be810b4c898013b22057942 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Sun, 30 Apr 2017 23:12:29 +0300 Subject: SQL: VIEW fix [related to #185] --- sql/sql_derived.cc | 2 +- sql/sql_select.cc | 8 +++++--- sql/table.h | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index f159708b932..de4e49e56a5 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -824,7 +824,7 @@ expli_table_err: if (!expli_end && (res= sl->vers_push_field(thd, impli_table, impli_end))) goto exit; - if (impli_table->vers_conditions) + if (impli_table->vers_conditions && !derived->is_view()) sl->vers_derived_conds= impli_table->vers_conditions; else if (sl->vers_conditions) sl->vers_derived_conds= sl->vers_conditions; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 9ebe9ddf31b..4b01ca1e3f9 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -694,7 +694,6 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, TABLE_LIST *table; int versioned_tables= 0; - int slex_conds_used= 0; if (!thd->stmt_arena->is_conventional() && !thd->stmt_arena->is_stmt_prepare() && !thd->stmt_arena->is_sp_execute()) @@ -789,7 +788,10 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, while (outer_slex && (!outer_slex->vers_conditions || outer_slex->vers_conditions.from_inner)) outer_slex= outer_slex->next_select_in_list(); if (outer_slex) + { slex->vers_conditions= outer_slex->vers_conditions; + outer_slex->vers_conditions.used= true; + } } } @@ -798,7 +800,7 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, if (table->table && table->table->versioned()) { vers_select_conds_t &vers_conditions= !table->vers_conditions? - (++slex_conds_used, slex->vers_conditions) : + (slex->vers_conditions.used= true, slex->vers_conditions) : table->vers_conditions; if (!vers_conditions) @@ -996,7 +998,7 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, } // if (... table->table->versioned()) } // for (table= tables; ...) - if (!slex_conds_used && slex->vers_conditions) + if (!slex->vers_conditions.used && slex->vers_conditions) { my_error(ER_VERS_WRONG_QUERY, MYF(0), "unused `QUERY FOR SYSTEM_TIME` clause!"); DBUG_RETURN(-1); diff --git a/sql/table.h b/sql/table.h index e03ea37226a..32ad43b0ae9 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1855,13 +1855,14 @@ struct vers_select_conds_t vers_range_unit_t unit; bool import_outer:1; bool from_inner:1; + bool used:1; Item *start, *end; void empty() { type= FOR_SYSTEM_TIME_UNSPECIFIED; unit= UNIT_TIMESTAMP; - import_outer= from_inner= false; + import_outer= from_inner= used= false; start= end= NULL; } @@ -1875,7 +1876,7 @@ struct vers_select_conds_t unit= u; start= s; end= e; - import_outer= from_inner= false; + import_outer= from_inner= used= false; } bool init_from_sysvar(THD *thd); -- cgit v1.2.1 From 7e0ff13d7acf796872b7a1d8df1c2fae45beca06 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Sun, 30 Apr 2017 23:51:42 +0300 Subject: SQL: derived fixes [related to #185] --- mysql-test/suite/versioning/r/cte_recursive.result | 4 ++-- mysql-test/suite/versioning/r/view.result | 4 ++++ mysql-test/suite/versioning/t/cte_recursive.test | 4 ++-- sql/sql_derived.cc | 6 +++++- sql/sql_select.cc | 12 ++++++++---- 5 files changed, 21 insertions(+), 9 deletions(-) diff --git a/mysql-test/suite/versioning/r/cte_recursive.result b/mysql-test/suite/versioning/r/cte_recursive.result index 91f95e561e3..4ad56b8f3a7 100644 --- a/mysql-test/suite/versioning/r/cte_recursive.result +++ b/mysql-test/suite/versioning/r/cte_recursive.result @@ -41,7 +41,7 @@ from emp as e for system_time as of timestamp @ts_1, ancestors as a where e.mgr = a.emp_id ) -select * from ancestors; +select * from ancestors for system_time as of now; emp_id name mgr salary 1 bill NULL 1000 30 jane 1 750 @@ -59,7 +59,7 @@ from emp as e for system_time as of timestamp @ts_2, ancestors as a where e.mgr = a.emp_id ) -select * from ancestors for system_time as of timestamp @ts_2; +select * from ancestors; emp_id name mgr salary 1 bill NULL 1000 30 jane 1 750 diff --git a/mysql-test/suite/versioning/r/view.result b/mysql-test/suite/versioning/r/view.result index 3065b244cda..08c67cfa693 100644 --- a/mysql-test/suite/versioning/r/view.result +++ b/mysql-test/suite/versioning/r/view.result @@ -39,9 +39,13 @@ x drop prepare stmt; select * from vt1; x +2 +1 prepare stmt from 'select * from vt1'; execute stmt; x +2 +1 drop prepare stmt; select * from t1 for system_time as of timestamp @t1; x diff --git a/mysql-test/suite/versioning/t/cte_recursive.test b/mysql-test/suite/versioning/t/cte_recursive.test index fcddb5971e7..d1de218bf62 100644 --- a/mysql-test/suite/versioning/t/cte_recursive.test +++ b/mysql-test/suite/versioning/t/cte_recursive.test @@ -47,7 +47,7 @@ as ancestors as a where e.mgr = a.emp_id ) -select * from ancestors; +select * from ancestors for system_time as of now; /* Expected 3 rows */ with recursive @@ -63,7 +63,7 @@ as ancestors as a where e.mgr = a.emp_id ) -select * from ancestors for system_time as of timestamp @ts_2; +select * from ancestors; drop table emp; drop table dept; diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index de4e49e56a5..d6a00827fef 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -824,8 +824,12 @@ expli_table_err: if (!expli_end && (res= sl->vers_push_field(thd, impli_table, impli_end))) goto exit; - if (impli_table->vers_conditions && !derived->is_view()) + if (impli_table->vers_conditions) + { sl->vers_derived_conds= impli_table->vers_conditions; + if (derived->is_view() && !sl->vers_conditions) + sl->vers_conditions.import_outer= true; + } else if (sl->vers_conditions) sl->vers_derived_conds= sl->vers_conditions; else diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 4b01ca1e3f9..2355552ab77 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -771,6 +771,7 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, } SELECT_LEX *outer_slex= slex->next_select_in_list(); + bool use_slex_conds= false; if (outer_slex) { if (slex->vers_derived_conds) @@ -778,11 +779,12 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, // Propagate derived conditions to outer SELECT_LEX: if (!outer_slex->vers_conditions) { - (outer_slex->vers_conditions= slex->vers_derived_conds). - from_inner= true; + outer_slex->vers_conditions= slex->vers_derived_conds; + outer_slex->vers_conditions.from_inner= true; + outer_slex->vers_conditions.used= true; } } - else if (slex->vers_conditions.import_outer) + if (slex->vers_conditions.import_outer) { // Propagate query conditions from nearest outer SELECT_LEX: while (outer_slex && (!outer_slex->vers_conditions || outer_slex->vers_conditions.from_inner)) @@ -791,6 +793,8 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, { slex->vers_conditions= outer_slex->vers_conditions; outer_slex->vers_conditions.used= true; + DBUG_ASSERT(slex->master_unit()->derived); + use_slex_conds= slex->master_unit()->derived->is_view(); } } } @@ -799,7 +803,7 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, { if (table->table && table->table->versioned()) { - vers_select_conds_t &vers_conditions= !table->vers_conditions? + vers_select_conds_t &vers_conditions= use_slex_conds || !table->vers_conditions? (slex->vers_conditions.used= true, slex->vers_conditions) : table->vers_conditions; -- cgit v1.2.1 From 1bdf01131422a35d86c161e9eaeccc945ed26279 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 2 May 2017 11:02:03 +0300 Subject: Merge: stale innodb_support_xa_basic --- .../sys_vars/r/innodb_support_xa_basic.result | 227 ------------------- .../suite/sys_vars/t/innodb_support_xa_basic.test | 240 --------------------- 2 files changed, 467 deletions(-) delete mode 100644 mysql-test/suite/sys_vars/r/innodb_support_xa_basic.result delete mode 100644 mysql-test/suite/sys_vars/t/innodb_support_xa_basic.test diff --git a/mysql-test/suite/sys_vars/r/innodb_support_xa_basic.result b/mysql-test/suite/sys_vars/r/innodb_support_xa_basic.result deleted file mode 100644 index 5c66ff41355..00000000000 --- a/mysql-test/suite/sys_vars/r/innodb_support_xa_basic.result +++ /dev/null @@ -1,227 +0,0 @@ -SET @session_start_value = @@session.innodb_support_xa; -SELECT @session_start_value; -@session_start_value -1 -SET @global_start_value = @@global.innodb_support_xa; -SELECT @global_start_value; -@global_start_value -1 -'#--------------------FN_DYNVARS_046_01------------------------#' -SET @@session.innodb_support_xa = 0; -Warnings: -Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed. -SET @@session.innodb_support_xa = DEFAULT; -Warnings: -Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. -SELECT @@session.innodb_support_xa; -@@session.innodb_support_xa -1 -SET @@global.innodb_support_xa = 0; -Warnings: -Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed. -SET @@global.innodb_support_xa = DEFAULT; -Warnings: -Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. -SELECT @@global.innodb_support_xa; -@@global.innodb_support_xa -1 -'#---------------------FN_DYNVARS_046_02-------------------------#' -SET innodb_support_xa = 1; -Warnings: -Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. -SELECT @@innodb_support_xa; -@@innodb_support_xa -1 -SELECT session.innodb_support_xa; -ERROR 42S02: Unknown table 'session' in field list -SELECT local.innodb_support_xa; -ERROR 42S02: Unknown table 'local' in field list -SELECT global.innodb_support_xa; -ERROR 42S02: Unknown table 'global' in field list -SET session innodb_support_xa = 0; -Warnings: -Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed. -SELECT @@session.innodb_support_xa; -@@session.innodb_support_xa -1 -SET global innodb_support_xa = 0; -Warnings: -Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed. -SELECT @@global.innodb_support_xa; -@@global.innodb_support_xa -1 -'#--------------------FN_DYNVARS_046_03------------------------#' -SET @@session.innodb_support_xa = 0; -Warnings: -Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed. -SELECT @@session.innodb_support_xa; -@@session.innodb_support_xa -1 -SET @@session.innodb_support_xa = 1; -Warnings: -Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. -SELECT @@session.innodb_support_xa; -@@session.innodb_support_xa -1 -SET @@global.innodb_support_xa = 0; -Warnings: -Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed. -SELECT @@global.innodb_support_xa; -@@global.innodb_support_xa -1 -SET @@global.innodb_support_xa = 1; -Warnings: -Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. -SELECT @@global.innodb_support_xa; -@@global.innodb_support_xa -1 -'#--------------------FN_DYNVARS_046_04-------------------------#' -SET @@session.innodb_support_xa = -0.6; -ERROR 42000: Incorrect argument type to variable 'innodb_support_xa' -SET @@session.innodb_support_xa = 1.6; -ERROR 42000: Incorrect argument type to variable 'innodb_support_xa' -SET @@session.innodb_support_xa = "T"; -ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'T' -SET @@session.innodb_support_xa = "Y"; -ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'Y' -SET @@session.innodb_support_xa = TRÜE; -ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'TRÜE' -SET @@session.innodb_support_xa = ÕN; -ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'ÕN' -SET @@session.innodb_support_xa = OFF; -Warnings: -Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed. -SELECT @@session.innodb_support_xa; -@@session.innodb_support_xa -1 -SET @@session.innodb_support_xa = ÓFF; -ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'ÓFF' -SET @@global.innodb_support_xa = -1; -ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of '-1' -SELECT @@global.innodb_support_xa; -@@global.innodb_support_xa -1 -SET @@global.innodb_support_xa = 2; -ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of '2' -SET @@global.innodb_support_xa = "T"; -ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'T' -SET @@global.innodb_support_xa = "Y"; -ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'Y' -SET @@global.innodb_support_xa = TRÜE; -ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'TRÜE' -SET @@global.innodb_support_xa = ÕN; -ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'ÕN' -SET @@global.innodb_support_xa = OFF; -Warnings: -Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed. -SELECT @@global.innodb_support_xa; -@@global.innodb_support_xa -1 -SET @@global.innodb_support_xa = ÓFF; -ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'ÓFF' -'#-------------------FN_DYNVARS_046_05----------------------------#' -SET @@global.innodb_support_xa = 0; -Warnings: -Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed. -SET @@session.innodb_support_xa = 1; -Warnings: -Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. -SELECT @@global.innodb_support_xa AS res_is_0; -res_is_0 -1 -SET @@global.innodb_support_xa = 0; -Warnings: -Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed. -SELECT @@session.innodb_support_xa AS res_is_1; -res_is_1 -1 -'#----------------------FN_DYNVARS_046_06------------------------#' -SELECT IF(@@global.innodb_support_xa, "ON", "OFF") = -VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES -WHERE VARIABLE_NAME='innodb_support_xa'; -IF(@@global.innodb_support_xa, "ON", "OFF") = -VARIABLE_VALUE -1 -SELECT @@global.innodb_support_xa; -@@global.innodb_support_xa -1 -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES -WHERE VARIABLE_NAME='innodb_support_xa'; -VARIABLE_VALUE -ON -'#----------------------FN_DYNVARS_046_07------------------------#' -SELECT IF(@@session.innodb_support_xa, "ON", "OFF") = -VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_VARIABLES -WHERE VARIABLE_NAME='innodb_support_xa'; -IF(@@session.innodb_support_xa, "ON", "OFF") = -VARIABLE_VALUE -1 -SELECT @@session.innodb_support_xa; -@@session.innodb_support_xa -1 -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_VARIABLES -WHERE VARIABLE_NAME='innodb_support_xa'; -VARIABLE_VALUE -ON -'#---------------------FN_DYNVARS_046_08-------------------------#' -SET @@session.innodb_support_xa = OFF; -Warnings: -Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed. -SELECT @@session.innodb_support_xa; -@@session.innodb_support_xa -1 -SET @@session.innodb_support_xa = ON; -Warnings: -Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. -SELECT @@session.innodb_support_xa; -@@session.innodb_support_xa -1 -SET @@global.innodb_support_xa = OFF; -Warnings: -Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed. -SELECT @@global.innodb_support_xa; -@@global.innodb_support_xa -1 -SET @@global.innodb_support_xa = ON; -Warnings: -Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. -SELECT @@global.innodb_support_xa; -@@global.innodb_support_xa -1 -'#---------------------FN_DYNVARS_046_09----------------------#' -SET @@session.innodb_support_xa = TRUE; -Warnings: -Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. -SELECT @@session.innodb_support_xa; -@@session.innodb_support_xa -1 -SET @@session.innodb_support_xa = FALSE; -Warnings: -Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed. -SELECT @@session.innodb_support_xa; -@@session.innodb_support_xa -1 -SET @@global.innodb_support_xa = TRUE; -Warnings: -Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. -SELECT @@global.innodb_support_xa; -@@global.innodb_support_xa -1 -SET @@global.innodb_support_xa = FALSE; -Warnings: -Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed. -SELECT @@global.innodb_support_xa; -@@global.innodb_support_xa -1 -SET @@session.innodb_support_xa = @session_start_value; -Warnings: -Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. -SELECT @@session.innodb_support_xa; -@@session.innodb_support_xa -1 -SET @@global.innodb_support_xa = @global_start_value; -Warnings: -Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. -SELECT @@global.innodb_support_xa; -@@global.innodb_support_xa -1 diff --git a/mysql-test/suite/sys_vars/t/innodb_support_xa_basic.test b/mysql-test/suite/sys_vars/t/innodb_support_xa_basic.test deleted file mode 100644 index f8ce5852769..00000000000 --- a/mysql-test/suite/sys_vars/t/innodb_support_xa_basic.test +++ /dev/null @@ -1,240 +0,0 @@ -################# mysql-test\t\innodb_support_xa_basic.test ################### -# # -# Variable Name: innodb_support_xa # -# Scope: GLOBAL | SESSION # -# Access Type: Dynamic # -# Data Type: boolean # -# Default Value: 1 # -# Range: 0,1 # -# # -# # -# Creation Date: 2008-02-20 # -# Author: Rizwan # -# # -# Description: Test Cases of Dynamic System Variable innodb_support_xa # -# 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/have_innodb.inc ---source include/load_sysvars.inc - -######################################################################## -# START OF innodb_support_xa TESTS # -######################################################################## - - -################################################################################ -# Saving initial value of innodb_support_xa in a temporary variable # -################################################################################ - - -SET @session_start_value = @@session.innodb_support_xa; -SELECT @session_start_value; - - -SET @global_start_value = @@global.innodb_support_xa; -SELECT @global_start_value; - - - ---echo '#--------------------FN_DYNVARS_046_01------------------------#' -######################################################################## -# Display the DEFAULT value of innodb_support_xa # -######################################################################## - -SET @@session.innodb_support_xa = 0; -SET @@session.innodb_support_xa = DEFAULT; -SELECT @@session.innodb_support_xa; - -SET @@global.innodb_support_xa = 0; -SET @@global.innodb_support_xa = DEFAULT; -SELECT @@global.innodb_support_xa; - ---echo '#---------------------FN_DYNVARS_046_02-------------------------#' -########################################################################## -# Check if innodb_support_xa can be accessed with and without @@ sign # -########################################################################## - -SET innodb_support_xa = 1; -SELECT @@innodb_support_xa; - ---Error ER_UNKNOWN_TABLE -SELECT session.innodb_support_xa; - ---Error ER_UNKNOWN_TABLE -SELECT local.innodb_support_xa; - ---Error ER_UNKNOWN_TABLE -SELECT global.innodb_support_xa; -#using another syntax for accessing system variables -SET session innodb_support_xa = 0; -SELECT @@session.innodb_support_xa; - -SET global innodb_support_xa = 0; -SELECT @@global.innodb_support_xa; - - ---echo '#--------------------FN_DYNVARS_046_03------------------------#' -########################################################################## -# change the value of innodb_support_xa to a valid value # -########################################################################## -# for session -SET @@session.innodb_support_xa = 0; -SELECT @@session.innodb_support_xa; -SET @@session.innodb_support_xa = 1; -SELECT @@session.innodb_support_xa; - -# for global -SET @@global.innodb_support_xa = 0; -SELECT @@global.innodb_support_xa; -SET @@global.innodb_support_xa = 1; -SELECT @@global.innodb_support_xa; - - ---echo '#--------------------FN_DYNVARS_046_04-------------------------#' -########################################################################### -# Change the value of innodb_support_xa to invalid value # -########################################################################### - -# for session ---Error ER_WRONG_TYPE_FOR_VAR -SET @@session.innodb_support_xa = -0.6; ---Error ER_WRONG_TYPE_FOR_VAR -SET @@session.innodb_support_xa = 1.6; ---Error ER_WRONG_VALUE_FOR_VAR -SET @@session.innodb_support_xa = "T"; ---Error ER_WRONG_VALUE_FOR_VAR -SET @@session.innodb_support_xa = "Y"; ---Error ER_WRONG_VALUE_FOR_VAR -SET @@session.innodb_support_xa = TRÜE; ---Error ER_WRONG_VALUE_FOR_VAR -SET @@session.innodb_support_xa = ÕN; - -SET @@session.innodb_support_xa = OFF; -SELECT @@session.innodb_support_xa; - ---Error ER_WRONG_VALUE_FOR_VAR -SET @@session.innodb_support_xa = ÓFF; - -# for global - - ---Error ER_WRONG_VALUE_FOR_VAR -SET @@global.innodb_support_xa = -1; -SELECT @@global.innodb_support_xa; - ---Error ER_WRONG_VALUE_FOR_VAR -SET @@global.innodb_support_xa = 2; ---Error ER_WRONG_VALUE_FOR_VAR -SET @@global.innodb_support_xa = "T"; ---Error ER_WRONG_VALUE_FOR_VAR -SET @@global.innodb_support_xa = "Y"; ---Error ER_WRONG_VALUE_FOR_VAR -SET @@global.innodb_support_xa = TRÜE; ---Error ER_WRONG_VALUE_FOR_VAR -SET @@global.innodb_support_xa = ÕN; - -SET @@global.innodb_support_xa = OFF; -SELECT @@global.innodb_support_xa; - ---Error ER_WRONG_VALUE_FOR_VAR -SET @@global.innodb_support_xa = ÓFF; - - ---echo '#-------------------FN_DYNVARS_046_05----------------------------#' -########################################################################### -# Test if changing global variable effects session and vice versa # -########################################################################### - -SET @@global.innodb_support_xa = 0; -SET @@session.innodb_support_xa = 1; -SELECT @@global.innodb_support_xa AS res_is_0; - -SET @@global.innodb_support_xa = 0; -SELECT @@session.innodb_support_xa AS res_is_1; - ---echo '#----------------------FN_DYNVARS_046_06------------------------#' -######################################################################### -# Check if the value in GLOBAL Table matches value in variable # -######################################################################### - ---disable_warnings -SELECT IF(@@global.innodb_support_xa, "ON", "OFF") = - VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES - WHERE VARIABLE_NAME='innodb_support_xa'; ---enable_warnings -SELECT @@global.innodb_support_xa; ---disable_warnings -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES - WHERE VARIABLE_NAME='innodb_support_xa'; ---enable_warnings - - ---echo '#----------------------FN_DYNVARS_046_07------------------------#' -######################################################################### -# Check if the value in SESSION Table matches value in variable # -######################################################################### - ---disable_warnings -SELECT IF(@@session.innodb_support_xa, "ON", "OFF") = - VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_VARIABLES - WHERE VARIABLE_NAME='innodb_support_xa'; ---enable_warnings -SELECT @@session.innodb_support_xa; ---disable_warnings -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_VARIABLES - WHERE VARIABLE_NAME='innodb_support_xa'; ---enable_warnings - - ---echo '#---------------------FN_DYNVARS_046_08-------------------------#' -################################################################### -# Check if ON and OFF values can be used on variable # -################################################################### - -SET @@session.innodb_support_xa = OFF; -SELECT @@session.innodb_support_xa; -SET @@session.innodb_support_xa = ON; -SELECT @@session.innodb_support_xa; - -SET @@global.innodb_support_xa = OFF; -SELECT @@global.innodb_support_xa; -SET @@global.innodb_support_xa = ON; -SELECT @@global.innodb_support_xa; - ---echo '#---------------------FN_DYNVARS_046_09----------------------#' -################################################################### -# Check if TRUE and FALSE values can be used on variable # -################################################################### - -SET @@session.innodb_support_xa = TRUE; -SELECT @@session.innodb_support_xa; -SET @@session.innodb_support_xa = FALSE; -SELECT @@session.innodb_support_xa; - -SET @@global.innodb_support_xa = TRUE; -SELECT @@global.innodb_support_xa; -SET @@global.innodb_support_xa = FALSE; -SELECT @@global.innodb_support_xa; - -############################## -# Restore initial value # -############################## - -SET @@session.innodb_support_xa = @session_start_value; -SELECT @@session.innodb_support_xa; - -SET @@global.innodb_support_xa = @global_start_value; -SELECT @@global.innodb_support_xa; - -############################################################### -# END OF innodb_support_xa TESTS # -############################################################### -- cgit v1.2.1 From dc12395b0b6b7972ff1417d42cc8a633090649be Mon Sep 17 00:00:00 2001 From: kevg Date: Tue, 2 May 2017 17:41:29 +0300 Subject: Misc: travis speed up --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 103f5bd73be..ad83dcf9d20 100644 --- a/.travis.yml +++ b/.travis.yml @@ -59,7 +59,6 @@ addons: - libcrack2-dev - libjemalloc-dev - devscripts # implicit for any build on Ubuntu - - libtcmalloc-minimal4 - valgrind env: @@ -75,4 +74,4 @@ env: script: - ${CC} --version ; ${CXX} --version - cd "${TRAVIS_BUILD_DIR}" - - "LD_PRELOAD=/usr/lib/libtcmalloc_minimal.so.4 cmake -DWITH_INNOBASE_STORAGE_ENGINE=yes $BUILD_TYPE && LD_PRELOAD=/usr/lib/libtcmalloc_minimal.so.4 make -j $(grep -c processor /proc/cpuinfo) && cd ./mysql-test && ./mtr $MTR_FLAGS --suite=versioning --force --max-test-fail=0" + - "cmake -DWITH_INNOBASE_STORAGE_ENGINE=1 -DWITHOUT_TOKUDB_STORAGE_ENGINE=1 -DWITHOUT_ROCKSDB_STORAGE_ENGINE=1 $BUILD_TYPE && make -j $(grep -c processor /proc/cpuinfo) && cd ./mysql-test && ./mtr $MTR_FLAGS --mem --suite=versioning --force --max-test-fail=0" -- cgit v1.2.1 From 44506f26696ecae268b3056edb46d247fcc6b919 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 3 May 2017 06:15:20 +0300 Subject: SQL: vers_ sysvars renamed to versioning_ --- .../sys_vars/r/sysvars_server_notembedded.result | 8 +- mysql-test/suite/versioning/common.opt | 2 +- mysql-test/suite/versioning/r/sysvars.result | 122 ++++++++++----------- mysql-test/suite/versioning/t/foreign.opt | 2 +- mysql-test/suite/versioning/t/partition.opt | 2 +- mysql-test/suite/versioning/t/rpl_test.opt | 2 +- mysql-test/suite/versioning/t/sysvars.opt | 2 +- mysql-test/suite/versioning/t/sysvars.test | 78 ++++++------- mysql-test/suite/versioning/t/truncate_history.opt | 2 +- mysql-test/suite/versioning/t/view.opt | 2 +- sql/sys_vars.cc | 8 +- 11 files changed, 115 insertions(+), 115 deletions(-) diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result index 5a9734c73a4..f46d3abec9e 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result @@ -5119,7 +5119,7 @@ NUMERIC_BLOCK_SIZE NULL ENUM_VALUE_LIST NEVER,COMPLEMENTARY,PREFERABLY READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED -VARIABLE_NAME VERS_CURRENT_TIME +VARIABLE_NAME VERSIONING_CURRENT_TIMESTAMP SESSION_VALUE NOW GLOBAL_VALUE NOW GLOBAL_VALUE_ORIGIN COMPILE-TIME @@ -5133,7 +5133,7 @@ NUMERIC_BLOCK_SIZE NULL ENUM_VALUE_LIST NULL READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED -VARIABLE_NAME VERS_FORCE +VARIABLE_NAME VERSIONING_FORCE SESSION_VALUE OFF GLOBAL_VALUE OFF GLOBAL_VALUE_ORIGIN COMPILE-TIME @@ -5147,7 +5147,7 @@ NUMERIC_BLOCK_SIZE NULL ENUM_VALUE_LIST OFF,ON READ_ONLY NO COMMAND_LINE_ARGUMENT OPTIONAL -VARIABLE_NAME VERS_HIDE +VARIABLE_NAME VERSIONING_HIDE SESSION_VALUE AUTO GLOBAL_VALUE AUTO GLOBAL_VALUE_ORIGIN COMPILE-TIME @@ -5161,7 +5161,7 @@ NUMERIC_BLOCK_SIZE NULL ENUM_VALUE_LIST AUTO,IMPLICIT,FULL,NEVER READ_ONLY NO COMMAND_LINE_ARGUMENT OPTIONAL -VARIABLE_NAME VERS_INNODB_ALGORITHM_SIMPLE +VARIABLE_NAME VERSIONING_INNODB_ALGORITHM_SIMPLE SESSION_VALUE ON GLOBAL_VALUE ON GLOBAL_VALUE_ORIGIN COMPILE-TIME diff --git a/mysql-test/suite/versioning/common.opt b/mysql-test/suite/versioning/common.opt index cc66825a3df..5575069d6ee 100644 --- a/mysql-test/suite/versioning/common.opt +++ b/mysql-test/suite/versioning/common.opt @@ -15,4 +15,4 @@ --innodb-sys-tables --innodb-sys-virtual --innodb-vtq ---vers-hide=implicit +--versioning-hide=implicit diff --git a/mysql-test/suite/versioning/r/sysvars.result b/mysql-test/suite/versioning/r/sysvars.result index dbab7f2c910..172a10c78d7 100644 --- a/mysql-test/suite/versioning/r/sysvars.result +++ b/mysql-test/suite/versioning/r/sysvars.result @@ -1,32 +1,32 @@ create table t (a int) with system versioning; insert into t values (1); update t set a= 2; -show global variables like 'vers_current_time'; +show global variables like 'versioning_current_timestamp'; Variable_name Value -vers_current_time NOW -show variables like 'vers_current_time'; +versioning_current_timestamp NOW +show variables like 'versioning_current_timestamp'; Variable_name Value -vers_current_time NOW +versioning_current_timestamp NOW select * from t; a 2 -set vers_current_time = '2031-1-1 0:0:0'; -show variables like 'vers_current_time'; +set versioning_current_timestamp = '2031-1-1 0:0:0'; +show variables like 'versioning_current_timestamp'; Variable_name Value -vers_current_time 2031-01-01 00:00:00.000000 +versioning_current_timestamp 2031-01-01 00:00:00.000000 select * from t; a 2 -set vers_current_time = '2011-1-1 0:0:0'; -show variables like 'vers_current_time'; +set versioning_current_timestamp = '2011-1-1 0:0:0'; +show variables like 'versioning_current_timestamp'; Variable_name Value -vers_current_time 2011-01-01 00:00:00.000000 +versioning_current_timestamp 2011-01-01 00:00:00.000000 select * from t; a -set vers_current_time = 'all'; -show variables like 'vers_current_time'; +set versioning_current_timestamp = 'all'; +show variables like 'versioning_current_timestamp'; Variable_name Value -vers_current_time ALL +versioning_current_timestamp ALL select * from t; a 2 @@ -41,70 +41,70 @@ select * from (select * from t) as tt; a 2 1 -set global vers_current_time= 'alley'; -ERROR 42000: Variable 'vers_current_time' can't be set to the value of 'alley' -set global vers_current_time= null; -ERROR 42000: Variable 'vers_current_time' can't be set to the value of 'NULL' -set global vers_current_time= 1; -ERROR 42000: Incorrect argument type to variable 'vers_current_time' -set global vers_current_time= 1.1; -ERROR 42000: Incorrect argument type to variable 'vers_current_time' -set vers_current_time= 'alley'; -ERROR 42000: Variable 'vers_current_time' can't be set to the value of 'alley' -set vers_current_time= null; -ERROR 42000: Variable 'vers_current_time' can't be set to the value of 'NULL' -set vers_current_time= 1; -ERROR 42000: Incorrect argument type to variable 'vers_current_time' -set vers_current_time= 1.1; -ERROR 42000: Incorrect argument type to variable 'vers_current_time' -set global vers_current_time= '1911-11-11 11:11:11.1111119'; -show global variables like 'vers_current_time'; +set global versioning_current_timestamp= 'alley'; +ERROR 42000: Variable 'versioning_current_timestamp' can't be set to the value of 'alley' +set global versioning_current_timestamp= null; +ERROR 42000: Variable 'versioning_current_timestamp' can't be set to the value of 'NULL' +set global versioning_current_timestamp= 1; +ERROR 42000: Incorrect argument type to variable 'versioning_current_timestamp' +set global versioning_current_timestamp= 1.1; +ERROR 42000: Incorrect argument type to variable 'versioning_current_timestamp' +set versioning_current_timestamp= 'alley'; +ERROR 42000: Variable 'versioning_current_timestamp' can't be set to the value of 'alley' +set versioning_current_timestamp= null; +ERROR 42000: Variable 'versioning_current_timestamp' can't be set to the value of 'NULL' +set versioning_current_timestamp= 1; +ERROR 42000: Incorrect argument type to variable 'versioning_current_timestamp' +set versioning_current_timestamp= 1.1; +ERROR 42000: Incorrect argument type to variable 'versioning_current_timestamp' +set global versioning_current_timestamp= '1911-11-11 11:11:11.1111119'; +show global variables like 'versioning_current_timestamp'; Variable_name Value -vers_current_time 1911-11-11 11:11:11.111111 -set global vers_current_time= '1900-01-01 00:00:00'; -show global variables like 'vers_current_time'; +versioning_current_timestamp 1911-11-11 11:11:11.111111 +set global versioning_current_timestamp= '1900-01-01 00:00:00'; +show global variables like 'versioning_current_timestamp'; Variable_name Value -vers_current_time 1900-01-01 00:00:00.000000 -set global vers_current_time= timestamp'1911-11-11 11:11:11.1111119'; +versioning_current_timestamp 1900-01-01 00:00:00.000000 +set global versioning_current_timestamp= timestamp'1911-11-11 11:11:11.1111119'; Warnings: Note 1292 Truncated incorrect datetime value: '1911-11-11 11:11:11.1111119' -show global variables like 'vers_current_time'; +show global variables like 'versioning_current_timestamp'; Variable_name Value -vers_current_time 1911-11-11 11:11:11.111111 +versioning_current_timestamp 1911-11-11 11:11:11.111111 set @ts= timestamp'1900-01-01 00:00:00'; -set global vers_current_time= @ts; -show global variables like 'vers_current_time'; +set global versioning_current_timestamp= @ts; +show global variables like 'versioning_current_timestamp'; Variable_name Value -vers_current_time 1900-01-01 00:00:00.000000 -set vers_current_time= '1911-11-11 11:11:11.1111119'; -show variables like 'vers_current_time'; +versioning_current_timestamp 1900-01-01 00:00:00.000000 +set versioning_current_timestamp= '1911-11-11 11:11:11.1111119'; +show variables like 'versioning_current_timestamp'; Variable_name Value -vers_current_time 1911-11-11 11:11:11.111111 -set vers_current_time= '1900-01-01 00:00:00'; -show variables like 'vers_current_time'; +versioning_current_timestamp 1911-11-11 11:11:11.111111 +set versioning_current_timestamp= '1900-01-01 00:00:00'; +show variables like 'versioning_current_timestamp'; Variable_name Value -vers_current_time 1900-01-01 00:00:00.000000 -set vers_current_time= timestamp'1911-11-11 11:11:11.1111119'; +versioning_current_timestamp 1900-01-01 00:00:00.000000 +set versioning_current_timestamp= timestamp'1911-11-11 11:11:11.1111119'; Warnings: Note 1292 Truncated incorrect datetime value: '1911-11-11 11:11:11.1111119' -show variables like 'vers_current_time'; +show variables like 'versioning_current_timestamp'; Variable_name Value -vers_current_time 1911-11-11 11:11:11.111111 +versioning_current_timestamp 1911-11-11 11:11:11.111111 set @ts= timestamp'1900-01-01 00:00:00'; -set vers_current_time= @ts; -show variables like 'vers_current_time'; +set versioning_current_timestamp= @ts; +show variables like 'versioning_current_timestamp'; Variable_name Value -vers_current_time 1900-01-01 00:00:00.000000 -set global vers_current_time= 'now'; -set vers_current_time= 'now'; -show variables where variable_name = "vers_hide"; +versioning_current_timestamp 1900-01-01 00:00:00.000000 +set global versioning_current_timestamp= 'now'; +set versioning_current_timestamp= 'now'; +show variables where variable_name = "versioning_hide"; Variable_name Value -vers_hide IMPLICIT +versioning_hide IMPLICIT select * from t for system_time all; a 2 1 -set vers_hide= AUTO; +set versioning_hide= AUTO; select * from t; a 2 @@ -123,11 +123,11 @@ select * from t for system_time timestamp between '0-0-0' and current_timestamp( a sys_trx_start sys_trx_end 2 TIMESTAMP TIMESTAMP 1 TIMESTAMP TIMESTAMP -set vers_hide= NEVER; +set versioning_hide= NEVER; select * from t; a sys_trx_start sys_trx_end 2 TIMESTAMP TIMESTAMP -set vers_hide= FULL; +set versioning_hide= FULL; create or replace table t ( x int, st timestamp(6) generated always as row start, @@ -147,4 +147,4 @@ select * from t for system_time all; x 1 drop table t; -set vers_hide= IMPLICIT; +set versioning_hide= IMPLICIT; diff --git a/mysql-test/suite/versioning/t/foreign.opt b/mysql-test/suite/versioning/t/foreign.opt index 61ababdf408..c1a585b67eb 100644 --- a/mysql-test/suite/versioning/t/foreign.opt +++ b/mysql-test/suite/versioning/t/foreign.opt @@ -1 +1 @@ ---vers-hide=implicit +--versioning-hide=implicit diff --git a/mysql-test/suite/versioning/t/partition.opt b/mysql-test/suite/versioning/t/partition.opt index 61ababdf408..c1a585b67eb 100644 --- a/mysql-test/suite/versioning/t/partition.opt +++ b/mysql-test/suite/versioning/t/partition.opt @@ -1 +1 @@ ---vers-hide=implicit +--versioning-hide=implicit diff --git a/mysql-test/suite/versioning/t/rpl_test.opt b/mysql-test/suite/versioning/t/rpl_test.opt index 61ababdf408..c1a585b67eb 100644 --- a/mysql-test/suite/versioning/t/rpl_test.opt +++ b/mysql-test/suite/versioning/t/rpl_test.opt @@ -1 +1 @@ ---vers-hide=implicit +--versioning-hide=implicit diff --git a/mysql-test/suite/versioning/t/sysvars.opt b/mysql-test/suite/versioning/t/sysvars.opt index 61ababdf408..c1a585b67eb 100644 --- a/mysql-test/suite/versioning/t/sysvars.opt +++ b/mysql-test/suite/versioning/t/sysvars.opt @@ -1 +1 @@ ---vers-hide=implicit +--versioning-hide=implicit diff --git a/mysql-test/suite/versioning/t/sysvars.test b/mysql-test/suite/versioning/t/sysvars.test index b6deadb8470..49ee14326f1 100644 --- a/mysql-test/suite/versioning/t/sysvars.test +++ b/mysql-test/suite/versioning/t/sysvars.test @@ -2,20 +2,20 @@ create table t (a int) with system versioning; insert into t values (1); update t set a= 2; -show global variables like 'vers_current_time'; -show variables like 'vers_current_time'; +show global variables like 'versioning_current_timestamp'; +show variables like 'versioning_current_timestamp'; select * from t; -set vers_current_time = '2031-1-1 0:0:0'; -show variables like 'vers_current_time'; +set versioning_current_timestamp = '2031-1-1 0:0:0'; +show variables like 'versioning_current_timestamp'; select * from t; -set vers_current_time = '2011-1-1 0:0:0'; -show variables like 'vers_current_time'; +set versioning_current_timestamp = '2011-1-1 0:0:0'; +show variables like 'versioning_current_timestamp'; select * from t; -set vers_current_time = 'all'; -show variables like 'vers_current_time'; +set versioning_current_timestamp = 'all'; +show variables like 'versioning_current_timestamp'; select * from t; create view vt as select * from t; @@ -26,59 +26,59 @@ select * from (select * from t) as tt; # global --error ER_WRONG_VALUE_FOR_VAR -set global vers_current_time= 'alley'; +set global versioning_current_timestamp= 'alley'; --error ER_WRONG_VALUE_FOR_VAR -set global vers_current_time= null; +set global versioning_current_timestamp= null; --error ER_WRONG_TYPE_FOR_VAR -set global vers_current_time= 1; +set global versioning_current_timestamp= 1; --error ER_WRONG_TYPE_FOR_VAR -set global vers_current_time= 1.1; +set global versioning_current_timestamp= 1.1; # session --error ER_WRONG_VALUE_FOR_VAR -set vers_current_time= 'alley'; +set versioning_current_timestamp= 'alley'; --error ER_WRONG_VALUE_FOR_VAR -set vers_current_time= null; +set versioning_current_timestamp= null; --error ER_WRONG_TYPE_FOR_VAR -set vers_current_time= 1; +set versioning_current_timestamp= 1; --error ER_WRONG_TYPE_FOR_VAR -set vers_current_time= 1.1; +set versioning_current_timestamp= 1.1; # global -set global vers_current_time= '1911-11-11 11:11:11.1111119'; -show global variables like 'vers_current_time'; +set global versioning_current_timestamp= '1911-11-11 11:11:11.1111119'; +show global variables like 'versioning_current_timestamp'; -set global vers_current_time= '1900-01-01 00:00:00'; -show global variables like 'vers_current_time'; +set global versioning_current_timestamp= '1900-01-01 00:00:00'; +show global variables like 'versioning_current_timestamp'; -set global vers_current_time= timestamp'1911-11-11 11:11:11.1111119'; -show global variables like 'vers_current_time'; +set global versioning_current_timestamp= timestamp'1911-11-11 11:11:11.1111119'; +show global variables like 'versioning_current_timestamp'; set @ts= timestamp'1900-01-01 00:00:00'; -set global vers_current_time= @ts; -show global variables like 'vers_current_time'; +set global versioning_current_timestamp= @ts; +show global variables like 'versioning_current_timestamp'; # session -set vers_current_time= '1911-11-11 11:11:11.1111119'; -show variables like 'vers_current_time'; +set versioning_current_timestamp= '1911-11-11 11:11:11.1111119'; +show variables like 'versioning_current_timestamp'; -set vers_current_time= '1900-01-01 00:00:00'; -show variables like 'vers_current_time'; +set versioning_current_timestamp= '1900-01-01 00:00:00'; +show variables like 'versioning_current_timestamp'; -set vers_current_time= timestamp'1911-11-11 11:11:11.1111119'; -show variables like 'vers_current_time'; +set versioning_current_timestamp= timestamp'1911-11-11 11:11:11.1111119'; +show variables like 'versioning_current_timestamp'; set @ts= timestamp'1900-01-01 00:00:00'; -set vers_current_time= @ts; -show variables like 'vers_current_time'; +set versioning_current_timestamp= @ts; +show variables like 'versioning_current_timestamp'; -set global vers_current_time= 'now'; -set vers_current_time= 'now'; +set global versioning_current_timestamp= 'now'; +set versioning_current_timestamp= 'now'; -show variables where variable_name = "vers_hide"; +show variables where variable_name = "versioning_hide"; select * from t for system_time all; -set vers_hide= AUTO; +set versioning_hide= AUTO; select * from t; select * from t for system_time as of timestamp current_timestamp(6); --replace_regex /\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\.\d{6}/TIMESTAMP/ @@ -88,11 +88,11 @@ select * from t for system_time timestamp from '0-0-0' to current_timestamp(6); --replace_regex /\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\.\d{6}/TIMESTAMP/ select * from t for system_time timestamp between '0-0-0' and current_timestamp(6); -set vers_hide= NEVER; +set versioning_hide= NEVER; --replace_regex /\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\.\d{6}/TIMESTAMP/ select * from t; -set vers_hide= FULL; +set versioning_hide= FULL; create or replace table t ( x int, st timestamp(6) generated always as row start, @@ -108,4 +108,4 @@ select * from t; select * from t for system_time all; drop table t; -set vers_hide= IMPLICIT; +set versioning_hide= IMPLICIT; diff --git a/mysql-test/suite/versioning/t/truncate_history.opt b/mysql-test/suite/versioning/t/truncate_history.opt index 61ababdf408..c1a585b67eb 100644 --- a/mysql-test/suite/versioning/t/truncate_history.opt +++ b/mysql-test/suite/versioning/t/truncate_history.opt @@ -1 +1 @@ ---vers-hide=implicit +--versioning-hide=implicit diff --git a/mysql-test/suite/versioning/t/view.opt b/mysql-test/suite/versioning/t/view.opt index 61ababdf408..c1a585b67eb 100644 --- a/mysql-test/suite/versioning/t/view.opt +++ b/mysql-test/suite/versioning/t/view.opt @@ -1 +1 @@ ---vers-hide=implicit +--versioning-hide=implicit diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index f1a674388fc..f1f8f56a546 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -383,17 +383,17 @@ static Sys_var_charptr Sys_basedir( IN_FS_CHARSET, DEFAULT(0)); static Sys_var_vers_asof Sys_vers_current_time( - "vers_current_time", "Default AS OF value for versioned tables", + "versioning_current_timestamp", "Default AS OF value for versioned tables", SESSION_VAR(vers_current_time), CMD_LINE(REQUIRED_ARG, OPT_VERS_CURRENT_TIME), IN_FS_CHARSET, DEFAULT("now")); static Sys_var_mybool Sys_vers_force( - "vers_force", "Force system versioning for all created tables", + "versioning_force", "Force system versioning for all created tables", SESSION_VAR(vers_force), CMD_LINE(OPT_ARG), DEFAULT(FALSE)); static const char *vers_hide_keywords[]= {"AUTO", "IMPLICIT", "FULL", "NEVER", NullS}; static Sys_var_enum Sys_vers_hide( - "vers_hide", "Hide system versioning from being displayed in table info. " + "versioning_hide", "Hide system versioning from being displayed in table info. " "AUTO: hide implicit system fields only in non-versioned and AS OF queries; " "IMPLICIT: hide implicit system fields in all queries; " "FULL: hide any system fields in all queries and hide versioning info in SHOW commands; " @@ -401,7 +401,7 @@ static Sys_var_enum Sys_vers_hide( SESSION_VAR(vers_hide), CMD_LINE(OPT_ARG), vers_hide_keywords, DEFAULT(VERS_HIDE_AUTO)); static Sys_var_mybool Sys_vers_innodb_algorithm_simple( - "vers_innodb_algorithm_simple", + "versioning_innodb_algorithm_simple", "Use simple algorithm of timestamp handling in InnoDB instead of TRX_SEES", SESSION_VAR(vers_innodb_algorithm_simple), CMD_LINE(OPT_ARG), DEFAULT(TRUE)); -- cgit v1.2.1 From f94fd4b730a35183c63c7640606fede20a60e6e4 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 3 May 2017 12:09:17 +0300 Subject: Style: warning fix --- sql/sql_base.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index bf6f2c3931e..8cdc835c0df 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7598,7 +7598,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, if ((sys_field && (thd->lex->sql_command == SQLCOM_CREATE_VIEW || slex->nest_level > 0 || - vers_hide == VERS_HIDE_FULL && thd->lex->sql_command != SQLCOM_CREATE_TABLE)) || + (vers_hide == VERS_HIDE_FULL && thd->lex->sql_command != SQLCOM_CREATE_TABLE))) || ((fl & HIDDEN_FLAG) && ( !sys_field || vers_hide == VERS_HIDE_IMPLICIT || -- cgit v1.2.1 From 018587244977235d9fa2283bde7533eec455a285 Mon Sep 17 00:00:00 2001 From: kevg Date: Mon, 24 Apr 2017 14:47:44 +0300 Subject: SQL: versioning DDL part I [closes #172] --- .../sys_vars/r/sysvars_server_notembedded.result | 14 ++ mysql-test/suite/versioning/r/ddl.result | 176 +++++++++++++++++++++ mysql-test/suite/versioning/t/ddl.test | 104 ++++++++++++ sql/sql_class.h | 1 + sql/sql_table.cc | 169 ++++++++++++++++++-- sql/sys_vars.cc | 4 + storage/innobase/handler/ha_innodb.cc | 3 +- storage/innobase/row/row0mysql.cc | 3 +- 8 files changed, 457 insertions(+), 17 deletions(-) create mode 100644 mysql-test/suite/versioning/r/ddl.result create mode 100644 mysql-test/suite/versioning/t/ddl.test diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result index f46d3abec9e..c9f4e76da69 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result @@ -5133,6 +5133,20 @@ NUMERIC_BLOCK_SIZE NULL ENUM_VALUE_LIST NULL READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED +VARIABLE_NAME VERSIONING_DDL_SURVIVAL +SESSION_VALUE OFF +GLOBAL_VALUE OFF +GLOBAL_VALUE_ORIGIN COMPILE-TIME +DEFAULT_VALUE OFF +VARIABLE_SCOPE SESSION +VARIABLE_TYPE BOOLEAN +VARIABLE_COMMENT Use system versioning DDL survival feature +NUMERIC_MIN_VALUE NULL +NUMERIC_MAX_VALUE NULL +NUMERIC_BLOCK_SIZE NULL +ENUM_VALUE_LIST OFF,ON +READ_ONLY NO +COMMAND_LINE_ARGUMENT OPTIONAL VARIABLE_NAME VERSIONING_FORCE SESSION_VALUE OFF GLOBAL_VALUE OFF diff --git a/mysql-test/suite/versioning/r/ddl.result b/mysql-test/suite/versioning/r/ddl.result new file mode 100644 index 00000000000..80f8469d015 --- /dev/null +++ b/mysql-test/suite/versioning/r/ddl.result @@ -0,0 +1,176 @@ +set @@session.time_zone='+00:00'; +select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +create procedure if not exists verify_vtq() +begin +set @i= 0; +select +@i:= @i + 1 as No, +trx_id > 0 as A, +commit_id > trx_id as B, +begin_ts > '1-1-1 0:0:0' as C, +commit_ts >= begin_ts as D +from information_schema.innodb_vtq +where trx_id > @start_trx_id; +select ifnull(max(trx_id), 0) +into @start_trx_id +from information_schema.innodb_vtq; +end~~ +create function if not exists default_engine() +returns varchar(255) +deterministic +begin +declare e varchar(255); +select lower(engine) from information_schema.engines where support='DEFAULT' into e; +return e; +end~~ +create function if not exists sys_datatype() +returns varchar(255) +deterministic +begin +if default_engine() = 'innodb' then +return 'bigint unsigned'; +elseif default_engine() = 'myisam' then +return 'timestamp(6)'; +end if; +return NULL; +end~~ +create function if not exists sys_commit_ts(sys_field varchar(255)) +returns varchar(255) +deterministic +begin +if default_engine() = 'innodb' then +return concat('vtq_commit_ts(', sys_field, ')'); +elseif default_engine() = 'myisam' then +return sys_field; +end if; +return NULL; +end~~ +create procedure if not exists innodb_verify_vtq(recs int) +begin +declare i int default 1; +if default_engine() = 'innodb' then +call verify_vtq; +elseif default_engine() = 'myisam' then +create temporary table tmp (No int, A bool, B bool, C bool, D bool); +while i <= recs do +insert into tmp values (i, 1, 1, 1, 1); +set i= i + 1; +end while; +select * from tmp; +drop table tmp; +end if; +end~~ +create procedure concat_exec2(a varchar(255), b varchar(255)) +begin +prepare stmt from concat(a, b); +execute stmt; +deallocate prepare stmt; +end~~ +create procedure concat_exec3(a varchar(255), b varchar(255), c varchar(255)) +begin +prepare stmt from concat(a, b, c); +execute stmt; +deallocate prepare stmt; +end~~ +create function get_historical_table_name(table_name_arg varchar(255)) +returns varchar(255) +begin +return (select table_name from information_schema.tables +where table_schema='test' and table_name like concat(table_name_arg, '_%') limit 1); +end~~ +create procedure drop_last_historical(table_name_arg varchar(255)) +begin +call concat_exec2('drop table ', get_historical_table_name(table_name_arg)); +end~~ +set versioning_ddl_survival = 1; +create or replace table t (a int) with system versioning; +insert into t values (1); +update t set a=2 where a=1; +select sys_trx_start from t where a=2 into @tm; +alter table t add column b int; +select * from t; +a b +2 NULL +call concat_exec3('select * from ', get_historical_table_name('t'), ' for system_time all'); +a +2 +1 +call concat_exec3('select @tm=sys_trx_start from ', get_historical_table_name('t'), ' for system_time all where a=2'); +@tm=sys_trx_start +1 +select @tmvariables.time_zone->gmt_sec_to_TIME(&now, thd->query_start()); + now.second_part= thd->query_start_sec_part(); + thd->time_zone_used= 1; + return now; +} + +static void vers_table_name_date(THD *thd, const char *table_name, + char *new_name, size_t new_name_size) +{ + const MYSQL_TIME now= vers_thd_get_now(thd); + my_snprintf(new_name, new_name_size, "%s_%04d%02d%02d_%02d%02d%02d_%06d", + table_name, now.year, now.month, now.day, now.hour, now.minute, + now.second, now.second_part); +} + +bool operator!=(const MYSQL_TIME &lhs, const MYSQL_TIME &rhs) +{ + return lhs.year != rhs.year || lhs.month != rhs.month || lhs.day != rhs.day || + lhs.hour != rhs.hour || lhs.minute != rhs.minute || + lhs.second_part != rhs.second_part || lhs.neg != rhs.neg || + lhs.time_type != rhs.time_type; +} + +// Sets sys_trx_end=MAX for rows with sys_trx_end=now(6) +static bool vers_reset_alter_copy(THD *thd, TABLE *table) +{ + const MYSQL_TIME now= vers_thd_get_now(thd); + + READ_RECORD info; + int error= 0; + bool will_batch= false; + uint dup_key_found= 0; + if (init_read_record(&info, thd, table, NULL, NULL, 0, 1, true)) + goto err; + + will_batch= !table->file->start_bulk_update(); + + while (!(error= info.read_record(&info))) + { + MYSQL_TIME current; + if (table->vers_end_field()->get_date(¤t, 0)) + goto err_read_record; + if (current != now) + { + continue; + } + + store_record(table, record[1]); + table->vers_end_field()->set_max(); + if (will_batch) + error= table->file->ha_bulk_update_row(table->record[1], table->record[0], + &dup_key_found); + else + error= table->file->ha_update_row(table->record[1], table->record[0]); + if (error && table->file->is_fatal_error(error, HA_CHECK_ALL)) + { + table->file->print_error(error, MYF(ME_FATALERROR)); + goto err_read_record; + } + } + + if (will_batch && (error= table->file->exec_bulk_update(&dup_key_found))) + table->file->print_error(error, MYF(ME_FATALERROR)); + if (will_batch) + table->file->end_bulk_update(); + +err_read_record: + end_read_record(&info); + +err: + if (table->file->ha_external_lock(thd, F_UNLCK)) + return true; + + return error ? true : false; +} /** Rename a table. @@ -8602,6 +8681,26 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, bool error= open_tables(thd, &table_list, &tables_opened, 0, &alter_prelocking_strategy); thd->open_options&= ~HA_OPEN_FOR_ALTER; + bool versioned= table_list->table && table_list->table->versioned(); + if (versioned && thd->variables.vers_ddl_survival) + { + table_list->set_lock_type(thd, TL_WRITE); + if (thd->mdl_context.upgrade_shared_lock(table_list->table->mdl_ticket, + MDL_EXCLUSIVE, + thd->variables.lock_wait_timeout)) + { + DBUG_RETURN(true); + } + + if (table_list->table->versioned_by_engine() && + alter_info->requested_algorithm == + Alter_info::ALTER_TABLE_ALGORITHM_DEFAULT && + !table_list->table->s->partition_info_str) + { + // Changle default ALGORITHM to COPY for INNODB + alter_info->requested_algorithm= Alter_info::ALTER_TABLE_ALGORITHM_COPY; + } + } DEBUG_SYNC(thd, "alter_opened_table"); @@ -8914,9 +9013,11 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, Upgrade from MDL_SHARED_UPGRADABLE to MDL_SHARED_NO_WRITE. Afterwards it's safe to take the table level lock. */ - if (thd->mdl_context.upgrade_shared_lock(mdl_ticket, MDL_SHARED_NO_WRITE, - thd->variables.lock_wait_timeout) - || lock_tables(thd, table_list, alter_ctx.tables_opened, 0)) + if ((!(versioned && thd->variables.vers_ddl_survival) && + thd->mdl_context.upgrade_shared_lock( + mdl_ticket, MDL_SHARED_NO_WRITE, + thd->variables.lock_wait_timeout)) || + lock_tables(thd, table_list, alter_ctx.tables_opened, 0)) { DBUG_RETURN(true); } @@ -8981,6 +9082,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, handlerton *new_db_type= create_info->db_type; handlerton *old_db_type= table->s->db_type(); TABLE *new_table= NULL; + bool new_versioned= false; ha_rows copied=0,deleted=0; /* @@ -9315,6 +9417,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, } if (!new_table) goto err_new_table_cleanup; + new_versioned= new_table->versioned(); /* Note: In case of MERGE table, we do not attach children. We do not copy data for MERGE tables. Only the children have data. @@ -9341,7 +9444,18 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, order_num, order, &copied, &deleted, alter_info->keys_onoff, &alter_ctx)) + { + if (versioned && new_versioned && thd->variables.vers_ddl_survival) + { + if (table->versioned_by_sql()) + { + // Failure of this function may result in corruption of + // an original table. + vers_reset_alter_copy(thd, table); + } + } goto err_new_table_cleanup; + } } else { @@ -9436,9 +9550,14 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, Rename the old table to temporary name to have a backup in case anything goes wrong while renaming the new table. */ - char backup_name[32]; - my_snprintf(backup_name, sizeof(backup_name), "%s2-%lx-%lx", tmp_file_prefix, - current_pid, thd->thread_id); + char backup_name[FN_LEN]; + if (versioned && thd->variables.vers_ddl_survival) + vers_table_name_date(thd, alter_ctx.table_name, backup_name, + sizeof(backup_name)); + else + my_snprintf(backup_name, sizeof(backup_name), "%s2-%lx-%lx", + tmp_file_prefix, current_pid, thd->thread_id); + if (lower_case_table_names) my_casedn_str(files_charset_info, backup_name); if (mysql_rename_table(old_db_type, alter_ctx.db, alter_ctx.table_name, @@ -9490,7 +9609,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, } // ALTER TABLE succeeded, delete the backup of the old table. - if (quick_rm_table(thd, old_db_type, alter_ctx.db, backup_name, FN_IS_TMP)) + if (!(versioned && new_versioned && thd->variables.vers_ddl_survival) && + quick_rm_table(thd, old_db_type, alter_ctx.db, backup_name, FN_IS_TMP)) { /* The fact that deletion of the backup failed is not critical @@ -9674,7 +9794,8 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, Field **dfield_ptr= to->default_field; bool make_versioned= !from->versioned() && to->versioned(); bool make_unversioned= from->versioned() && !to->versioned(); - Field *to_sys_trx_start= NULL, *from_sys_trx_end= NULL, *to_sys_trx_end= NULL; + bool keep_versioned= from->versioned() && to->versioned(); + Field *to_sys_trx_start= NULL, *to_sys_trx_end= NULL, *from_sys_trx_end= NULL; MYSQL_TIME now; DBUG_ENTER("copy_data_between_tables"); @@ -9777,19 +9898,26 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, if (make_versioned) { - thd->variables.time_zone->gmt_sec_to_TIME(&now, thd->query_start()); - now.second_part= thd->query_start_sec_part(); - thd->time_zone_used= 1; - to_sys_trx_start= to->field[to->s->row_start_field]; - to_sys_trx_end= to->field[to->s->row_end_field]; + now= vers_thd_get_now(thd); + to_sys_trx_start= to->vers_start_field(); + to_sys_trx_end= to->vers_end_field(); } else if (make_unversioned) { - from_sys_trx_end= from->field[from->s->row_end_field]; + from_sys_trx_end= from->vers_end_field(); } - else if (from->versioned() && to->versioned()) + else if (keep_versioned) { to->file->vers_auto_decrement= 0xffffffffffffffff; + if (thd->variables.vers_ddl_survival) + { + thd->variables.time_zone->gmt_sec_to_TIME(&now, thd->query_start()); + now.second_part= thd->query_start_sec_part(); + thd->time_zone_used= 1; + + from_sys_trx_end= from->vers_end_field(); + to_sys_trx_start= to->vers_start_field(); + } } THD_STAGE_INFO(thd, stage_copy_to_tmp_table); @@ -9863,6 +9991,17 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, if (!from_sys_trx_end->is_max()) continue; } + else if (keep_versioned && thd->variables.vers_ddl_survival) + { + // Do not copy history rows. + if (!from_sys_trx_end->is_max()) + continue; + + store_record(from, record[1]); + from->vers_end_field()->store_time(&now); + from->file->ha_update_row(from->record[1], from->record[0]); + to_sys_trx_start->store_time(&now); + } prev_insert_id= to->file->next_insert_id; if (to->default_field) diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index f1f8f56a546..c618a4f4bc2 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -406,6 +406,10 @@ static Sys_var_mybool Sys_vers_innodb_algorithm_simple( SESSION_VAR(vers_innodb_algorithm_simple), CMD_LINE(OPT_ARG), DEFAULT(TRUE)); +static Sys_var_mybool Sys_vers_ddl_survival( + "versioning_ddl_survival", "Use system versioning DDL survival feature", + SESSION_VAR(vers_ddl_survival), CMD_LINE(OPT_ARG), DEFAULT(FALSE)); + static Sys_var_ulonglong Sys_binlog_cache_size( "binlog_cache_size", "The size of the transactional cache for " "updates to transactional engines for the binary log. " diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index bd8eb6b4d88..bf21abe765c 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -9530,7 +9530,8 @@ ha_innobase::update_row( error = row_update_for_mysql((byte*) old_row, m_prebuilt, vers_set_fields); - if (error == DB_SUCCESS && vers_set_fields) { + if (error == DB_SUCCESS && vers_set_fields && + thd_sql_command(m_user_thd) != SQLCOM_ALTER_TABLE) { if (trx->id != static_cast(table->vers_start_field()->val_int())) error = row_insert_for_mysql((byte*) old_row, m_prebuilt, ROW_INS_HISTORICAL); } diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 3631022228b..07150dbaaa3 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -2004,7 +2004,8 @@ run_again: upd_field_t* ufield; dict_col_t* col; unsigned col_idx; - if (node->is_delete) { + if (node->is_delete || + thd_sql_command(trx->mysql_thd) == SQLCOM_ALTER_TABLE) { ufield = &uvect->fields[0]; uvect->n_fields = 0; node->is_delete = false; -- cgit v1.2.1 From f751b30884c09be2f2ff6282129f8c023f44d265 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 3 May 2017 14:28:15 +0300 Subject: Style: comment fixes --- sql/sql_table.cc | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index a5afcfbd9a5..268c8bd7ac2 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -9449,8 +9449,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, { if (table->versioned_by_sql()) { - // Failure of this function may result in corruption of - // an original table. + // Failure of this function may result in corruption of an original table. vers_reset_alter_copy(thd, table); } } @@ -9987,15 +9986,13 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, } else if (make_unversioned) { - // Drop history rows. if (!from_sys_trx_end->is_max()) - continue; + continue; // Drop history rows. } else if (keep_versioned && thd->variables.vers_ddl_survival) { - // Do not copy history rows. if (!from_sys_trx_end->is_max()) - continue; + continue; // Do not copy history rows. store_record(from, record[1]); from->vers_end_field()->store_time(&now); -- cgit v1.2.1 From 7445be89afca1a0f7ab427f130e776728fe3163f Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Thu, 11 May 2017 12:29:14 +0300 Subject: IB: correct way of using start_time_micro [fixes #189] --- storage/innobase/row/row0ins.cc | 2 +- storage/innobase/trx/trx0purge.cc | 1 + storage/innobase/trx/trx0trx.cc | 20 +++++++++----------- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index c107ae6e01b..9fb473aadfa 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -3985,7 +3985,7 @@ void vers_notify_vtq(trx_t* trx) timeval begin_ts, commit_ts; begin_ts.tv_sec = trx->start_time; - begin_ts.tv_usec = trx->start_time_micro; + begin_ts.tv_usec = trx->start_time_micro % 1000000; mutex_enter(&trx_sys->mutex); trx_id_t commit_id = trx_sys_get_new_trx_id(); diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index 39e042d3756..ea243061b0e 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -185,6 +185,7 @@ trx_purge_graph_build(sess_t* sess) trx->id = 0; ut_usectime((ulong *)&trx->start_time, (ulong *)&trx->start_time_micro); + trx->start_time_micro += trx->start_time * 1000000; trx->state = TRX_STATE_ACTIVE; trx->op_info = "purge trx"; diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index aaa8a610bf0..a7d0071c67e 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -882,6 +882,7 @@ trx_resurrect_insert( ut_usectime((ulong *)&trx->start_time, (ulong *)&trx->start_time_micro); + trx->start_time_micro += trx->start_time * 1000000; } if (undo->dict_operation) { @@ -983,6 +984,7 @@ trx_resurrect_update( || trx->state == TRX_STATE_PREPARED) { ut_usectime((ulong *)&trx->start_time, (ulong *)&trx->start_time_micro); + trx->start_time_micro += trx->start_time * 1000000; } if (undo->dict_operation) { @@ -1351,18 +1353,14 @@ trx_start_low( } } - ut_usectime((ulong *)&trx->start_time, - (ulong *)&trx->start_time_micro); + if (trx->mysql_thd != NULL && + (trx->start_time_micro = thd_query_start_micro(trx->mysql_thd))) { + trx->start_time = trx->start_time_micro / 1000000; - if (trx->mysql_thd != NULL) { - time_t start_time = thd_start_time_in_secs(trx->mysql_thd); - ib_uint64_t start_utime = thd_query_start_micro(trx->mysql_thd); - if (start_time < trx->start_time || - (start_time == trx->start_time && start_utime < trx->start_time_micro)) - { - trx->start_time = start_time; - trx->start_time_micro = start_utime; - } + } else { + ut_usectime((ulong *)&trx->start_time, + (ulong *)&trx->start_time_micro); + trx->start_time_micro += trx->start_time * 1000000; } trx->vtq_notify_on_commit = false; -- cgit v1.2.1 From fe71bdf568f2ea026ab9b2330831281bd58ed222 Mon Sep 17 00:00:00 2001 From: kevg Date: Sun, 14 May 2017 21:33:01 +0300 Subject: Tests: order independence of versioning fields --- mysql-test/suite/versioning/r/update.result | 4 ++-- mysql-test/suite/versioning/t/update.test | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mysql-test/suite/versioning/r/update.result b/mysql-test/suite/versioning/r/update.result index c0e7a87f03b..3c62fa0a14b 100644 --- a/mysql-test/suite/versioning/r/update.result +++ b/mysql-test/suite/versioning/r/update.result @@ -170,9 +170,9 @@ begin set @str= concat(' create table t1( x int unsigned, - y int unsigned, - sys_start ', sys_type, ' generated always as row start, sys_end ', sys_type, ' generated always as row end, + sys_start ', sys_type, ' generated always as row start, + y int unsigned, period for system_time (sys_start, sys_end), primary key(x, y)) with system versioning diff --git a/mysql-test/suite/versioning/t/update.test b/mysql-test/suite/versioning/t/update.test index bec4aef208c..b7e0c1fc85f 100644 --- a/mysql-test/suite/versioning/t/update.test +++ b/mysql-test/suite/versioning/t/update.test @@ -124,9 +124,9 @@ begin set @str= concat(' create table t1( x int unsigned, - y int unsigned, - sys_start ', sys_type, ' generated always as row start, sys_end ', sys_type, ' generated always as row end, + sys_start ', sys_type, ' generated always as row start, + y int unsigned, period for system_time (sys_start, sys_end), primary key(x, y)) with system versioning -- cgit v1.2.1 From ec0002e908c3f8f946a71fa07adfee7d106961b2 Mon Sep 17 00:00:00 2001 From: kevg Date: Thu, 18 May 2017 16:44:29 +0300 Subject: Parser: useful attributes for AS ROW fields --- mysql-test/suite/versioning/r/create.result | 8 ++++---- mysql-test/suite/versioning/t/create.test | 4 ++-- sql/sql_yacc.yy | 17 +++++++++++++++-- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/mysql-test/suite/versioning/r/create.result b/mysql-test/suite/versioning/r/create.result index 74bf5beb710..4e76063a52a 100644 --- a/mysql-test/suite/versioning/r/create.result +++ b/mysql-test/suite/versioning/r/create.result @@ -63,16 +63,16 @@ end~~ drop table if exists t1; create table t1 ( x1 int unsigned, -Sys_start SYS_TRX_TYPE generated always as row start, -Sys_end SYS_TRX_TYPE generated always as row end, +Sys_start SYS_TRX_TYPE generated always as row start comment 'start', +Sys_end SYS_TRX_TYPE generated always as row end comment 'end', period for system_time (Sys_start, Sys_end) ) with system versioning; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `x1` int(10) unsigned DEFAULT NULL, - `Sys_start` SYS_TRX_TYPE GENERATED ALWAYS AS ROW START, - `Sys_end` SYS_TRX_TYPE GENERATED ALWAYS AS ROW END, + `Sys_start` SYS_TRX_TYPE GENERATED ALWAYS AS ROW START COMMENT 'start', + `Sys_end` SYS_TRX_TYPE GENERATED ALWAYS AS ROW END COMMENT 'end', PERIOD FOR SYSTEM_TIME (`Sys_start`, `Sys_end`) ) ENGINE=INNODB_OR_MYISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING # Implicit fields test diff --git a/mysql-test/suite/versioning/t/create.test b/mysql-test/suite/versioning/t/create.test index ba860365dc1..a51e50f5deb 100644 --- a/mysql-test/suite/versioning/t/create.test +++ b/mysql-test/suite/versioning/t/create.test @@ -9,8 +9,8 @@ drop table if exists t1; --replace_result "bigint unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE eval create table t1 ( x1 int unsigned, - Sys_start $sys_datatype generated always as row start, - Sys_end $sys_datatype generated always as row end, + Sys_start $sys_datatype generated always as row start comment 'start', + Sys_end $sys_datatype generated always as row end comment 'end', period for system_time (Sys_start, Sys_end) ) with system versioning; --replace_result InnoDB INNODB_OR_MYISAM MyISAM INNODB_OR_MYISAM "bigint(20) unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 4abe1dbc24a..8f02a033210 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -6262,6 +6262,15 @@ opt_serial_attribute_list: | serial_attribute ; +opt_asrow_attribute: + /* empty */ {} + | opt_asrow_attribute_list {} + ; + +opt_asrow_attribute_list: + opt_asrow_attribute_list asrow_attribute {} + | asrow_attribute + ; field_def: opt_attribute @@ -6271,7 +6280,7 @@ field_def: Lex->last_field->flags&= ~NOT_NULL_FLAG; // undo automatic NOT NULL for timestamps } vcol_opt_specifier vcol_opt_attribute - | opt_generated_always AS ROW_SYM start_or_end + | opt_generated_always AS ROW_SYM start_or_end opt_asrow_attribute { LEX *lex= Lex; Vers_parse_info &info= lex->vers_get_info(); @@ -6743,7 +6752,7 @@ attribute: | serial_attribute ; -serial_attribute: +asrow_attribute: not NULL_SYM { Lex->last_field->flags|= NOT_NULL_FLAG; @@ -6768,6 +6777,10 @@ serial_attribute: lex->alter_info.flags|= Alter_info::ALTER_ADD_INDEX; } | COMMENT_SYM TEXT_STRING_sys { Lex->last_field->comment= $2; } + ; + +serial_attribute: + asrow_attribute | IDENT_sys equal TEXT_STRING_sys { if ($3.length > ENGINE_OPTION_MAX_LENGTH) -- cgit v1.2.1 From abba11e6c4bd992c6c380ad73dfde1f7f4d438d7 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Fri, 19 May 2017 01:40:11 +0300 Subject: SQL: fix fix_create_like() --- sql/handler.cc | 43 ++++++++++++++++++++++++++++++------------- sql/handler.h | 2 +- sql/sql_table.cc | 2 +- 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/sql/handler.cc b/sql/handler.cc index b66e616dfda..1d21d499dde 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6926,28 +6926,45 @@ bool Vers_parse_info::check_and_fix_alter(THD *thd, Alter_info *alter_info, } bool Vers_parse_info::fix_create_like(THD *thd, Alter_info *alter_info, - HA_CREATE_INFO *create_info) + HA_CREATE_INFO *create_info, TABLE_LIST *table) { List_iterator it(alter_info->create_list); - Create_field *f= NULL; + Create_field *f, *f_start=NULL, *f_end= NULL; DBUG_ASSERT(alter_info->create_list.elements > 2); - for (uint i= 0; i < alter_info->create_list.elements - 1; ++i) - f= it++; - DBUG_ASSERT(f->flags & VERS_SYS_START_FLAG); - if (create_string(thd->mem_root, &generated_as_row.start, f->field_name) || - create_string(thd->mem_root, &period_for_system_time.start, - f->field_name)) + while ((f= it++)) + { + if (f->flags & VERS_SYS_START_FLAG) + { + f_start= f; + if (f_end) + break; + } + else if (f->flags & VERS_SYS_END_FLAG) + { + f_end= f; + if (f_start) + break; + } + } + + if (!f_start || !f_end) + { + my_error(ER_VERS_WRONG_PARAMS, MYF(0), table->table_name, + "Missed one of system versioning fields from source"); return true; + } - f= it++; - DBUG_ASSERT(f->flags & VERS_SYS_END_FLAG); - if (create_string(thd->mem_root, &generated_as_row.end, f->field_name) || - create_string(thd->mem_root, &period_for_system_time.end, f->field_name)) + if (create_string(thd->mem_root, &generated_as_row.start, f_start->field_name) || + create_string(thd->mem_root, &period_for_system_time.start, f_start->field_name) || + create_string(thd->mem_root, &generated_as_row.end, f_end->field_name) || + create_string(thd->mem_root, &period_for_system_time.end, f_end->field_name)) + { + sql_print_error("Failed to allocate memory for Vers_parse_info::fix_create_like()"); return true; + } create_info->options|= HA_VERSIONED_TABLE; - return false; } diff --git a/sql/handler.h b/sql/handler.h index 76d6bae734f..c46ee422565 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1728,7 +1728,7 @@ public: bool check_and_fix_alter(THD *thd, Alter_info *alter_info, HA_CREATE_INFO *create_info, TABLE_SHARE *share); bool fix_create_like(THD *thd, Alter_info *alter_info, - HA_CREATE_INFO *create_info); + HA_CREATE_INFO *create_info, TABLE_LIST *table); /** User has added 'WITH SYSTEM VERSIONING' to table definition */ bool declared_with_system_versioning : 1; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 268c8bd7ac2..bbfe78ac4b2 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5459,7 +5459,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, if (src_table->table->versioned() && local_create_info.vers_info.fix_create_like(thd, &local_alter_info, - &local_create_info)) + &local_create_info, src_table)) { goto err; } -- cgit v1.2.1 From 45f6acd2964a89c933077b9c6cf66009bcc91de7 Mon Sep 17 00:00:00 2001 From: kevg Date: Fri, 19 May 2017 23:27:40 +0300 Subject: Scripts: VTMD table [closes #122] --- mysql-test/r/1st.result | 1 + mysql-test/r/connect.result | 3 +++ mysql-test/r/ctype_upgrade.result | 2 ++ mysql-test/r/derived_view.result | 2 ++ mysql-test/r/information_schema.result | 5 +++-- mysql-test/r/information_schema_all_engines.result | 2 +- mysql-test/r/join.result | 1 + mysql-test/r/log_tables_upgrade.result | 1 + mysql-test/r/mysql_upgrade-6984.result | 6 ++++++ mysql-test/r/mysql_upgrade.result | 12 ++++++++++- mysql-test/r/mysql_upgrade_no_innodb.result | 6 ++++++ mysql-test/r/mysql_upgrade_noengine.result | 3 +++ mysql-test/r/mysql_upgrade_ssl.result | 1 + mysql-test/r/mysql_upgrade_view.result | 18 +++++++++++++++++ mysql-test/r/mysqlbinlog_row_compressed.result | 16 +++++++-------- mysql-test/r/mysqlbinlog_row_minimal.result | 16 +++++++-------- mysql-test/r/mysqlcheck.result | 9 +++++++++ mysql-test/r/ps.result | 3 +++ mysql-test/r/system_mysql_db.result | 1 + mysql-test/r/system_mysql_db_fix40123.result | 1 + mysql-test/r/system_mysql_db_fix50030.result | 1 + mysql-test/r/system_mysql_db_fix50117.result | 1 + .../suite/encryption/r/encrypt_and_grep.result | 5 ++++- .../r/innodb-key-rotation-disable.result | 1 + .../suite/encryption/r/innodb-spatial-index.result | 1 + .../suite/encryption/t/debug_key_management.test | 4 ++-- .../suite/encryption/t/encrypt_and_grep.test | 2 +- mysql-test/suite/funcs_1/r/is_columns.result | 1 + mysql-test/suite/funcs_1/r/is_columns_mysql.result | 10 ++++++++++ .../suite/funcs_1/r/is_key_column_usage.result | 1 + mysql-test/suite/funcs_1/r/is_statistics.result | 1 + .../suite/funcs_1/r/is_statistics_mysql.result | 1 + .../suite/funcs_1/r/is_table_constraints.result | 1 + .../funcs_1/r/is_table_constraints_mysql.result | 1 + mysql-test/suite/funcs_1/r/is_tables_mysql.result | 23 ++++++++++++++++++++++ mysql-test/suite/versioning/r/ddl.result | 13 ++++++++++++ mysql-test/suite/versioning/t/ddl.test | 3 +++ mysql-test/t/system_mysql_db_fix40123.test | 2 +- mysql-test/t/system_mysql_db_fix50030.test | 2 +- mysql-test/t/system_mysql_db_fix50117.test | 2 +- scripts/mysql_system_tables.sql | 15 ++++++++++++++ 41 files changed, 173 insertions(+), 27 deletions(-) diff --git a/mysql-test/r/1st.result b/mysql-test/r/1st.result index f9e4b37aa94..1c4000c9a6a 100644 --- a/mysql-test/r/1st.result +++ b/mysql-test/r/1st.result @@ -37,3 +37,4 @@ time_zone_name time_zone_transition time_zone_transition_type user +vtmd_template diff --git a/mysql-test/r/connect.result b/mysql-test/r/connect.result index dfe4406605e..e3e2e4db39c 100644 --- a/mysql-test/r/connect.result +++ b/mysql-test/r/connect.result @@ -33,6 +33,7 @@ time_zone_name time_zone_transition time_zone_transition_type user +vtmd_template connect con2,localhost,root,,test; show tables; Tables_in_test @@ -80,6 +81,7 @@ time_zone_name time_zone_transition time_zone_transition_type user +vtmd_template connect con4,localhost,test,gambling,test; show tables; Tables_in_test @@ -139,6 +141,7 @@ time_zone_name time_zone_transition time_zone_transition_type user +vtmd_template connect con6,localhost,test,gambling3,test; show tables; Tables_in_test diff --git a/mysql-test/r/ctype_upgrade.result b/mysql-test/r/ctype_upgrade.result index 53cb858035b..e56cfaa617d 100644 --- a/mysql-test/r/ctype_upgrade.result +++ b/mysql-test/r/ctype_upgrade.result @@ -258,6 +258,7 @@ mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK +mysql.vtmd_template OK Phase 2/7: Installing used storage engines... Skipped Phase 3/7: Fixing views Phase 4/7: Running 'mysql_fix_privilege_tables' @@ -316,6 +317,7 @@ mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK +mysql.vtmd_template OK Phase 2/7: Installing used storage engines... Skipped Phase 3/7: Fixing views Phase 4/7: Running 'mysql_fix_privilege_tables' diff --git a/mysql-test/r/derived_view.result b/mysql-test/r/derived_view.result index e986b486bf2..1de3894e278 100644 --- a/mysql-test/r/derived_view.result +++ b/mysql-test/r/derived_view.result @@ -2310,6 +2310,8 @@ Warning 1286 Unknown storage engine 'InnoDB' Warning 1286 Unknown storage engine 'InnoDB' Warning 1286 Unknown storage engine 'InnoDB' Warning 1286 Unknown storage engine 'InnoDB' +Warning 1286 Unknown storage engine 'InnoDB' +Warning 1286 Unknown storage engine 'InnoDB' DROP TABLE t1; SET SESSION optimizer_switch= @save_optimizer_switch; # diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index dad6d5d8c8a..6a6b5e0616a 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -123,6 +123,7 @@ time_zone_transition time_zone_transition_type user v1 +vtmd_template select c,table_name from v1 inner join information_schema.TABLES v2 on (v1.c=v2.table_name) where v1.c like "t%"; @@ -1334,12 +1335,12 @@ DROP PROCEDURE p1; DROP USER mysql_bug20230@localhost; SELECT MAX(table_name) FROM information_schema.tables WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test') and table_name not like 'xtradb%'; MAX(table_name) -VIEWS +vtmd_template SELECT table_name from information_schema.tables WHERE table_name=(SELECT MAX(table_name) FROM information_schema.tables WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test') and table_name not like 'xtradb%'); table_name -VIEWS +vtmd_template DROP TABLE IF EXISTS bug23037; DROP FUNCTION IF EXISTS get_value; SELECT COLUMN_NAME, MD5(COLUMN_DEFAULT), LENGTH(COLUMN_DEFAULT) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='bug23037'; diff --git a/mysql-test/r/information_schema_all_engines.result b/mysql-test/r/information_schema_all_engines.result index 126a6f4bccd..8a92f0226ff 100644 --- a/mysql-test/r/information_schema_all_engines.result +++ b/mysql-test/r/information_schema_all_engines.result @@ -454,4 +454,4 @@ Wildcard: inf_rmation_schema SELECT table_schema, count(*) FROM information_schema.TABLES WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test', 'mysqltest') GROUP BY TABLE_SCHEMA; table_schema count(*) information_schema 64 -mysql 30 +mysql 31 diff --git a/mysql-test/r/join.result b/mysql-test/r/join.result index be497475f4d..00b62ca44d0 100644 --- a/mysql-test/r/join.result +++ b/mysql-test/r/join.result @@ -762,6 +762,7 @@ user User def mysql 0 mysql PRIMARY 2 A NULL NULL BTREE def mysql NO char 80 Warnings: Warning 1286 Unknown storage engine 'InnoDB' Warning 1286 Unknown storage engine 'InnoDB' +Warning 1286 Unknown storage engine 'InnoDB' drop table t1; drop table t2; drop table t3; diff --git a/mysql-test/r/log_tables_upgrade.result b/mysql-test/r/log_tables_upgrade.result index a56d067c2cd..a8352824aa4 100644 --- a/mysql-test/r/log_tables_upgrade.result +++ b/mysql-test/r/log_tables_upgrade.result @@ -43,6 +43,7 @@ mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK +mysql.vtmd_template OK Phase 2/7: Installing used storage engines... Skipped Phase 3/7: Fixing views Phase 4/7: Running 'mysql_fix_privilege_tables' diff --git a/mysql-test/r/mysql_upgrade-6984.result b/mysql-test/r/mysql_upgrade-6984.result index 59c9a865b7c..2b995ad5364 100644 --- a/mysql-test/r/mysql_upgrade-6984.result +++ b/mysql-test/r/mysql_upgrade-6984.result @@ -34,6 +34,9 @@ mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK +mysql.vtmd_template +Error : Unknown storage engine 'InnoDB' +error : Corrupt Repairing tables mysql.innodb_index_stats @@ -42,6 +45,9 @@ error : Corrupt mysql.innodb_table_stats Error : Unknown storage engine 'InnoDB' error : Corrupt +mysql.vtmd_template +Error : Unknown storage engine 'InnoDB' +error : Corrupt Phase 2/7: Installing used storage engines... Skipped Phase 3/7: Fixing views Phase 4/7: Running 'mysql_fix_privilege_tables' diff --git a/mysql-test/r/mysql_upgrade.result b/mysql-test/r/mysql_upgrade.result index a337a939acc..194a118f0e4 100644 --- a/mysql-test/r/mysql_upgrade.result +++ b/mysql-test/r/mysql_upgrade.result @@ -31,6 +31,7 @@ mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK +mysql.vtmd_template OK Phase 2/7: Installing used storage engines... Skipped Phase 3/7: Fixing views Phase 4/7: Running 'mysql_fix_privilege_tables' @@ -79,6 +80,7 @@ mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK +mysql.vtmd_template OK Phase 2/7: Installing used storage engines... Skipped Phase 3/7: Fixing views Phase 4/7: Running 'mysql_fix_privilege_tables' @@ -127,6 +129,7 @@ mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK +mysql.vtmd_template OK Phase 2/7: Installing used storage engines... Skipped Phase 3/7: Fixing views Phase 4/7: Running 'mysql_fix_privilege_tables' @@ -180,6 +183,7 @@ mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK +mysql.vtmd_template OK Phase 2/7: Installing used storage engines... Skipped Phase 3/7: Fixing views Phase 4/7: Running 'mysql_fix_privilege_tables' @@ -234,6 +238,7 @@ mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK +mysql.vtmd_template OK Phase 2/7: Installing used storage engines... Skipped Phase 3/7: Fixing views Phase 4/7: Running 'mysql_fix_privilege_tables' @@ -291,6 +296,7 @@ mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK +mysql.vtmd_template OK Phase 2/7: Installing used storage engines... Skipped Phase 3/7: Fixing views Phase 4/7: Running 'mysql_fix_privilege_tables' @@ -343,6 +349,7 @@ mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK +mysql.vtmd_template OK Phase 2/7: Installing used storage engines... Skipped Phase 3/7: Fixing views... Skipped Phase 4/7: Running 'mysql_fix_privilege_tables' @@ -387,6 +394,7 @@ mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK +mysql.vtmd_template OK Phase 2/7: Installing used storage engines... Skipped Phase 3/7: Fixing views Phase 4/7: Running 'mysql_fix_privilege_tables' @@ -452,6 +460,7 @@ mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK +mysql.vtmd_template OK Phase 2/7: Installing used storage engines... Skipped Phase 3/7: Fixing views Phase 4/7: Running 'mysql_fix_privilege_tables' @@ -511,6 +520,7 @@ mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK +mysql.vtmd_template OK Phase 2/7: Installing used storage engines... Skipped Phase 3/7: Fixing views Phase 4/7: Running 'mysql_fix_privilege_tables' @@ -529,7 +539,7 @@ OK # Should return 2 SELECT count(*) FROM information_schema.tables where ENGINE="InnoDB"; count(*) -2 +3 SHOW CREATE TABLE test.t1; Table Create Table t1 CREATE TABLE `t1` ( diff --git a/mysql-test/r/mysql_upgrade_no_innodb.result b/mysql-test/r/mysql_upgrade_no_innodb.result index 6ad818278f8..22e88e27775 100644 --- a/mysql-test/r/mysql_upgrade_no_innodb.result +++ b/mysql-test/r/mysql_upgrade_no_innodb.result @@ -34,6 +34,9 @@ mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK +mysql.vtmd_template +Error : Unknown storage engine 'InnoDB' +error : Corrupt Repairing tables mysql.innodb_index_stats @@ -42,6 +45,9 @@ error : Corrupt mysql.innodb_table_stats Error : Unknown storage engine 'InnoDB' error : Corrupt +mysql.vtmd_template +Error : Unknown storage engine 'InnoDB' +error : Corrupt Phase 2/7: Installing used storage engines... Skipped Phase 3/7: Fixing views... Skipped Phase 4/7: Running 'mysql_fix_privilege_tables' diff --git a/mysql-test/r/mysql_upgrade_noengine.result b/mysql-test/r/mysql_upgrade_noengine.result index 09e705abb69..582147d09df 100644 --- a/mysql-test/r/mysql_upgrade_noengine.result +++ b/mysql-test/r/mysql_upgrade_noengine.result @@ -81,6 +81,7 @@ mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK +mysql.vtmd_template OK Phase 2/7: Installing used storage engines... Skipped Phase 3/7: Fixing views Phase 4/7: Running 'mysql_fix_privilege_tables' @@ -167,6 +168,7 @@ mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK +mysql.vtmd_template OK Phase 2/7: Installing used storage engines... Skipped Phase 3/7: Fixing views Phase 4/7: Running 'mysql_fix_privilege_tables' @@ -253,6 +255,7 @@ mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK +mysql.vtmd_template OK Upgrading from a version before MariaDB-10.1 Phase 2/7: Installing used storage engines Checking for tables with unknown storage engine diff --git a/mysql-test/r/mysql_upgrade_ssl.result b/mysql-test/r/mysql_upgrade_ssl.result index 918a24ffc71..0285d4ac095 100644 --- a/mysql-test/r/mysql_upgrade_ssl.result +++ b/mysql-test/r/mysql_upgrade_ssl.result @@ -32,6 +32,7 @@ mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK +mysql.vtmd_template OK Phase 2/7: Installing used storage engines... Skipped Phase 3/7: Fixing views Phase 4/7: Running 'mysql_fix_privilege_tables' diff --git a/mysql-test/r/mysql_upgrade_view.result b/mysql-test/r/mysql_upgrade_view.result index dc31592566a..0092a772bf9 100644 --- a/mysql-test/r/mysql_upgrade_view.result +++ b/mysql-test/r/mysql_upgrade_view.result @@ -98,6 +98,9 @@ mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK +mysql.vtmd_template +Error : Unknown storage engine 'InnoDB' +error : Corrupt Repairing tables mysql.innodb_index_stats @@ -106,6 +109,9 @@ error : Corrupt mysql.innodb_table_stats Error : Unknown storage engine 'InnoDB' error : Corrupt +mysql.vtmd_template +Error : Unknown storage engine 'InnoDB' +error : Corrupt Phase 2/7: Installing used storage engines... Skipped Phase 3/7: Fixing views test.v1 OK @@ -242,6 +248,9 @@ mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK +mysql.vtmd_template +Error : Unknown storage engine 'InnoDB' +error : Corrupt Repairing tables mysql.innodb_index_stats @@ -250,6 +259,9 @@ error : Corrupt mysql.innodb_table_stats Error : Unknown storage engine 'InnoDB' error : Corrupt +mysql.vtmd_template +Error : Unknown storage engine 'InnoDB' +error : Corrupt Phase 2/7: Installing used storage engines... Skipped Phase 3/7: Fixing views from mysql test.v1 OK @@ -361,6 +373,9 @@ mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK +mysql.vtmd_template +Error : Unknown storage engine 'InnoDB' +error : Corrupt Repairing tables mysql.innodb_index_stats @@ -369,6 +384,9 @@ error : Corrupt mysql.innodb_table_stats Error : Unknown storage engine 'InnoDB' error : Corrupt +mysql.vtmd_template +Error : Unknown storage engine 'InnoDB' +error : Corrupt Phase 2/7: Installing used storage engines... Skipped Phase 3/7: Fixing views from mysql test.v1 OK diff --git a/mysql-test/r/mysqlbinlog_row_compressed.result b/mysql-test/r/mysqlbinlog_row_compressed.result index 24fff723ec8..fc44934ef3f 100644 --- a/mysql-test/r/mysqlbinlog_row_compressed.result +++ b/mysql-test/r/mysqlbinlog_row_compressed.result @@ -61,7 +61,7 @@ BEGIN #Q> INSERT INTO t1 VALUES (10, 1, 2, 3, 4, 5, 6, 7, "") # server id 1 end_log_pos 899 CRC32 XXX Table_map: `test`.`t1` mapped to number num # at 899 -# server id 1 end_log_pos 967 CRC32 XXX Write_compressed_rows: table id 30 flags: STMT_END_F +# server id 1 end_log_pos 967 CRC32 XXX Write_compressed_rows: table id 31 flags: STMT_END_F ### INSERT INTO `test`.`t1` ### SET ### @1=10 /* INT meta=0 nullable=0 is_null=0 */ @@ -89,7 +89,7 @@ BEGIN #Q> INSERT INTO t1 VALUES (11, 1, 2, 3, 4, 5, 6, 7, NULL) # server id 1 end_log_pos 1214 CRC32 XXX Table_map: `test`.`t1` mapped to number num # at 1214 -# server id 1 end_log_pos 1281 CRC32 XXX Write_compressed_rows: table id 30 flags: STMT_END_F +# server id 1 end_log_pos 1281 CRC32 XXX Write_compressed_rows: table id 31 flags: STMT_END_F ### INSERT INTO `test`.`t1` ### SET ### @1=11 /* INT meta=0 nullable=0 is_null=0 */ @@ -117,7 +117,7 @@ BEGIN #Q> INSERT INTO t1 VALUES (12, 1, 2, 3, NULL, 5, 6, 7, "A") # server id 1 end_log_pos 1530 CRC32 XXX Table_map: `test`.`t1` mapped to number num # at 1530 -# server id 1 end_log_pos 1596 CRC32 XXX Write_compressed_rows: table id 30 flags: STMT_END_F +# server id 1 end_log_pos 1596 CRC32 XXX Write_compressed_rows: table id 31 flags: STMT_END_F ### INSERT INTO `test`.`t1` ### SET ### @1=12 /* INT meta=0 nullable=0 is_null=0 */ @@ -145,7 +145,7 @@ BEGIN #Q> INSERT INTO t1 VALUES (13, 1, 2, 3, 0, 5, 6, 7, "A") # server id 1 end_log_pos 1842 CRC32 XXX Table_map: `test`.`t1` mapped to number num # at 1842 -# server id 1 end_log_pos 1909 CRC32 XXX Write_compressed_rows: table id 30 flags: STMT_END_F +# server id 1 end_log_pos 1909 CRC32 XXX Write_compressed_rows: table id 31 flags: STMT_END_F ### INSERT INTO `test`.`t1` ### SET ### @1=13 /* INT meta=0 nullable=0 is_null=0 */ @@ -173,7 +173,7 @@ BEGIN #Q> INSERT INTO t2 SELECT * FROM t1 # server id 1 end_log_pos 2134 CRC32 XXX Table_map: `test`.`t2` mapped to number num # at 2134 -# server id 1 end_log_pos 2225 CRC32 XXX Write_compressed_rows: table id 31 flags: STMT_END_F +# server id 1 end_log_pos 2225 CRC32 XXX Write_compressed_rows: table id 32 flags: STMT_END_F ### INSERT INTO `test`.`t2` ### SET ### @1=10 /* INT meta=0 nullable=0 is_null=0 */ @@ -234,7 +234,7 @@ BEGIN #Q> UPDATE t2 SET f4=5 WHERE f4>0 or f4 is NULL # server id 1 end_log_pos 2462 CRC32 XXX Table_map: `test`.`t2` mapped to number num # at 2462 -# server id 1 end_log_pos 2561 CRC32 XXX Update_compressed_rows: table id 31 flags: STMT_END_F +# server id 1 end_log_pos 2561 CRC32 XXX Update_compressed_rows: table id 32 flags: STMT_END_F ### UPDATE `test`.`t2` ### WHERE ### @1=10 /* INT meta=0 nullable=0 is_null=0 */ @@ -314,7 +314,7 @@ BEGIN #Q> DELETE FROM t1 # server id 1 end_log_pos 2769 CRC32 XXX Table_map: `test`.`t1` mapped to number num # at 2769 -# server id 1 end_log_pos 2861 CRC32 XXX Delete_compressed_rows: table id 30 flags: STMT_END_F +# server id 1 end_log_pos 2861 CRC32 XXX Delete_compressed_rows: table id 31 flags: STMT_END_F ### DELETE FROM `test`.`t1` ### WHERE ### @1=10 /* INT meta=0 nullable=0 is_null=0 */ @@ -375,7 +375,7 @@ BEGIN #Q> DELETE FROM t2 # server id 1 end_log_pos 3069 CRC32 XXX Table_map: `test`.`t2` mapped to number num # at 3069 -# server id 1 end_log_pos 3154 CRC32 XXX Delete_compressed_rows: table id 31 flags: STMT_END_F +# server id 1 end_log_pos 3154 CRC32 XXX Delete_compressed_rows: table id 32 flags: STMT_END_F ### DELETE FROM `test`.`t2` ### WHERE ### @1=10 /* INT meta=0 nullable=0 is_null=0 */ diff --git a/mysql-test/r/mysqlbinlog_row_minimal.result b/mysql-test/r/mysqlbinlog_row_minimal.result index ca8e43bfb33..9cdac056078 100644 --- a/mysql-test/r/mysqlbinlog_row_minimal.result +++ b/mysql-test/r/mysqlbinlog_row_minimal.result @@ -59,7 +59,7 @@ BEGIN #Q> INSERT INTO t1 VALUES (10, 1, 2, 3, 4, 5, 6, 7, "") # server id 1 end_log_pos 946 CRC32 XXX Table_map: `test`.`t1` mapped to number num # at 946 -# server id 1 end_log_pos 1015 CRC32 XXX Write_rows: table id 30 flags: STMT_END_F +# server id 1 end_log_pos 1015 CRC32 XXX Write_rows: table id 31 flags: STMT_END_F ### INSERT INTO `test`.`t1` ### SET ### @1=10 /* INT meta=0 nullable=0 is_null=0 */ @@ -87,7 +87,7 @@ BEGIN #Q> INSERT INTO t1 VALUES (11, 1, 2, 3, 4, 5, 6, 7, NULL) # server id 1 end_log_pos 1262 CRC32 XXX Table_map: `test`.`t1` mapped to number num # at 1262 -# server id 1 end_log_pos 1330 CRC32 XXX Write_rows: table id 30 flags: STMT_END_F +# server id 1 end_log_pos 1330 CRC32 XXX Write_rows: table id 31 flags: STMT_END_F ### INSERT INTO `test`.`t1` ### SET ### @1=11 /* INT meta=0 nullable=0 is_null=0 */ @@ -115,7 +115,7 @@ BEGIN #Q> INSERT INTO t1 VALUES (12, 1, 2, 3, NULL, 5, 6, 7, "A") # server id 1 end_log_pos 1579 CRC32 XXX Table_map: `test`.`t1` mapped to number num # at 1579 -# server id 1 end_log_pos 1646 CRC32 XXX Write_rows: table id 30 flags: STMT_END_F +# server id 1 end_log_pos 1646 CRC32 XXX Write_rows: table id 31 flags: STMT_END_F ### INSERT INTO `test`.`t1` ### SET ### @1=12 /* INT meta=0 nullable=0 is_null=0 */ @@ -143,7 +143,7 @@ BEGIN #Q> INSERT INTO t1 VALUES (13, 1, 2, 3, 0, 5, 6, 7, "A") # server id 1 end_log_pos 1892 CRC32 XXX Table_map: `test`.`t1` mapped to number num # at 1892 -# server id 1 end_log_pos 1962 CRC32 XXX Write_rows: table id 30 flags: STMT_END_F +# server id 1 end_log_pos 1962 CRC32 XXX Write_rows: table id 31 flags: STMT_END_F ### INSERT INTO `test`.`t1` ### SET ### @1=13 /* INT meta=0 nullable=0 is_null=0 */ @@ -171,7 +171,7 @@ BEGIN #Q> INSERT INTO t2 SELECT * FROM t1 # server id 1 end_log_pos 2187 CRC32 XXX Table_map: `test`.`t2` mapped to number num # at 2187 -# server id 1 end_log_pos 2354 CRC32 XXX Write_rows: table id 31 flags: STMT_END_F +# server id 1 end_log_pos 2354 CRC32 XXX Write_rows: table id 32 flags: STMT_END_F ### INSERT INTO `test`.`t2` ### SET ### @1=10 /* INT meta=0 nullable=0 is_null=0 */ @@ -232,7 +232,7 @@ BEGIN #Q> UPDATE t2 SET f4=5 WHERE f4>0 or f4 is NULL # server id 1 end_log_pos 2591 CRC32 XXX Table_map: `test`.`t2` mapped to number num # at 2591 -# server id 1 end_log_pos 2665 CRC32 XXX Update_rows: table id 31 flags: STMT_END_F +# server id 1 end_log_pos 2665 CRC32 XXX Update_rows: table id 32 flags: STMT_END_F ### UPDATE `test`.`t2` ### WHERE ### @1=10 /* INT meta=0 nullable=0 is_null=0 */ @@ -267,7 +267,7 @@ BEGIN #Q> DELETE FROM t1 # server id 1 end_log_pos 2873 CRC32 XXX Table_map: `test`.`t1` mapped to number num # at 2873 -# server id 1 end_log_pos 2927 CRC32 XXX Delete_rows: table id 30 flags: STMT_END_F +# server id 1 end_log_pos 2927 CRC32 XXX Delete_rows: table id 31 flags: STMT_END_F ### DELETE FROM `test`.`t1` ### WHERE ### @1=10 /* INT meta=0 nullable=0 is_null=0 */ @@ -296,7 +296,7 @@ BEGIN #Q> DELETE FROM t2 # server id 1 end_log_pos 3135 CRC32 XXX Table_map: `test`.`t2` mapped to number num # at 3135 -# server id 1 end_log_pos 3189 CRC32 XXX Delete_rows: table id 31 flags: STMT_END_F +# server id 1 end_log_pos 3189 CRC32 XXX Delete_rows: table id 32 flags: STMT_END_F ### DELETE FROM `test`.`t2` ### WHERE ### @1=10 /* INT meta=0 nullable=0 is_null=0 */ diff --git a/mysql-test/r/mysqlcheck.result b/mysql-test/r/mysqlcheck.result index ff9cc5d5c81..a2967bd5e5b 100644 --- a/mysql-test/r/mysqlcheck.result +++ b/mysql-test/r/mysqlcheck.result @@ -32,6 +32,7 @@ mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK +mysql.vtmd_template OK mtr.global_suppressions Table is already up to date mtr.test_suppressions Table is already up to date mysql.column_stats OK @@ -66,6 +67,9 @@ mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK +mysql.vtmd_template +note : Table does not support optimize, doing recreate + analyze instead +status : OK mysql.column_stats OK mysql.columns_priv OK mysql.db OK @@ -94,6 +98,7 @@ mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK +mysql.vtmd_template OK mysql.column_stats Table is already up to date mysql.columns_priv Table is already up to date mysql.db Table is already up to date @@ -126,6 +131,9 @@ mysql.time_zone_name Table is already up to date mysql.time_zone_transition Table is already up to date mysql.time_zone_transition_type Table is already up to date mysql.user Table is already up to date +mysql.vtmd_template +note : Table does not support optimize, doing recreate + analyze instead +status : OK create table t1 (a int) engine=myisam; create view v1 as select * from t1; test.t1 OK @@ -448,6 +456,7 @@ mysql.time_zone_name Table is already up to date mysql.time_zone_transition Table is already up to date mysql.time_zone_transition_type Table is already up to date mysql.user Table is already up to date +mysql.vtmd_template OK mysqltest1.t1 warning : Table is marked as crashed warning : Size of datafile is: 4 Should be: 0 diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 567be0d0d3f..317ba5a3283 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -1211,18 +1211,21 @@ COUNT(*) Warnings: Warning 1286 Unknown storage engine 'InnoDB' Warning 1286 Unknown storage engine 'InnoDB' +Warning 1286 Unknown storage engine 'InnoDB' execute my_stmt; COUNT(*) 46 Warnings: Warning 1286 Unknown storage engine 'InnoDB' Warning 1286 Unknown storage engine 'InnoDB' +Warning 1286 Unknown storage engine 'InnoDB' execute my_stmt; COUNT(*) 46 Warnings: Warning 1286 Unknown storage engine 'InnoDB' Warning 1286 Unknown storage engine 'InnoDB' +Warning 1286 Unknown storage engine 'InnoDB' deallocate prepare my_stmt; drop procedure if exists p1| drop table if exists t1| diff --git a/mysql-test/r/system_mysql_db.result b/mysql-test/r/system_mysql_db.result index b88497dbd9b..558b552e2fd 100644 --- a/mysql-test/r/system_mysql_db.result +++ b/mysql-test/r/system_mysql_db.result @@ -30,6 +30,7 @@ time_zone_name time_zone_transition time_zone_transition_type user +vtmd_template show create table db; Table Create Table db CREATE TABLE `db` ( diff --git a/mysql-test/r/system_mysql_db_fix40123.result b/mysql-test/r/system_mysql_db_fix40123.result index b88497dbd9b..558b552e2fd 100644 --- a/mysql-test/r/system_mysql_db_fix40123.result +++ b/mysql-test/r/system_mysql_db_fix40123.result @@ -30,6 +30,7 @@ time_zone_name time_zone_transition time_zone_transition_type user +vtmd_template show create table db; Table Create Table db CREATE TABLE `db` ( diff --git a/mysql-test/r/system_mysql_db_fix50030.result b/mysql-test/r/system_mysql_db_fix50030.result index 14905ab81a0..17252b09912 100644 --- a/mysql-test/r/system_mysql_db_fix50030.result +++ b/mysql-test/r/system_mysql_db_fix50030.result @@ -30,6 +30,7 @@ time_zone_name time_zone_transition time_zone_transition_type user +vtmd_template show create table db; Table Create Table db CREATE TABLE `db` ( diff --git a/mysql-test/r/system_mysql_db_fix50117.result b/mysql-test/r/system_mysql_db_fix50117.result index b88497dbd9b..558b552e2fd 100644 --- a/mysql-test/r/system_mysql_db_fix50117.result +++ b/mysql-test/r/system_mysql_db_fix50117.result @@ -30,6 +30,7 @@ time_zone_name time_zone_transition time_zone_transition_type user +vtmd_template show create table db; Table Create Table db CREATE TABLE `db` ( diff --git a/mysql-test/suite/encryption/r/encrypt_and_grep.result b/mysql-test/suite/encryption/r/encrypt_and_grep.result index b1ffbdb8134..1b468baf6bc 100644 --- a/mysql-test/suite/encryption/r/encrypt_and_grep.result +++ b/mysql-test/suite/encryption/r/encrypt_and_grep.result @@ -13,6 +13,7 @@ SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_ NAME mysql/innodb_table_stats mysql/innodb_index_stats +mysql/vtmd_template test/t1 test/t2 innodb_system @@ -32,12 +33,13 @@ SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_ NAME mysql/innodb_table_stats mysql/innodb_index_stats -test/t2 +mysql/vtmd_template test/t3 innodb_system SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; NAME test/t1 +test/t2 # t1 yes on expecting NOT FOUND NOT FOUND /foobar/ in t1.ibd # t2 ... on expecting FOUND @@ -57,6 +59,7 @@ SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_ NAME mysql/innodb_table_stats mysql/innodb_index_stats +mysql/vtmd_template test/t1 test/t2 innodb_system diff --git a/mysql-test/suite/encryption/r/innodb-key-rotation-disable.result b/mysql-test/suite/encryption/r/innodb-key-rotation-disable.result index feaede20f2a..7b8454aaa86 100644 --- a/mysql-test/suite/encryption/r/innodb-key-rotation-disable.result +++ b/mysql-test/suite/encryption/r/innodb-key-rotation-disable.result @@ -4,6 +4,7 @@ SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_ NAME mysql/innodb_table_stats mysql/innodb_index_stats +mysql/vtmd_template innodb_system create database enctests; use enctests; diff --git a/mysql-test/suite/encryption/r/innodb-spatial-index.result b/mysql-test/suite/encryption/r/innodb-spatial-index.result index 852be0b9a73..f214355718d 100644 --- a/mysql-test/suite/encryption/r/innodb-spatial-index.result +++ b/mysql-test/suite/encryption/r/innodb-spatial-index.result @@ -34,6 +34,7 @@ SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_ NAME mysql/innodb_table_stats mysql/innodb_index_stats +mysql/vtmd_template test/t1 test/t2 innodb_system diff --git a/mysql-test/suite/encryption/t/debug_key_management.test b/mysql-test/suite/encryption/t/debug_key_management.test index 5001ac6a516..edc8745b5f6 100644 --- a/mysql-test/suite/encryption/t/debug_key_management.test +++ b/mysql-test/suite/encryption/t/debug_key_management.test @@ -8,13 +8,13 @@ if (`select count(*) = 0 from information_schema.plugins set global innodb_encrypt_tables=ON; show variables like 'innodb_encrypt%'; -let $wait_condition= select count(*) = 3 from information_schema.innodb_tablespaces_encryption where current_key_version=1; +let $wait_condition= select count(*) = 4 from information_schema.innodb_tablespaces_encryption where current_key_version=1; --source include/wait_condition.inc select count(*) from information_schema.innodb_tablespaces_encryption where current_key_version <> 1; set global debug_key_management_version=10; -let $wait_condition= select count(*) = 3 from information_schema.innodb_tablespaces_encryption where current_key_version=10; +let $wait_condition= select count(*) = 4 from information_schema.innodb_tablespaces_encryption where current_key_version=10; --source include/wait_condition.inc select count(*) from information_schema.innodb_tablespaces_encryption where current_key_version <> 10; diff --git a/mysql-test/suite/encryption/t/encrypt_and_grep.test b/mysql-test/suite/encryption/t/encrypt_and_grep.test index 2ef69db237d..37ebf97f3eb 100644 --- a/mysql-test/suite/encryption/t/encrypt_and_grep.test +++ b/mysql-test/suite/encryption/t/encrypt_and_grep.test @@ -26,7 +26,7 @@ insert t3 values (repeat('dummy', 42)); --echo # Wait max 10 min for key encryption threads to encrypt all spaces --let $wait_timeout= 600 ---let $wait_condition=SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 +--let $wait_condition=SELECT COUNT(*) <= 2 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 --source include/wait_condition.inc SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; diff --git a/mysql-test/suite/funcs_1/r/is_columns.result b/mysql-test/suite/funcs_1/r/is_columns.result index 26a8677495b..62b0bce8ede 100644 --- a/mysql-test/suite/funcs_1/r/is_columns.result +++ b/mysql-test/suite/funcs_1/r/is_columns.result @@ -106,6 +106,7 @@ table_catalog table_schema table_name column_name Warnings: Warning 1286 Unknown storage engine 'InnoDB' Warning 1286 Unknown storage engine 'InnoDB' +Warning 1286 Unknown storage engine 'InnoDB' ############################################################################### # Testcase 3.2.6.2 + 3.2.6.3: INFORMATION_SCHEMA.COLUMNS accessible information ############################################################################### diff --git a/mysql-test/suite/funcs_1/r/is_columns_mysql.result b/mysql-test/suite/funcs_1/r/is_columns_mysql.result index b12574a0dc4..f51c4bfb089 100644 --- a/mysql-test/suite/funcs_1/r/is_columns_mysql.result +++ b/mysql-test/suite/funcs_1/r/is_columns_mysql.result @@ -265,6 +265,11 @@ def mysql user Update_priv 6 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci e def mysql user User 2 NO char 80 240 NULL NULL NULL utf8 utf8_bin char(80) PRI select,insert,update,references NEVER NULL def mysql user x509_issuer 35 NULL NO blob 65535 65535 NULL NULL NULL NULL NULL blob select,insert,update,references NEVER NULL def mysql user x509_subject 36 NULL NO blob 65535 65535 NULL NULL NULL NULL NULL blob select,insert,update,references NEVER NULL +def mysql vtmd_template col_renames 5 NULL YES blob 65535 65535 NULL NULL NULL NULL NULL blob select,insert,update,references Column name mapping from previous lifetime NEVER NULL +def mysql vtmd_template end 2 NULL NO bigint NULL NULL 20 0 NULL NULL NULL bigint(20) unsigned PRI select,insert,update,references TRX_ID of table lifetime end NEVER NULL +def mysql vtmd_template frm_image 4 NULL NO blob 65535 65535 NULL NULL NULL NULL NULL blob select,insert,update,references Table structure during period [start, end) NEVER NULL +def mysql vtmd_template name 3 NULL NO varchar 64 192 NULL NULL NULL utf8 utf8_bin varchar(64) select,insert,update,references Table name during period [start, end) NEVER NULL +def mysql vtmd_template start 1 NULL YES bigint NULL NULL 20 0 NULL NULL NULL bigint(20) unsigned select,insert,update,references TRX_ID of table lifetime start NEVER NULL ########################################################################## # Show the quotient of CHARACTER_OCTET_LENGTH and CHARACTER_MAXIMUM_LENGTH ########################################################################## @@ -600,3 +605,8 @@ NULL mysql user max_user_connections int NULL NULL NULL NULL int(11) 3.0000 mysql user is_role enum 1 3 utf8 utf8_general_ci enum('N','Y') 3.0000 mysql user default_role char 80 240 utf8 utf8_bin char(80) NULL mysql user max_statement_time decimal NULL NULL NULL NULL decimal(12,6) +NULL mysql vtmd_template start bigint NULL NULL NULL NULL bigint(20) unsigned +NULL mysql vtmd_template end bigint NULL NULL NULL NULL bigint(20) unsigned +3.0000 mysql vtmd_template name varchar 64 192 utf8 utf8_bin varchar(64) +1.0000 mysql vtmd_template frm_image blob 65535 65535 NULL NULL blob +1.0000 mysql vtmd_template col_renames blob 65535 65535 NULL NULL blob diff --git a/mysql-test/suite/funcs_1/r/is_key_column_usage.result b/mysql-test/suite/funcs_1/r/is_key_column_usage.result index 80dd2db5441..b90083b6587 100644 --- a/mysql-test/suite/funcs_1/r/is_key_column_usage.result +++ b/mysql-test/suite/funcs_1/r/is_key_column_usage.result @@ -143,6 +143,7 @@ def mysql PRIMARY def mysql time_zone_transition_type Time_zone_id def mysql PRIMARY def mysql time_zone_transition_type Transition_type_id def mysql PRIMARY def mysql user Host def mysql PRIMARY def mysql user User +def mysql PRIMARY def mysql vtmd_template end ######################################################################################## # Testcase 3.2.7.2 + 3.2.7.3: INFORMATION_SCHEMA.KEY_COLUMN_USAGE accessible information ######################################################################################## diff --git a/mysql-test/suite/funcs_1/r/is_statistics.result b/mysql-test/suite/funcs_1/r/is_statistics.result index 749b09fa87d..8f82c04e3da 100644 --- a/mysql-test/suite/funcs_1/r/is_statistics.result +++ b/mysql-test/suite/funcs_1/r/is_statistics.result @@ -154,6 +154,7 @@ def mysql user mysql PRIMARY Warnings: Warning 1286 Unknown storage engine 'InnoDB' Warning 1286 Unknown storage engine 'InnoDB' +Warning 1286 Unknown storage engine 'InnoDB' #################################################################################### # Testcase 3.2.14.2 + 3.2.14.3: INFORMATION_SCHEMA.STATISTICS accessible information #################################################################################### diff --git a/mysql-test/suite/funcs_1/r/is_statistics_mysql.result b/mysql-test/suite/funcs_1/r/is_statistics_mysql.result index dc3ed5f9839..332d85ffbcd 100644 --- a/mysql-test/suite/funcs_1/r/is_statistics_mysql.result +++ b/mysql-test/suite/funcs_1/r/is_statistics_mysql.result @@ -79,6 +79,7 @@ def mysql time_zone_transition_type 0 mysql PRIMARY 1 Time_zone_id A #CARD# NULL def mysql time_zone_transition_type 0 mysql PRIMARY 2 Transition_type_id A #CARD# NULL NULL BTREE def mysql user 0 mysql PRIMARY 1 Host A #CARD# NULL NULL BTREE def mysql user 0 mysql PRIMARY 2 User A #CARD# NULL NULL BTREE +def mysql vtmd_template 0 mysql PRIMARY 1 end A #CARD# NULL NULL BTREE connect testuser1,localhost,testuser1,,db_datadict; SELECT * FROM information_schema.statistics WHERE table_schema = 'mysql' diff --git a/mysql-test/suite/funcs_1/r/is_table_constraints.result b/mysql-test/suite/funcs_1/r/is_table_constraints.result index 37fcce5ae42..9637f24959e 100644 --- a/mysql-test/suite/funcs_1/r/is_table_constraints.result +++ b/mysql-test/suite/funcs_1/r/is_table_constraints.result @@ -88,6 +88,7 @@ def mysql PRIMARY mysql time_zone_name def mysql PRIMARY mysql time_zone_transition def mysql PRIMARY mysql time_zone_transition_type def mysql PRIMARY mysql user +def mysql PRIMARY mysql vtmd_template ######################################################################################### # Testcase 3.2.7.2 + 3.2.7.3: INFORMATION_SCHEMA.TABLE_CONSTRAINTS accessible information ######################################################################################### diff --git a/mysql-test/suite/funcs_1/r/is_table_constraints_mysql.result b/mysql-test/suite/funcs_1/r/is_table_constraints_mysql.result index e54de0671a2..9998f99ab1b 100644 --- a/mysql-test/suite/funcs_1/r/is_table_constraints_mysql.result +++ b/mysql-test/suite/funcs_1/r/is_table_constraints_mysql.result @@ -38,6 +38,7 @@ def mysql PRIMARY mysql time_zone_name PRIMARY KEY def mysql PRIMARY mysql time_zone_transition PRIMARY KEY def mysql PRIMARY mysql time_zone_transition_type PRIMARY KEY def mysql PRIMARY mysql user PRIMARY KEY +def mysql PRIMARY mysql vtmd_template PRIMARY KEY connect testuser1,localhost,testuser1,,db_datadict; SELECT * FROM information_schema.table_constraints WHERE table_schema = 'mysql' diff --git a/mysql-test/suite/funcs_1/r/is_tables_mysql.result b/mysql-test/suite/funcs_1/r/is_tables_mysql.result index 8e0c9b64dab..704bb51f70a 100644 --- a/mysql-test/suite/funcs_1/r/is_tables_mysql.result +++ b/mysql-test/suite/funcs_1/r/is_tables_mysql.result @@ -700,6 +700,29 @@ CREATE_OPTIONS #CO# TABLE_COMMENT #TC# user_comment Users and global privileges Separator ----------------------------------------------------- +TABLE_CATALOG def +TABLE_SCHEMA mysql +TABLE_NAME vtmd_template +TABLE_TYPE BASE TABLE +ENGINE InnoDB +VERSION 10 +ROW_FORMAT DYNAMIC_OR_PAGE +TABLE_ROWS #TBLR# +AVG_ROW_LENGTH #ARL# +DATA_LENGTH #DL# +MAX_DATA_LENGTH #MDL# +INDEX_LENGTH #IL# +DATA_FREE #DF# +AUTO_INCREMENT NULL +CREATE_TIME #CRT# +UPDATE_TIME #UT# +CHECK_TIME #CT# +TABLE_COLLATION utf8_bin +CHECKSUM NULL +CREATE_OPTIONS #CO# +TABLE_COMMENT #TC# +user_comment +Separator ----------------------------------------------------- DROP USER testuser1@localhost; CREATE USER testuser1@localhost; GRANT SELECT ON test1.* TO testuser1@localhost; diff --git a/mysql-test/suite/versioning/r/ddl.result b/mysql-test/suite/versioning/r/ddl.result index 80f8469d015..415d6c54feb 100644 --- a/mysql-test/suite/versioning/r/ddl.result +++ b/mysql-test/suite/versioning/r/ddl.result @@ -161,6 +161,19 @@ drop procedure concat_exec2; drop procedure concat_exec3; drop function get_historical_table_name; drop procedure drop_last_historical; +select * from mysql.vtmd_template; +start end name frm_image col_renames +show create table mysql.vtmd_template; +Table Create Table +vtmd_template CREATE TABLE `vtmd_template` ( + `start` bigint(20) unsigned GENERATED ALWAYS AS ROW START COMMENT 'TRX_ID of table lifetime start', + `end` bigint(20) unsigned NOT NULL GENERATED ALWAYS AS ROW END COMMENT 'TRX_ID of table lifetime end', + `name` varchar(64) COLLATE utf8_bin NOT NULL COMMENT 'Table name during period [start, end)', + `frm_image` blob NOT NULL COMMENT 'Table structure during period [start, end)', + `col_renames` blob DEFAULT NULL COMMENT 'Column name mapping from previous lifetime', + PRIMARY KEY (`end`), + PERIOD FOR SYSTEM_TIME (`start`, `end`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin STATS_PERSISTENT=0 WITH SYSTEM VERSIONING call verify_vtq; No A B C D 1 1 1 1 1 diff --git a/mysql-test/suite/versioning/t/ddl.test b/mysql-test/suite/versioning/t/ddl.test index 7d919209bcd..43c0d588a4f 100644 --- a/mysql-test/suite/versioning/t/ddl.test +++ b/mysql-test/suite/versioning/t/ddl.test @@ -98,6 +98,9 @@ drop procedure concat_exec3; drop function get_historical_table_name; drop procedure drop_last_historical; +select * from mysql.vtmd_template; +show create table mysql.vtmd_template; + call verify_vtq; drop table t; diff --git a/mysql-test/t/system_mysql_db_fix40123.test b/mysql-test/t/system_mysql_db_fix40123.test index fd1212d4ce6..e21f52c7726 100644 --- a/mysql-test/t/system_mysql_db_fix40123.test +++ b/mysql-test/t/system_mysql_db_fix40123.test @@ -72,7 +72,7 @@ CREATE TABLE time_zone_leap_second ( Transition_time bigint signed NOT NULL, -- disable_query_log # Drop all tables created by this test -DROP TABLE db, host, user, func, plugin, tables_priv, columns_priv, procs_priv, servers, help_category, help_keyword, help_relation, help_topic, proc, time_zone, time_zone_leap_second, time_zone_name, time_zone_transition, time_zone_transition_type, general_log, slow_log, event, proxies_priv, innodb_index_stats, innodb_table_stats, table_stats, column_stats, index_stats, roles_mapping, gtid_slave_pos; +DROP TABLE db, host, user, func, plugin, tables_priv, columns_priv, procs_priv, servers, help_category, help_keyword, help_relation, help_topic, proc, time_zone, time_zone_leap_second, time_zone_name, time_zone_transition, time_zone_transition_type, general_log, slow_log, event, proxies_priv, innodb_index_stats, innodb_table_stats, vtmd_template, table_stats, column_stats, index_stats, roles_mapping, gtid_slave_pos; -- enable_query_log diff --git a/mysql-test/t/system_mysql_db_fix50030.test b/mysql-test/t/system_mysql_db_fix50030.test index c3e7dd7b9b1..9c7d4f9f10e 100644 --- a/mysql-test/t/system_mysql_db_fix50030.test +++ b/mysql-test/t/system_mysql_db_fix50030.test @@ -79,7 +79,7 @@ INSERT INTO servers VALUES ('test','localhost','test','root','', 0,'','mysql','r -- disable_query_log # Drop all tables created by this test -DROP TABLE db, host, user, func, plugin, tables_priv, columns_priv, procs_priv, servers, help_category, help_keyword, help_relation, help_topic, proc, time_zone, time_zone_leap_second, time_zone_name, time_zone_transition, time_zone_transition_type, general_log, slow_log, event, proxies_priv, innodb_index_stats, innodb_table_stats, table_stats, column_stats, index_stats, roles_mapping, gtid_slave_pos; +DROP TABLE db, host, user, func, plugin, tables_priv, columns_priv, procs_priv, servers, help_category, help_keyword, help_relation, help_topic, proc, time_zone, time_zone_leap_second, time_zone_name, time_zone_transition, time_zone_transition_type, general_log, slow_log, event, proxies_priv, innodb_index_stats, innodb_table_stats, vtmd_template, table_stats, column_stats, index_stats, roles_mapping, gtid_slave_pos; -- enable_query_log diff --git a/mysql-test/t/system_mysql_db_fix50117.test b/mysql-test/t/system_mysql_db_fix50117.test index dcc765ae132..561a2040160 100644 --- a/mysql-test/t/system_mysql_db_fix50117.test +++ b/mysql-test/t/system_mysql_db_fix50117.test @@ -96,7 +96,7 @@ CREATE TABLE IF NOT EXISTS event ( db char(64) CHARACTER SET utf8 COLLATE utf8_b -- disable_query_log # Drop all tables created by this test -DROP TABLE db, host, user, func, plugin, tables_priv, columns_priv, procs_priv, servers, help_category, help_keyword, help_relation, help_topic, proc, time_zone, time_zone_leap_second, time_zone_name, time_zone_transition, time_zone_transition_type, general_log, slow_log, event, proxies_priv, innodb_index_stats, innodb_table_stats, table_stats, column_stats, index_stats, roles_mapping, gtid_slave_pos; +DROP TABLE db, host, user, func, plugin, tables_priv, columns_priv, procs_priv, servers, help_category, help_keyword, help_relation, help_topic, proc, time_zone, time_zone_leap_second, time_zone_name, time_zone_transition, time_zone_transition_type, general_log, slow_log, event, proxies_priv, innodb_index_stats, innodb_table_stats, vtmd_template, table_stats, column_stats, index_stats, roles_mapping, gtid_slave_pos; -- enable_query_log diff --git a/scripts/mysql_system_tables.sql b/scripts/mysql_system_tables.sql index 7b614163f46..51e324386c3 100644 --- a/scripts/mysql_system_tables.sql +++ b/scripts/mysql_system_tables.sql @@ -129,6 +129,16 @@ SET @create_innodb_index_stats="CREATE TABLE IF NOT EXISTS innodb_index_stats ( PRIMARY KEY (database_name, table_name, index_name, stat_name) ) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_bin STATS_PERSISTENT=0"; +SET @create_vtmd_template="CREATE TABLE IF NOT EXISTS vtmd_template ( + start BIGINT UNSIGNED GENERATED ALWAYS AS ROW START COMMENT 'TRX_ID of table lifetime start', + end BIGINT UNSIGNED GENERATED ALWAYS AS ROW END COMMENT 'TRX_ID of table lifetime end', + name VARCHAR(64) NOT NULL COMMENT 'Table name during period [start, end)', + frm_image BLOB NOT NULL COMMENT 'Table structure during period [start, end)', + col_renames BLOB COMMENT 'Column name mapping from previous lifetime', + PERIOD FOR SYSTEM_TIME(start, end), + PRIMARY KEY (end) +) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_bin STATS_PERSISTENT=0 WITH SYSTEM VERSIONING"; + SET @str=IF(@have_innodb <> 0, @create_innodb_table_stats, "SET @dummy = 0"); PREPARE stmt FROM @str; EXECUTE stmt; @@ -139,6 +149,11 @@ PREPARE stmt FROM @str; EXECUTE stmt; DROP PREPARE stmt; +SET @str=IF(@have_innodb <> 0, @create_vtmd_template, "SET @dummy = 0"); +PREPARE stmt FROM @str; +EXECUTE stmt; +DROP PREPARE stmt; + SET @cmd="CREATE TABLE IF NOT EXISTS slave_relay_log_info ( Number_of_lines INTEGER UNSIGNED NOT NULL COMMENT 'Number of lines in the file or rows in the table. Used to version table definitions.', Relay_log_name TEXT CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'The name of the current relay log file.', -- cgit v1.2.1 From 84b4baef93d125d3afcf49bec96849f2eeca23ec Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Mon, 22 May 2017 23:40:48 +0300 Subject: SQL: SHOW CREATE for GENERATED ALWAYS AS ROW Test is main.mysqldump --- mysql-test/suite/versioning/r/ddl.result | 2 +- sql/sql_show.cc | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/mysql-test/suite/versioning/r/ddl.result b/mysql-test/suite/versioning/r/ddl.result index 415d6c54feb..16e830f21cc 100644 --- a/mysql-test/suite/versioning/r/ddl.result +++ b/mysql-test/suite/versioning/r/ddl.result @@ -167,7 +167,7 @@ show create table mysql.vtmd_template; Table Create Table vtmd_template CREATE TABLE `vtmd_template` ( `start` bigint(20) unsigned GENERATED ALWAYS AS ROW START COMMENT 'TRX_ID of table lifetime start', - `end` bigint(20) unsigned NOT NULL GENERATED ALWAYS AS ROW END COMMENT 'TRX_ID of table lifetime end', + `end` bigint(20) unsigned GENERATED ALWAYS AS ROW END NOT NULL COMMENT 'TRX_ID of table lifetime end', `name` varchar(64) COLLATE utf8_bin NOT NULL COMMENT 'Table name during period [start, end)', `frm_image` blob NOT NULL COMMENT 'Table structure during period [start, end)', `col_renames` blob DEFAULT NULL COMMENT 'Column name mapping from previous lifetime', diff --git a/sql/sql_show.cc b/sql/sql_show.cc index a3ce1fd19c6..f6e046a8d34 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2112,6 +2112,15 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, } else { + if (field->flags & VERS_SYS_START_FLAG) + { + packet->append(STRING_WITH_LEN(" GENERATED ALWAYS AS ROW START")); + } + else if (field->flags & VERS_SYS_END_FLAG) + { + packet->append(STRING_WITH_LEN(" GENERATED ALWAYS AS ROW END")); + } + if (flags & NOT_NULL_FLAG) packet->append(STRING_WITH_LEN(" NOT NULL")); else if (field->type() == MYSQL_TYPE_TIMESTAMP && !field->vers_sys_field()) @@ -2129,14 +2138,6 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, packet->append(STRING_WITH_LEN(" DEFAULT ")); packet->append(def_value.ptr(), def_value.length(), system_charset_info); } - else if (field->flags & VERS_SYS_START_FLAG) - { - packet->append(STRING_WITH_LEN(" GENERATED ALWAYS AS ROW START")); - } - else if (field->flags & VERS_SYS_END_FLAG) - { - packet->append(STRING_WITH_LEN(" GENERATED ALWAYS AS ROW END")); - } if (field->flags & VERS_OPTIMIZED_UPDATE_FLAG) { -- cgit v1.2.1 From 3bdf5b60ec0d2e5f33223c6fcc45e55fc489c7f0 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Mon, 22 May 2017 23:43:55 +0300 Subject: Misc: README.md Travis CI label --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a8eaa1441a1..f2b092b22f6 100644 --- a/README.md +++ b/README.md @@ -67,4 +67,4 @@ https://github.com/MariaDB/server Code status: ------------ -* [![tests status](https://travis-ci.org/tempesta-tech/mariadb_10.2.svg?branch=natsys%2Ftrunk)](https://travis-ci.org/tempesta-tech/mariadb_10.2) travis-ci.org (natsys/trunk) +* [![tests status](https://travis-ci.org/tempesta-tech/mariadb.svg?branch=natsys%2Ftrunk)](https://travis-ci.org/tempesta-tech/mariadb) travis-ci.org (natsys/trunk) -- cgit v1.2.1 From 414651c80a64d93ece5a3f03bfb186fe52cca6f0 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Tue, 23 May 2017 11:15:44 +0300 Subject: SQL: ALTER ADD COLUMN order fix --- mysql-test/suite/versioning/r/alter.result | 28 ++++++++++++---------------- mysql-test/suite/versioning/t/alter.test | 5 ----- sql/handler.cc | 22 +--------------------- 3 files changed, 13 insertions(+), 42 deletions(-) diff --git a/mysql-test/suite/versioning/r/alter.result b/mysql-test/suite/versioning/r/alter.result index 882d15f7b88..3bb6f235056 100644 --- a/mysql-test/suite/versioning/r/alter.result +++ b/mysql-test/suite/versioning/r/alter.result @@ -77,9 +77,9 @@ show create table t; Table Create Table t CREATE TABLE `t` ( `a` int(11) DEFAULT NULL, - `b` int(11) DEFAULT NULL, `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + `b` int(11) DEFAULT NULL, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING alter table t add column c int; @@ -87,10 +87,10 @@ show create table t; Table Create Table t CREATE TABLE `t` ( `a` int(11) DEFAULT NULL, - `b` int(11) DEFAULT NULL, - `c` int(11) DEFAULT NULL, `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING alter table t add column d int first; @@ -99,10 +99,10 @@ Table Create Table t CREATE TABLE `t` ( `d` int(11) DEFAULT NULL, `a` int(11) DEFAULT NULL, - `b` int(11) DEFAULT NULL, - `c` int(11) DEFAULT NULL, `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING alter table t add column e int after d; @@ -112,26 +112,22 @@ t CREATE TABLE `t` ( `d` int(11) DEFAULT NULL, `e` int(11) DEFAULT NULL, `a` int(11) DEFAULT NULL, - `b` int(11) DEFAULT NULL, - `c` int(11) DEFAULT NULL, `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING -alter table t add column f int after sys_trx_start; -ERROR HY000: Wrong parameters for `t`: Can not put new field after system versioning field -alter table t add column f int after sys_trx_end; -ERROR HY000: Wrong parameters for `t`: Can not put new field after system versioning field alter table t drop column a; show create table t; Table Create Table t CREATE TABLE `t` ( `d` int(11) DEFAULT NULL, `e` int(11) DEFAULT NULL, - `b` int(11) DEFAULT NULL, - `c` int(11) DEFAULT NULL, `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING alter table t drop column sys_trx_start; @@ -179,9 +175,9 @@ show create table t; Table Create Table t CREATE TABLE `t` ( `a` int(11) DEFAULT NULL, - `b` int(11) DEFAULT NULL, `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + `b` int(11) DEFAULT NULL, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING select * from t; @@ -339,9 +335,9 @@ show create table t; Table Create Table t CREATE TABLE `t` ( `a` int(11) DEFAULT NULL, - `b` int(11) DEFAULT NULL, `sys_trx_start` bigint(20) unsigned GENERATED ALWAYS AS ROW START, `sys_trx_end` bigint(20) unsigned GENERATED ALWAYS AS ROW END, + `b` int(11) DEFAULT NULL, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING select * from t; @@ -366,9 +362,9 @@ show create table t; Table Create Table t CREATE TABLE `t` ( `a` int(11) DEFAULT NULL, - `b` int(11) DEFAULT NULL, `sys_trx_start` bigint(20) unsigned GENERATED ALWAYS AS ROW START, `sys_trx_end` bigint(20) unsigned GENERATED ALWAYS AS ROW END, + `b` int(11) DEFAULT NULL, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING select * from t; diff --git a/mysql-test/suite/versioning/t/alter.test b/mysql-test/suite/versioning/t/alter.test index b6ffb41f33b..af297d2ba03 100644 --- a/mysql-test/suite/versioning/t/alter.test +++ b/mysql-test/suite/versioning/t/alter.test @@ -59,11 +59,6 @@ show create table t; alter table t add column e int after d; show create table t; ---error ER_VERS_WRONG_PARAMS -alter table t add column f int after sys_trx_start; ---error ER_VERS_WRONG_PARAMS -alter table t add column f int after sys_trx_end; - alter table t drop column a; show create table t; diff --git a/sql/handler.cc b/sql/handler.cc index 1d21d499dde..f2e74d936fd 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6874,31 +6874,11 @@ bool Vers_parse_info::check_and_fix_alter(THD *thd, Alter_info *alter_info, if (alter_info->create_list.elements) { - DBUG_ASSERT(share->fields > 2); - const char *after_this= share->field[share->fields - 3]->field_name; - List_iterator it(alter_info->create_list); + List_iterator_fast it(alter_info->create_list); while (Create_field *f= it++) { if (f->versioning == Column_definition::WITHOUT_VERSIONING) f->flags|= VERS_OPTIMIZED_UPDATE_FLAG; - - if (f->change) - continue; - - if (f->after) - { - if (is_trx_start(f->after) || is_trx_end(f->after)) - { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, - "Can not put new field after system versioning field"); - return true; - } - - continue; - } - - // TODO: ALTER_COLUMN_ORDER? - f->after= after_this; } } -- cgit v1.2.1 From 1c8a2de73eecef8b53165b9c8c3d001513a7a4c1 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 24 May 2017 18:52:48 +0300 Subject: Scripts: VTMD schema fix --- mysql-test/suite/versioning/r/ddl.result | 6 +++--- scripts/mysql_system_tables.sql | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mysql-test/suite/versioning/r/ddl.result b/mysql-test/suite/versioning/r/ddl.result index 16e830f21cc..f5d7b024e14 100644 --- a/mysql-test/suite/versioning/r/ddl.result +++ b/mysql-test/suite/versioning/r/ddl.result @@ -162,15 +162,15 @@ drop procedure concat_exec3; drop function get_historical_table_name; drop procedure drop_last_historical; select * from mysql.vtmd_template; -start end name frm_image col_renames +start end name archive_name col_renames show create table mysql.vtmd_template; Table Create Table vtmd_template CREATE TABLE `vtmd_template` ( `start` bigint(20) unsigned GENERATED ALWAYS AS ROW START COMMENT 'TRX_ID of table lifetime start', `end` bigint(20) unsigned GENERATED ALWAYS AS ROW END NOT NULL COMMENT 'TRX_ID of table lifetime end', `name` varchar(64) COLLATE utf8_bin NOT NULL COMMENT 'Table name during period [start, end)', - `frm_image` blob NOT NULL COMMENT 'Table structure during period [start, end)', - `col_renames` blob DEFAULT NULL COMMENT 'Column name mapping from previous lifetime', + `archive_name` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT 'Name of archive table', + `col_renames` blob DEFAULT NULL COMMENT 'Column name mappings from previous lifetime', PRIMARY KEY (`end`), PERIOD FOR SYSTEM_TIME (`start`, `end`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin STATS_PERSISTENT=0 WITH SYSTEM VERSIONING diff --git a/scripts/mysql_system_tables.sql b/scripts/mysql_system_tables.sql index 51e324386c3..ae115b37b9f 100644 --- a/scripts/mysql_system_tables.sql +++ b/scripts/mysql_system_tables.sql @@ -133,8 +133,8 @@ SET @create_vtmd_template="CREATE TABLE IF NOT EXISTS vtmd_template ( start BIGINT UNSIGNED GENERATED ALWAYS AS ROW START COMMENT 'TRX_ID of table lifetime start', end BIGINT UNSIGNED GENERATED ALWAYS AS ROW END COMMENT 'TRX_ID of table lifetime end', name VARCHAR(64) NOT NULL COMMENT 'Table name during period [start, end)', - frm_image BLOB NOT NULL COMMENT 'Table structure during period [start, end)', - col_renames BLOB COMMENT 'Column name mapping from previous lifetime', + archive_name VARCHAR(64) NULL COMMENT 'Name of archive table', + col_renames BLOB COMMENT 'Column name mappings from previous lifetime', PERIOD FOR SYSTEM_TIME(start, end), PRIMARY KEY (end) ) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_bin STATS_PERSISTENT=0 WITH SYSTEM VERSIONING"; -- cgit v1.2.1 From 397a891538eab4310b6f45319783a1c5c53977c7 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Thu, 25 May 2017 15:19:49 +0300 Subject: SQL: minor cleanup in mysql_alter_table() --- sql/sql_table.cc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index bbfe78ac4b2..a1140b1c6bc 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -9445,13 +9445,11 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, alter_info->keys_onoff, &alter_ctx)) { - if (versioned && new_versioned && thd->variables.vers_ddl_survival) + if (table->versioned_by_sql() && new_versioned && + thd->variables.vers_ddl_survival) { - if (table->versioned_by_sql()) - { - // Failure of this function may result in corruption of an original table. - vers_reset_alter_copy(thd, table); - } + // Failure of this function may result in corruption of an original table. + vers_reset_alter_copy(thd, table); } goto err_new_table_cleanup; } -- cgit v1.2.1 From f915fe8eaeed8e35ee418c6692dbe1873ffb586f Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Fri, 2 Jun 2017 16:53:24 +0300 Subject: SQL: renamed vers_thd_get_now() to THD::query_start_TIME() --- sql/sql_class.cc | 9 +++++++++ sql/sql_class.h | 1 + sql/sql_table.cc | 31 +++++++++---------------------- 3 files changed, 19 insertions(+), 22 deletions(-) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 052e5ae136d..4226da573cb 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -6859,6 +6859,15 @@ static bool protect_against_unsafe_warning_flood(int unsafe_type) DBUG_RETURN(unsafe_warning_suppression_active[unsafe_type]); } +MYSQL_TIME THD::query_start_TIME() +{ + MYSQL_TIME res; + variables.time_zone->gmt_sec_to_TIME(&res, query_start()); + res.second_part= query_start_sec_part(); + time_zone_used= 1; + return res; +} + /** Auxiliary method used by @c binlog_query() to raise warnings. diff --git a/sql/sql_class.h b/sql/sql_class.h index e9a0f192c5f..d024a27c2cd 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3244,6 +3244,7 @@ public: inline my_time_t query_start() { query_start_used=1; return start_time; } inline ulong query_start_sec_part() { query_start_sec_part_used=1; return start_time_sec_part; } + MYSQL_TIME query_start_TIME(); inline void set_current_time() { my_hrtime_t hrtime= my_hrtime(); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index a1140b1c6bc..efb2969f548 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5155,20 +5155,10 @@ static void make_unique_constraint_name(THD *thd, LEX_STRING *name, ** Alter a table definition ****************************************************************************/ -// Works as NOW(6) -static MYSQL_TIME vers_thd_get_now(THD *thd) -{ - MYSQL_TIME now; - thd->variables.time_zone->gmt_sec_to_TIME(&now, thd->query_start()); - now.second_part= thd->query_start_sec_part(); - thd->time_zone_used= 1; - return now; -} - static void vers_table_name_date(THD *thd, const char *table_name, char *new_name, size_t new_name_size) { - const MYSQL_TIME now= vers_thd_get_now(thd); + const MYSQL_TIME now= thd->query_start_TIME(); my_snprintf(new_name, new_name_size, "%s_%04d%02d%02d_%02d%02d%02d_%06d", table_name, now.year, now.month, now.day, now.hour, now.minute, now.second, now.second_part); @@ -5185,7 +5175,7 @@ bool operator!=(const MYSQL_TIME &lhs, const MYSQL_TIME &rhs) // Sets sys_trx_end=MAX for rows with sys_trx_end=now(6) static bool vers_reset_alter_copy(THD *thd, TABLE *table) { - const MYSQL_TIME now= vers_thd_get_now(thd); + const MYSQL_TIME query_start= thd->query_start_TIME(); READ_RECORD info; int error= 0; @@ -5201,7 +5191,7 @@ static bool vers_reset_alter_copy(THD *thd, TABLE *table) MYSQL_TIME current; if (table->vers_end_field()->get_date(¤t, 0)) goto err_read_record; - if (current != now) + if (current != query_start) { continue; } @@ -9793,7 +9783,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, bool make_unversioned= from->versioned() && !to->versioned(); bool keep_versioned= from->versioned() && to->versioned(); Field *to_sys_trx_start= NULL, *to_sys_trx_end= NULL, *from_sys_trx_end= NULL; - MYSQL_TIME now; + MYSQL_TIME query_start; DBUG_ENTER("copy_data_between_tables"); /* Two or 3 stages; Sorting, copying data and update indexes */ @@ -9895,7 +9885,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, if (make_versioned) { - now= vers_thd_get_now(thd); + query_start= thd->query_start_TIME(); to_sys_trx_start= to->vers_start_field(); to_sys_trx_end= to->vers_end_field(); } @@ -9908,10 +9898,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, to->file->vers_auto_decrement= 0xffffffffffffffff; if (thd->variables.vers_ddl_survival) { - thd->variables.time_zone->gmt_sec_to_TIME(&now, thd->query_start()); - now.second_part= thd->query_start_sec_part(); - thd->time_zone_used= 1; - + query_start= thd->query_start_TIME(); from_sys_trx_end= from->vers_end_field(); to_sys_trx_start= to->vers_start_field(); } @@ -9975,7 +9962,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, { to_sys_trx_start->set_notnull(to_sys_trx_start->null_offset()); // TODO: write directly to record bypassing the same checks on every call - to_sys_trx_start->store_time(&now); + to_sys_trx_start->store_time(&query_start); static const timeval max_tv= {0x7fffffff, 0}; static const uint dec= 6; @@ -9993,9 +9980,9 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, continue; // Do not copy history rows. store_record(from, record[1]); - from->vers_end_field()->store_time(&now); + from->vers_end_field()->store_time(&query_start); from->file->ha_update_row(from->record[1], from->record[0]); - to_sys_trx_start->store_time(&now); + to_sys_trx_start->store_time(&query_start); } prev_insert_id= to->file->next_insert_id; -- cgit v1.2.1 From efaa0d66dafc44d994054c7d6ff160cb295a0bf6 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Tue, 13 Jun 2017 10:07:16 +0300 Subject: Cleanup: stale sql/field.h.orig --- sql/field.h.orig | 4160 ------------------------------------------------------ 1 file changed, 4160 deletions(-) delete mode 100644 sql/field.h.orig diff --git a/sql/field.h.orig b/sql/field.h.orig deleted file mode 100644 index 03d9ba06ac4..00000000000 --- a/sql/field.h.orig +++ /dev/null @@ -1,4160 +0,0 @@ -#ifndef FIELD_INCLUDED -#define FIELD_INCLUDED -/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. - Copyright (c) 2008, 2017, MariaDB Corporation. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - -/* - Because of the function make_new_field() all field classes that have static - variables must declare the size_of() member function. -*/ - -#ifdef USE_PRAGMA_INTERFACE -#pragma interface /* gcc class implementation */ -#endif - -#include "mysqld.h" /* system_charset_info */ -#include "table.h" /* TABLE */ -#include "sql_string.h" /* String */ -#include "my_decimal.h" /* my_decimal */ -#include "sql_error.h" /* Sql_condition */ -#include "compat56.h" -#include "sql_type.h" /* Type_std_attributes */ - -class Send_field; -class Copy_field; -class Protocol; -class Create_field; -class Relay_log_info; -class Field; -class Column_statistics; -class Column_statistics_collected; -class Item_func; -class Item_bool_func; -class Item_equal; - -enum enum_check_fields -{ - CHECK_FIELD_IGNORE, - CHECK_FIELD_WARN, - CHECK_FIELD_ERROR_FOR_NULL -}; - -/* - Common declarations for Field and Item -*/ -class Value_source -{ -protected: - - // Parameters for warning and note generation - class Warn_filter - { - bool m_want_warning_edom; - bool m_want_note_truncated_spaces; - public: - Warn_filter(bool want_warning_edom, bool want_note_truncated_spaces) : - m_want_warning_edom(want_warning_edom), - m_want_note_truncated_spaces(want_note_truncated_spaces) - { } - Warn_filter(const THD *thd); - bool want_warning_edom() const - { return m_want_warning_edom; } - bool want_note_truncated_spaces() const - { return m_want_note_truncated_spaces; } - }; - class Warn_filter_all: public Warn_filter - { - public: - Warn_filter_all() :Warn_filter(true, true) { } - }; - - class Converter_double_to_longlong - { - protected: - bool m_error; - longlong m_result; - public: - Converter_double_to_longlong(double nr, bool unsigned_flag); - longlong result() const { return m_result; } - bool error() const { return m_error; } - void push_warning(THD *thd, double nr, bool unsigned_flag); - }; - class Converter_double_to_longlong_with_warn: - public Converter_double_to_longlong - { - public: - Converter_double_to_longlong_with_warn(THD *thd, double nr, - bool unsigned_flag) - :Converter_double_to_longlong(nr, unsigned_flag) - { - if (m_error) - push_warning(thd, nr, unsigned_flag); - } - Converter_double_to_longlong_with_warn(double nr, bool unsigned_flag) - :Converter_double_to_longlong(nr, unsigned_flag) - { - if (m_error) - push_warning(current_thd, nr, unsigned_flag); - } - }; - - // String-to-number converters - class Converter_string_to_number - { - protected: - char *m_end_of_num; // Where the low-level conversion routine stopped - int m_error; // The error code returned by the low-level routine - bool m_edom; // If EDOM-alike error happened during conversion - /** - Check string-to-number conversion and produce a warning if - - could not convert any digits (EDOM-alike error) - - found garbage at the end of the string - - found extra spaces at the end (a note) - See also Field_num::check_edom_and_truncation() for a similar function. - - @param thd - the thread that will be used to generate warnings. - Can be NULL (which means current_thd will be used - if a warning is really necessary). - @param type - name of the data type - (e.g. "INTEGER", "DECIMAL", "DOUBLE") - @param cs - character set of the original string - @param str - the original string - @param end - the end of the string - @param allow_notes - tells if trailing space notes should be displayed - or suppressed. - - Unlike Field_num::check_edom_and_truncation(), this function does not - distinguish between EDOM and truncation and reports the same warning for - both cases. Perhaps we should eventually print different warnings, - to make the explicit CAST work closer to the implicit cast in - Field_xxx::store(). - */ - void check_edom_and_truncation(THD *thd, Warn_filter filter, - const char *type, - CHARSET_INFO *cs, - const char *str, - size_t length) const; - public: - int error() const { return m_error; } - }; - - class Converter_strntod: public Converter_string_to_number - { - double m_result; - public: - Converter_strntod(CHARSET_INFO *cs, const char *str, size_t length) - { - m_result= my_strntod(cs, (char *) str, length, &m_end_of_num, &m_error); - // strntod() does not set an error if the input string was empty - m_edom= m_error !=0 || str == m_end_of_num; - } - double result() const { return m_result; } - }; - - class Converter_string_to_longlong: public Converter_string_to_number - { - protected: - longlong m_result; - public: - longlong result() const { return m_result; } - }; - - class Converter_strntoll: public Converter_string_to_longlong - { - public: - Converter_strntoll(CHARSET_INFO *cs, const char *str, size_t length) - { - m_result= my_strntoll(cs, str, length, 10, &m_end_of_num, &m_error); - /* - All non-zero errors means EDOM error. - strntoll() does not set an error if the input string was empty. - Check it here. - Notice the different with the same condition in Converter_strntoll10. - */ - m_edom= m_error != 0 || str == m_end_of_num; - } - }; - - class Converter_strtoll10: public Converter_string_to_longlong - { - public: - Converter_strtoll10(CHARSET_INFO *cs, const char *str, size_t length) - { - m_end_of_num= (char *) str + length; - m_result= (*(cs->cset->strtoll10))(cs, str, &m_end_of_num, &m_error); - /* - Negative error means "good negative number". - Only a positive m_error value means a real error. - strtoll10() sets error to MY_ERRNO_EDOM in case of an empty string, - so we don't have to additionally catch empty strings here. - */ - m_edom= m_error > 0; - } - }; - - class Converter_str2my_decimal: public Converter_string_to_number - { - public: - Converter_str2my_decimal(uint mask, - CHARSET_INFO *cs, const char *str, size_t length, - my_decimal *buf) - { - m_error= str2my_decimal(mask, str, length, cs, - buf, (const char **) &m_end_of_num); - // E_DEC_TRUNCATED means a very minor truncation: '1e-100' -> 0 - m_edom= m_error && m_error != E_DEC_TRUNCATED; - } - }; - - - // String-to-number converters with automatic warning generation - class Converter_strntod_with_warn: public Converter_strntod - { - public: - Converter_strntod_with_warn(THD *thd, Warn_filter filter, - CHARSET_INFO *cs, - const char *str, size_t length) - :Converter_strntod(cs, str, length) - { - check_edom_and_truncation(thd, filter, "DOUBLE", cs, str, length); - } - }; - - class Converter_strntoll_with_warn: public Converter_strntoll - { - public: - Converter_strntoll_with_warn(THD *thd, Warn_filter filter, - CHARSET_INFO *cs, - const char *str, size_t length) - :Converter_strntoll(cs, str, length) - { - check_edom_and_truncation(thd, filter, "INTEGER", cs, str, length); - } - }; - - class Converter_strtoll10_with_warn: public Converter_strtoll10 - { - public: - Converter_strtoll10_with_warn(THD *thd, Warn_filter filter, - CHARSET_INFO *cs, - const char *str, size_t length) - :Converter_strtoll10(cs, str, length) - { - check_edom_and_truncation(thd, filter, "INTEGER", cs, str, length); - } - }; - - class Converter_str2my_decimal_with_warn: public Converter_str2my_decimal - { - public: - Converter_str2my_decimal_with_warn(THD *thd, Warn_filter filter, - uint mask, CHARSET_INFO *cs, - const char *str, size_t length, - my_decimal *buf) - :Converter_str2my_decimal(mask, cs, str, length, buf) - { - check_edom_and_truncation(thd, filter, "DECIMAL", cs, str, length); - } - }; - - - // String-to-number convertion methods for the old code compatibility - longlong longlong_from_string_with_check(CHARSET_INFO *cs, const char *cptr, - const char *end) const - { - /* - TODO: Give error if we wanted a signed integer and we got an unsigned - one - - Notice, longlong_from_string_with_check() honors thd->no_error, because - it's used to handle queries like this: - SELECT COUNT(@@basedir); - and is called when Item_func_get_system_var::update_null_value() - suppresses warnings and then calls val_int(). - The other methods {double|decimal}_from_string_with_check() ignore - thd->no_errors, because they are not used for update_null_value() - and they always allow all kind of warnings. - */ - THD *thd= current_thd; - return Converter_strtoll10_with_warn(thd, Warn_filter(thd), - cs, cptr, end - cptr).result(); - } - - double double_from_string_with_check(CHARSET_INFO *cs, const char *cptr, - const char *end) const - { - return Converter_strntod_with_warn(NULL, Warn_filter_all(), - cs, cptr, end - cptr).result(); - } - my_decimal *decimal_from_string_with_check(my_decimal *decimal_value, - CHARSET_INFO *cs, - const char *cptr, - const char *end) - { - Converter_str2my_decimal_with_warn(NULL, Warn_filter_all(), - E_DEC_FATAL_ERROR & ~E_DEC_BAD_NUM, - cs, cptr, end - cptr, decimal_value); - return decimal_value; - } - - longlong longlong_from_hex_hybrid(const char *str, uint32 length) - { - const char *end= str + length; - const char *ptr= end - MY_MIN(length, sizeof(longlong)); - ulonglong value= 0; - for ( ; ptr != end ; ptr++) - value= (value << 8) + (ulonglong) (uchar) *ptr; - return (longlong) value; - } - - longlong longlong_from_string_with_check(const String *str) const - { - return longlong_from_string_with_check(str->charset(), - str->ptr(), str->end()); - } - double double_from_string_with_check(const String *str) const - { - return double_from_string_with_check(str->charset(), - str->ptr(), str->end()); - } - my_decimal *decimal_from_string_with_check(my_decimal *decimal_value, - const String *str) - { - return decimal_from_string_with_check(decimal_value, str->charset(), - str->ptr(), str->end()); - } - // End of String-to-number conversion methods - -public: - /* - The enumeration Subst_constraint is currently used only in implementations - of the virtual function subst_argument_checker. - */ - enum Subst_constraint - { - ANY_SUBST, /* Any substitution for a field is allowed */ - IDENTITY_SUBST /* Substitution for a field is allowed if any two - different values of the field type are not equal */ - }; - /* - Item context attributes. - Comparison functions pass their attributes to propagate_equal_fields(). - For exmple, for string comparison, the collation of the comparison - operation is important inside propagate_equal_fields(). - */ - class Context - { - /* - Which type of propagation is allowed: - - ANY_SUBST (loose equality, according to the collation), or - - IDENTITY_SUBST (strict binary equality). - */ - Subst_constraint m_subst_constraint; - /* - Comparison type. - Impostant only when ANY_SUBSTS. - */ - Item_result m_compare_type; - /* - Collation of the comparison operation. - Important only when ANY_SUBST. - */ - CHARSET_INFO *m_compare_collation; - public: - Context(Subst_constraint subst, Item_result type, CHARSET_INFO *cs) - :m_subst_constraint(subst), - m_compare_type(type), - m_compare_collation(cs) { } - Subst_constraint subst_constraint() const { return m_subst_constraint; } - Item_result compare_type() const - { - DBUG_ASSERT(m_subst_constraint == ANY_SUBST); - return m_compare_type; - } - CHARSET_INFO *compare_collation() const - { - DBUG_ASSERT(m_subst_constraint == ANY_SUBST); - return m_compare_collation; - } - }; - class Context_identity: public Context - { // Use this to request only exact value, no invariants. - public: - Context_identity() - :Context(IDENTITY_SUBST, STRING_RESULT, &my_charset_bin) { } - }; - class Context_boolean: public Context - { // Use this when an item is [a part of] a boolean expression - public: - Context_boolean() :Context(ANY_SUBST, INT_RESULT, &my_charset_bin) { } - }; -}; - - -#define STORAGE_TYPE_MASK 7 -#define COLUMN_FORMAT_MASK 7 -#define COLUMN_FORMAT_SHIFT 3 - -/* The length of the header part for each virtual column in the .frm file */ -#define FRM_VCOL_OLD_HEADER_SIZE(b) (3 + MY_TEST(b)) -#define FRM_VCOL_NEW_BASE_SIZE 16 -#define FRM_VCOL_NEW_HEADER_SIZE 6 - -class Count_distinct_field; - -struct ha_field_option_struct; - -struct st_cache_field; -int field_conv(Field *to,Field *from); -int truncate_double(double *nr, uint field_length, uint dec, - bool unsigned_flag, double max_value); - -inline uint get_enum_pack_length(int elements) -{ - return elements < 256 ? 1 : 2; -} - -inline uint get_set_pack_length(int elements) -{ - uint len= (elements + 7) / 8; - return len > 4 ? 8 : len; -} - - -/** - Tests if field type is temporal and has date part, - i.e. represents DATE, DATETIME or TIMESTAMP types in SQL. - - @param type Field type, as returned by field->type(). - @retval true If field type is temporal type with date part. - @retval false If field type is not temporal type with date part. -*/ -inline bool is_temporal_type_with_date(enum_field_types type) -{ - switch (type) - { - case MYSQL_TYPE_DATE: - case MYSQL_TYPE_DATETIME: - case MYSQL_TYPE_TIMESTAMP: - return true; - case MYSQL_TYPE_DATETIME2: - case MYSQL_TYPE_TIMESTAMP2: - DBUG_ASSERT(0); // field->real_type() should not get to here. - default: - return false; - } -} - - -/** - Recognizer for concrete data type (called real_type for some reason), - returning true if it is one of the TIMESTAMP types. -*/ -inline bool is_timestamp_type(enum_field_types type) -{ - return type == MYSQL_TYPE_TIMESTAMP || type == MYSQL_TYPE_TIMESTAMP2; -} - - -/** - Convert temporal real types as retuned by field->real_type() - to field type as returned by field->type(). - - @param real_type Real type. - @retval Field type. -*/ -inline enum_field_types real_type_to_type(enum_field_types real_type) -{ - switch (real_type) - { - case MYSQL_TYPE_TIME2: - return MYSQL_TYPE_TIME; - case MYSQL_TYPE_DATETIME2: - return MYSQL_TYPE_DATETIME; - case MYSQL_TYPE_TIMESTAMP2: - return MYSQL_TYPE_TIMESTAMP; - case MYSQL_TYPE_NEWDATE: - return MYSQL_TYPE_DATE; - /* Note: NEWDECIMAL is a type, not only a real_type */ - default: return real_type; - } -} - - -static inline enum enum_mysql_timestamp_type -mysql_type_to_time_type(enum enum_field_types mysql_type) -{ - switch(mysql_type) { - case MYSQL_TYPE_TIME2: - case MYSQL_TYPE_TIME: return MYSQL_TIMESTAMP_TIME; - case MYSQL_TYPE_TIMESTAMP2: - case MYSQL_TYPE_TIMESTAMP: - case MYSQL_TYPE_DATETIME2: - case MYSQL_TYPE_DATETIME: return MYSQL_TIMESTAMP_DATETIME; - case MYSQL_TYPE_NEWDATE: - case MYSQL_TYPE_DATE: return MYSQL_TIMESTAMP_DATE; - default: return MYSQL_TIMESTAMP_ERROR; - } -} - - -/** - Tests if field type is temporal, i.e. represents - DATE, TIME, DATETIME or TIMESTAMP types in SQL. - - @param type Field type, as returned by field->type(). - @retval true If field type is temporal - @retval false If field type is not temporal -*/ -inline bool is_temporal_type(enum_field_types type) -{ - return mysql_type_to_time_type(type) != MYSQL_TIMESTAMP_ERROR; -} - - -/** - Tests if field type is temporal and has time part, - i.e. represents TIME, DATETIME or TIMESTAMP types in SQL. - - @param type Field type, as returned by field->type(). - @retval true If field type is temporal type with time part. - @retval false If field type is not temporal type with time part. -*/ -inline bool is_temporal_type_with_time(enum_field_types type) -{ - switch (type) - { - case MYSQL_TYPE_TIME: - case MYSQL_TYPE_DATETIME: - case MYSQL_TYPE_TIMESTAMP: - return true; - default: - return false; - } -} - -enum enum_vcol_info_type -{ - VCOL_GENERATED_VIRTUAL, VCOL_GENERATED_STORED, - VCOL_DEFAULT, VCOL_CHECK_FIELD, VCOL_CHECK_TABLE -}; - -static inline const char *vcol_type_name(enum_vcol_info_type type) -{ - switch (type) - { - case VCOL_GENERATED_VIRTUAL: - case VCOL_GENERATED_STORED: - return "GENERATED ALWAYS AS"; - case VCOL_DEFAULT: - return "DEFAULT"; - case VCOL_CHECK_FIELD: - case VCOL_CHECK_TABLE: - return "CHECK"; - } - return 0; -} - -/* - Flags for Virtual_column_info. If none is set, the expression must be - a constant with no side-effects, so it's calculated at CREATE TABLE time, - stored in table->record[2], and not recalculated for every statement. -*/ -#define VCOL_FIELD_REF 1 -#define VCOL_NON_DETERMINISTIC 2 -#define VCOL_SESSION_FUNC 4 /* uses session data, e.g. USER or DAYNAME */ -#define VCOL_TIME_FUNC 8 -#define VCOL_IMPOSSIBLE 16 - -#define VCOL_NOT_STRICTLY_DETERMINISTIC \ - (VCOL_NON_DETERMINISTIC | VCOL_TIME_FUNC | VCOL_SESSION_FUNC) - -/* - Virtual_column_info is the class to contain additional - characteristics that is specific for a virtual/computed - field such as: - - the defining expression that is evaluated to compute the value - of the field - - whether the field is to be stored in the database - - whether the field is used in a partitioning expression -*/ - -class Virtual_column_info: public Sql_alloc -{ -private: - /* - The following data is only updated by the parser and read - when a Create_field object is created/initialized. - */ - enum_field_types field_type; /* Real field type*/ - /* Flag indicating that the field used in a partitioning expression */ - bool in_partitioning_expr; - -public: - /* Flag indicating that the field is physically stored in the database */ - bool stored_in_db; - bool utf8; /* Already in utf8 */ - Item *expr; - LEX_STRING name; /* Name of constraint */ - uint flags; - - Virtual_column_info() - : field_type((enum enum_field_types)MYSQL_TYPE_VIRTUAL), - in_partitioning_expr(FALSE), stored_in_db(FALSE), - utf8(TRUE), expr(NULL), flags(0) - { - name.str= NULL; - name.length= 0; - }; - ~Virtual_column_info() {} - enum_field_types get_real_type() const - { - return field_type; - } - void set_field_type(enum_field_types fld_type) - { - /* Calling this function can only be done once. */ - field_type= fld_type; - } - bool is_stored() const - { - return stored_in_db; - } - void set_stored_in_db_flag(bool stored) - { - stored_in_db= stored; - } - bool is_in_partitioning_expr() const - { - return in_partitioning_expr; - } - void mark_as_in_partitioning_expr() - { - in_partitioning_expr= TRUE; - } - inline bool is_equal(const Virtual_column_info* vcol) const; - void print(String*); -}; - -class Field: public Value_source -{ - Field(const Item &); /* Prevent use of these */ - void operator=(Field &); -protected: - int save_in_field_str(Field *to) - { - StringBuffer result(charset()); - val_str(&result); - return to->store(result.ptr(), result.length(), charset()); - } - static void do_field_int(Copy_field *copy); - static void do_field_real(Copy_field *copy); - static void do_field_string(Copy_field *copy); - static void do_field_temporal(Copy_field *copy); - static void do_field_decimal(Copy_field *copy); -public: - static void *operator new(size_t size, MEM_ROOT *mem_root) throw () - { return alloc_root(mem_root, size); } - static void *operator new(size_t size) throw () - { return thd_alloc(current_thd, size); } - static void operator delete(void *ptr_arg, size_t size) { TRASH(ptr_arg, size); } - static void operator delete(void *ptr, MEM_ROOT *mem_root) - { DBUG_ASSERT(0); } - - /** - Used by System Versioning. - */ - virtual bool set_max() - { DBUG_ASSERT(0); return false; } - - /** - Used by System Versioning. - */ - virtual bool is_max() - { DBUG_ASSERT(0); return false; } - - uchar *ptr; // Position to field in record - /** - Byte where the @c NULL bit is stored inside a record. If this Field is a - @c NOT @c NULL field, this member is @c NULL. - */ - uchar *null_ptr; - /* - Note that you can use table->in_use as replacement for current_thd member - only inside of val_*() and store() members (e.g. you can't use it in cons) - */ - TABLE *table; // Pointer for table - TABLE *orig_table; // Pointer to original table - const char * const *table_name; - const char *field_name; - /** reference to the list of options or NULL */ - engine_option_value *option_list; - ha_field_option_struct *option_struct; /* structure with parsed options */ - LEX_STRING comment; - /* Field is part of the following keys */ - key_map key_start, part_of_key, part_of_key_not_clustered; - - /* - Bitmap of indexes that have records ordered by col1, ... this_field, ... - - For example, INDEX (col(prefix_n)) is not present in col.part_of_sortkey. - */ - key_map part_of_sortkey; - /* - We use three additional unireg types for TIMESTAMP to overcome limitation - of current binary format of .frm file. We'd like to be able to support - NOW() as default and on update value for such fields but unable to hold - this info anywhere except unireg_check field. This issue will be resolved - in more clean way with transition to new text based .frm format. - See also comment for Field_timestamp::Field_timestamp(). - */ - enum utype { - NONE=0, - NEXT_NUMBER=15, // AUTO_INCREMENT - TIMESTAMP_OLD_FIELD=18, // TIMESTAMP created before 4.1.3 - TIMESTAMP_DN_FIELD=21, // TIMESTAMP DEFAULT NOW() - TIMESTAMP_UN_FIELD=22, // TIMESTAMP ON UPDATE NOW() - TIMESTAMP_DNUN_FIELD=23 // TIMESTAMP DEFAULT NOW() ON UPDATE NOW() - }; - enum geometry_type - { - GEOM_GEOMETRY = 0, GEOM_POINT = 1, GEOM_LINESTRING = 2, GEOM_POLYGON = 3, - GEOM_MULTIPOINT = 4, GEOM_MULTILINESTRING = 5, GEOM_MULTIPOLYGON = 6, - GEOM_GEOMETRYCOLLECTION = 7 - }; - enum imagetype { itRAW, itMBR}; - - utype unireg_check; - uint32 field_length; // Length of field - uint32 flags; - uint16 field_index; // field number in fields array - uchar null_bit; // Bit used to test null bit - /** - If true, this field was created in create_tmp_field_from_item from a NULL - value. This means that the type of the field is just a guess, and the type - may be freely coerced to another type. - - @see create_tmp_field_from_item - @see Item_type_holder::get_real_type - - */ - bool is_created_from_null_item; - - /* TRUE in Field objects created for column min/max values */ - bool is_stat_field; - - /* - Selectivity of the range condition over this field. - When calculating this selectivity a range predicate - is taken into account only if: - - it is extracted from the WHERE clause - - it depends only on the table the field belongs to - */ - double cond_selectivity; - - /* - The next field in the class of equal fields at the top AND level - of the WHERE clause - */ - Field *next_equal_field; - - /* - This structure is used for statistical data on the column - that has been read from the statistical table column_stat - */ - Column_statistics *read_stats; - /* - This structure is used for statistical data on the column that - is collected by the function collect_statistics_for_table - */ - Column_statistics_collected *collected_stats; - - /* - This is additional data provided for any computed(virtual) field, - default function or check constraint. - In particular it includes a pointer to the item by which this field - can be computed from other fields. - */ - Virtual_column_info *vcol_info, *check_constraint, *default_value; - - Field(uchar *ptr_arg,uint32 length_arg,uchar *null_ptr_arg, - uchar null_bit_arg, utype unireg_check_arg, - const char *field_name_arg); - virtual ~Field() {} - - DTCollation dtcollation() const - { - return DTCollation(charset(), derivation(), repertoire()); - } - Type_std_attributes type_std_attributes() const - { - return Type_std_attributes(field_length, decimals(), - MY_TEST(flags & UNSIGNED_FLAG), - dtcollation()); - } - - /** - Convenience definition of a copy function returned by - Field::get_copy_func() - */ - typedef void Copy_func(Copy_field*); - virtual Copy_func *get_copy_func(const Field *from) const= 0; - /* Store functions returns 1 on overflow and -1 on fatal error */ - virtual int store_field(Field *from) { return from->save_in_field(this); } - virtual int save_in_field(Field *to)= 0; - /** - Check if it is possible just copy the value - of the field 'from' to the field 'this', e.g. for - INSERT INTO t1 (field1) SELECT field2 FROM t2; - @param from - The field to copy from - @retval true - it is possible to just copy value of 'from' to 'this' - @retval false - conversion is needed - */ - virtual bool memcpy_field_possible(const Field *from) const= 0; - virtual int store(const char *to, uint length,CHARSET_INFO *cs)=0; - virtual int store_hex_hybrid(const char *str, uint length); - virtual int store(double nr)=0; - virtual int store(longlong nr, bool unsigned_val)=0; - virtual int store_decimal(const my_decimal *d)=0; - virtual int store_time_dec(MYSQL_TIME *ltime, uint dec); - int store_time(MYSQL_TIME *ltime) - { return store_time_dec(ltime, TIME_SECOND_PART_DIGITS); } - int store(const char *to, uint length, CHARSET_INFO *cs, - enum_check_fields check_level); - int store(const LEX_STRING *ls, CHARSET_INFO *cs) - { return store(ls->str, ls->length, cs); } - virtual double val_real(void)=0; - virtual longlong val_int(void)=0; - virtual bool val_bool(void)= 0; - virtual my_decimal *val_decimal(my_decimal *); - inline String *val_str(String *str) { return val_str(str, str); } - /* - val_str(buf1, buf2) gets two buffers and should use them as follows: - if it needs a temp buffer to convert result to string - use buf1 - example Field_tiny::val_str() - if the value exists as a string already - use buf2 - example Field_string::val_str() - consequently, buf2 may be created as 'String buf;' - no memory - will be allocated for it. buf1 will be allocated to hold a - value if it's too small. Using allocated buffer for buf2 may result in - an unnecessary free (and later, may be an alloc). - This trickery is used to decrease a number of malloc calls. - */ - virtual String *val_str(String*,String *)=0; - String *val_int_as_str(String *val_buffer, bool unsigned_flag); - fast_field_copier get_fast_field_copier(const Field *from); - /* - str_needs_quotes() returns TRUE if the value returned by val_str() needs - to be quoted when used in constructing an SQL query. - */ - virtual bool str_needs_quotes() { return FALSE; } - virtual Item_result result_type () const=0; - virtual Item_result cmp_type () const { return result_type(); } - virtual const Type_handler *cast_to_int_type_handler() const - { - return Type_handler::get_handler_by_field_type(type()); - } - static bool type_can_have_key_part(enum_field_types); - static enum_field_types field_type_merge(enum_field_types, enum_field_types); - virtual bool eq(Field *field) - { - return (ptr == field->ptr && null_ptr == field->null_ptr && - null_bit == field->null_bit && field->type() == type()); - } - virtual bool eq_def(const Field *field) const; - - /* - pack_length() returns size (in bytes) used to store field data in memory - (i.e. it returns the maximum size of the field in a row of the table, - which is located in RAM). - */ - virtual uint32 pack_length() const { return (uint32) field_length; } - - /* - pack_length_in_rec() returns size (in bytes) used to store field data on - storage (i.e. it returns the maximal size of the field in a row of the - table, which is located on disk). - */ - virtual uint32 pack_length_in_rec() const { return pack_length(); } - virtual bool compatible_field_size(uint metadata, Relay_log_info *rli, - uint16 mflags, int *order); - virtual uint pack_length_from_metadata(uint field_metadata) - { - DBUG_ENTER("Field::pack_length_from_metadata"); - DBUG_RETURN(field_metadata); - } - virtual uint row_pack_length() const { return 0; } - virtual int save_field_metadata(uchar *first_byte) - { return do_save_field_metadata(first_byte); } - - /* - data_length() return the "real size" of the data in memory. - */ - virtual uint32 data_length() { return pack_length(); } - virtual uint32 sort_length() const { return pack_length(); } - - /* - Get the number bytes occupied by the value in the field. - CHAR values are stripped of trailing spaces. - Flexible values are stripped of their length. - */ - virtual uint32 value_length() - { - uint len; - if (!zero_pack() && - (type() == MYSQL_TYPE_STRING && - (len= pack_length()) >= 4 && len < 256)) - { - uchar *str, *end; - for (str= ptr, end= str+len; end > str && end[-1] == ' '; end--) {} - len=(uint) (end-str); - return len; - } - return data_length(); - } - - /** - Get the maximum size of the data in packed format. - - @return Maximum data length of the field when packed using the - Field::pack() function. - */ - virtual uint32 max_data_length() const { - return pack_length(); - }; - - virtual int reset(void) { bzero(ptr,pack_length()); return 0; } - virtual void reset_fields() {} - const uchar *ptr_in_record(const uchar *record) const - { - my_ptrdiff_t l_offset= (my_ptrdiff_t) (record - table->record[0]); - return ptr + l_offset; - } - virtual void set_default(); - - bool has_update_default_function() const - { - return flags & ON_UPDATE_NOW_FLAG; - } - bool has_default_now_unireg_check() const - { - return unireg_check == TIMESTAMP_DN_FIELD - || unireg_check == TIMESTAMP_DNUN_FIELD; - } - - /* - Mark the field as having a value supplied by the client, thus it should - not be auto-updated. - */ - void set_has_explicit_value() - { - bitmap_set_bit(&table->has_value_set, field_index); - } - bool has_explicit_value() - { - return bitmap_is_set(&table->has_value_set, field_index); - } - virtual bool set_explicit_default(Item *value); - - /** - Evaluates the @c UPDATE default function, if one exists, and stores the - result in the record buffer. If no such function exists for the column, - or the function is not valid for the column's data type, invoking this - function has no effect. - */ - virtual int evaluate_update_default_function() { return 0; } - - virtual bool binary() const { return 1; } - virtual bool zero_pack() const { return 1; } - virtual enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } - virtual uint32 key_length() const { return pack_length(); } - virtual enum_field_types type() const =0; - virtual enum_field_types real_type() const { return type(); } - virtual enum_field_types binlog_type() const - { - /* - Binlog stores field->type() as type code by default. For example, - it puts MYSQL_TYPE_STRING in case of CHAR, VARCHAR, SET and ENUM, - with extra data type details put into metadata. - - Binlog behaviour slightly differs between various MySQL and MariaDB - versions for the temporal data types TIME, DATETIME and TIMESTAMP. - - MySQL prior to 5.6 uses MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME - and MYSQL_TYPE_TIMESTAMP type codes in binlog and stores no - additional metadata. - - MariaDB-5.3 implements new versions for TIME, DATATIME, TIMESTAMP - with fractional second precision, but uses the old format for the - types TIME(0), DATETIME(0), TIMESTAMP(0), and it still stores - MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME and MYSQL_TYPE_TIMESTAMP in binlog, - with no additional metadata. - So row-based replication between temporal data types of - different precision is not possible in MariaDB. - - MySQL-5.6 also implements a new version of TIME, DATETIME, TIMESTAMP - which support fractional second precision 0..6, and use the new - format even for the types TIME(0), DATETIME(0), TIMESTAMP(0). - For these new data types, MySQL-5.6 stores new type codes - MYSQL_TYPE_TIME2, MYSQL_TYPE_DATETIME2, MYSQL_TYPE_TIMESTAMP2 in binlog, - with fractional precision 0..6 put into metadata. - This makes it in theory possible to do row-based replication between - columns of different fractional precision (e.g. from TIME(1) on master - to TIME(6) on slave). However, it's not currently fully implemented yet. - MySQL-5.6 can only do row-based replication from the old types - TIME, DATETIME, TIMESTAMP (represented by MYSQL_TYPE_TIME, - MYSQL_TYPE_DATETIME and MYSQL_TYPE_TIMESTAMP type codes in binlog) - to the new corresponding types TIME(0), DATETIME(0), TIMESTAMP(0). - - Note: MariaDB starting from the version 10.0 understands the new - MySQL-5.6 type codes MYSQL_TYPE_TIME2, MYSQL_TYPE_DATETIME2, - MYSQL_TYPE_TIMESTAMP2. When started over MySQL-5.6 tables both on - master and on slave, MariaDB-10.0 can also do row-based replication - from the old types TIME, DATETIME, TIMESTAMP to the new MySQL-5.6 - types TIME(0), DATETIME(0), TIMESTAMP(0). - - Note: perhaps binlog should eventually be modified to store - real_type() instead of type() for all column types. - */ - return type(); - } - inline int cmp(const uchar *str) { return cmp(ptr,str); } - virtual int cmp_max(const uchar *a, const uchar *b, uint max_len) - { return cmp(a, b); } - virtual int cmp(const uchar *,const uchar *)=0; - virtual int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0U) - { return memcmp(a,b,pack_length()); } - virtual int cmp_offset(uint row_offset) - { return cmp(ptr,ptr+row_offset); } - virtual int cmp_binary_offset(uint row_offset) - { return cmp_binary(ptr, ptr+row_offset); }; - virtual int key_cmp(const uchar *a,const uchar *b) - { return cmp(a, b); } - virtual int key_cmp(const uchar *str, uint length) - { return cmp(ptr,str); } - /* - Update the value m of the 'min_val' field with the current value v - of this field if force_update is set to TRUE or if v < m. - Return TRUE if the value has been updated. - */ - virtual bool update_min(Field *min_val, bool force_update) - { - bool update_fl= force_update || cmp(ptr, min_val->ptr) < 0; - if (update_fl) - { - min_val->set_notnull(); - memcpy(min_val->ptr, ptr, pack_length()); - } - return update_fl; - } - /* - Update the value m of the 'max_val' field with the current value v - of this field if force_update is set to TRUE or if v > m. - Return TRUE if the value has been updated. - */ - virtual bool update_max(Field *max_val, bool force_update) - { - bool update_fl= force_update || cmp(ptr, max_val->ptr) > 0; - if (update_fl) - { - max_val->set_notnull(); - memcpy(max_val->ptr, ptr, pack_length()); - } - return update_fl; - } - virtual void store_field_value(uchar *val, uint len) - { - memcpy(ptr, val, len); - } - virtual uint decimals() const { return 0; } - /* - Caller beware: sql_type can change str.Ptr, so check - ptr() to see if it changed if you are using your own buffer - in str and restore it with set() if needed - */ - virtual void sql_type(String &str) const =0; - virtual uint size_of() const =0; // For new field - inline bool is_null(my_ptrdiff_t row_offset= 0) const - { - /* - The table may have been marked as containing only NULL values - for all fields if it is a NULL-complemented row of an OUTER JOIN - or if the query is an implicitly grouped query (has aggregate - functions but no GROUP BY clause) with no qualifying rows. If - this is the case (in which TABLE::null_row is true), the field - is considered to be NULL. - - Note that if a table->null_row is set then also all null_bits are - set for the row. - - In the case of the 'result_field' for GROUP BY, table->null_row might - refer to the *next* row in the table (when the algorithm is: read the - next row, see if any of group column values have changed, send the - result - grouped - row to the client if yes). So, table->null_row might - be wrong, but such a result_field is always nullable (that's defined by - original_field->maybe_null()) and we trust its null bit. - */ - return null_ptr ? null_ptr[row_offset] & null_bit : table->null_row; - } - inline bool is_real_null(my_ptrdiff_t row_offset= 0) const - { return null_ptr && (null_ptr[row_offset] & null_bit); } - inline bool is_null_in_record(const uchar *record) const - { - if (maybe_null_in_table()) - return record[(uint) (null_ptr - table->record[0])] & null_bit; - return 0; - } - inline void set_null(my_ptrdiff_t row_offset= 0) - { if (null_ptr) null_ptr[row_offset]|= null_bit; } - inline void set_notnull(my_ptrdiff_t row_offset= 0) - { if (null_ptr) null_ptr[row_offset]&= (uchar) ~null_bit; } - inline bool maybe_null(void) const - { return null_ptr != 0 || table->maybe_null; } - - /* @return true if this field is NULL-able (even if temporarily) */ - inline bool real_maybe_null(void) const { return null_ptr != 0; } - uint null_offset(const uchar *record) const - { return (uint) (null_ptr - record); } - /* - For a NULL-able field (that can actually store a NULL value in a table) - null_ptr points to the "null bitmap" in the table->record[0] header. For - NOT NULL fields it is either 0 or points outside table->record[0] into the - table->triggers->extra_null_bitmap (so that the field can store a NULL - value temporarily, only in memory) - */ - bool maybe_null_in_table() const - { return null_ptr >= table->record[0] && null_ptr <= ptr; } - - uint null_offset() const - { return null_offset(table->record[0]); } - void set_null_ptr(uchar *p_null_ptr, uint p_null_bit) - { - null_ptr= p_null_ptr; - null_bit= p_null_bit; - } - - bool stored_in_db() const { return !vcol_info || vcol_info->stored_in_db; } - - inline THD *get_thd() const - { return likely(table) ? table->in_use : current_thd; } - - enum { - LAST_NULL_BYTE_UNDEF= 0 - }; - - /* - Find the position of the last null byte for the field. - - SYNOPSIS - last_null_byte() - - DESCRIPTION - Return a pointer to the last byte of the null bytes where the - field conceptually is placed. - - RETURN VALUE - The position of the last null byte relative to the beginning of - the record. If the field does not use any bits of the null - bytes, the value 0 (LAST_NULL_BYTE_UNDEF) is returned. - */ - size_t last_null_byte() const { - size_t bytes= do_last_null_byte(); - DBUG_PRINT("debug", ("last_null_byte() ==> %ld", (long) bytes)); - DBUG_ASSERT(bytes <= table->s->null_bytes); - return bytes; - } - - void make_sort_key(uchar *buff, uint length); - virtual void make_field(Send_field *); - virtual void sort_string(uchar *buff,uint length)=0; - virtual bool optimize_range(uint idx, uint part); - virtual void free() {} - virtual Field *make_new_field(MEM_ROOT *root, TABLE *new_table, - bool keep_type); - virtual Field *new_key_field(MEM_ROOT *root, TABLE *new_table, - uchar *new_ptr, uint32 length, - uchar *new_null_ptr, uint new_null_bit); - Field *clone(MEM_ROOT *mem_root, TABLE *new_table); - Field *clone(MEM_ROOT *mem_root, TABLE *new_table, my_ptrdiff_t diff, - bool stat_flag= FALSE); - Field *clone(MEM_ROOT *mem_root, my_ptrdiff_t diff); - inline void move_field(uchar *ptr_arg,uchar *null_ptr_arg,uchar null_bit_arg) - { - ptr=ptr_arg; null_ptr=null_ptr_arg; null_bit=null_bit_arg; - } - inline void move_field(uchar *ptr_arg) { ptr=ptr_arg; } - inline uchar *record_ptr() // record[0] or wherever the field was moved to - { - my_ptrdiff_t offset= table->s->field[field_index]->ptr - table->s->default_values; - return ptr - offset; - } - virtual void move_field_offset(my_ptrdiff_t ptr_diff) - { - ptr=ADD_TO_PTR(ptr,ptr_diff, uchar*); - if (null_ptr) - null_ptr=ADD_TO_PTR(null_ptr,ptr_diff,uchar*); - } - virtual void get_image(uchar *buff, uint length, CHARSET_INFO *cs) - { memcpy(buff,ptr,length); } - virtual void set_image(const uchar *buff,uint length, CHARSET_INFO *cs) - { memcpy(ptr,buff,length); } - - - /* - Copy a field part into an output buffer. - - SYNOPSIS - Field::get_key_image() - buff [out] output buffer - length output buffer size - type itMBR for geometry blobs, otherwise itRAW - - DESCRIPTION - This function makes a copy of field part of size equal to or - less than "length" parameter value. - For fields of string types (CHAR, VARCHAR, TEXT) the rest of buffer - is padded by zero byte. - - NOTES - For variable length character fields (i.e. UTF-8) the "length" - parameter means a number of output buffer bytes as if all field - characters have maximal possible size (mbmaxlen). In the other words, - "length" parameter is a number of characters multiplied by - field_charset->mbmaxlen. - - RETURN - Number of copied bytes (excluding padded zero bytes -- see above). - */ - - virtual uint get_key_image(uchar *buff, uint length, imagetype type_arg) - { - get_image(buff, length, &my_charset_bin); - return length; - } - virtual void set_key_image(const uchar *buff,uint length) - { set_image(buff,length, &my_charset_bin); } - inline longlong val_int_offset(uint row_offset) - { - ptr+=row_offset; - longlong tmp=val_int(); - ptr-=row_offset; - return tmp; - } - inline longlong val_int(const uchar *new_ptr) - { - uchar *old_ptr= ptr; - longlong return_value; - ptr= (uchar*) new_ptr; - return_value= val_int(); - ptr= old_ptr; - return return_value; - } - inline String *val_str(String *str, const uchar *new_ptr) - { - uchar *old_ptr= ptr; - ptr= (uchar*) new_ptr; - val_str(str); - ptr= old_ptr; - return str; - } - virtual bool send_binary(Protocol *protocol); - - virtual uchar *pack(uchar *to, const uchar *from, uint max_length); - /** - @overload Field::pack(uchar*, const uchar*, uint, bool) - */ - uchar *pack(uchar *to, const uchar *from) - { - DBUG_ENTER("Field::pack"); - uchar *result= this->pack(to, from, UINT_MAX); - DBUG_RETURN(result); - } - - virtual const uchar *unpack(uchar* to, const uchar *from, - const uchar *from_end, uint param_data=0); - - virtual uint packed_col_length(const uchar *to, uint length) - { return length;} - virtual uint max_packed_col_length(uint max_length) - { return max_length;} - - uint offset(uchar *record) const - { - return (uint) (ptr - record); - } - void copy_from_tmp(int offset); - uint fill_cache_field(struct st_cache_field *copy); - virtual bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); - bool get_time(MYSQL_TIME *ltime) { return get_date(ltime, TIME_TIME_ONLY); } - virtual CHARSET_INFO *charset(void) const { return &my_charset_bin; } - virtual CHARSET_INFO *charset_for_protocol(void) const - { return binary() ? &my_charset_bin : charset(); } - virtual CHARSET_INFO *sort_charset(void) const { return charset(); } - virtual bool has_charset(void) const { return FALSE; } - virtual enum Derivation derivation(void) const - { return DERIVATION_IMPLICIT; } - virtual uint repertoire(void) const { return MY_REPERTOIRE_UNICODE30; } - virtual void set_derivation(enum Derivation derivation_arg, - uint repertoire_arg) - { } - virtual int set_time() { return 1; } - bool set_warning(Sql_condition::enum_warning_level, unsigned int code, - int cuted_increment) const; -protected: - bool set_warning(unsigned int code, int cuted_increment) const - { - return set_warning(Sql_condition::WARN_LEVEL_WARN, code, cuted_increment); - } - bool set_note(unsigned int code, int cuted_increment) const - { - return set_warning(Sql_condition::WARN_LEVEL_NOTE, code, cuted_increment); - } - void set_datetime_warning(Sql_condition::enum_warning_level, uint code, - const ErrConv *str, timestamp_type ts_type, - int cuted_increment) const; - void set_datetime_warning(uint code, - const ErrConv *str, timestamp_type ts_type, - int cuted_increment) const - { - set_datetime_warning(Sql_condition::WARN_LEVEL_WARN, code, str, ts_type, - cuted_increment); - } - void set_warning_truncated_wrong_value(const char *type, const char *value); - inline bool check_overflow(int op_result) - { - return (op_result == E_DEC_OVERFLOW); - } - int warn_if_overflow(int op_result); - Copy_func *get_identical_copy_func() const; -public: - void set_table_name(String *alias) - { - table_name= &alias->Ptr; - } - void init(TABLE *table_arg) - { - orig_table= table= table_arg; - set_table_name(&table_arg->alias); - } - - /* maximum possible display length */ - virtual uint32 max_display_length()= 0; - - /** - Whether a field being created is compatible with a existing one. - - Used by the ALTER TABLE code to evaluate whether the new definition - of a table is compatible with the old definition so that it can - determine if data needs to be copied over (table data change). - */ - virtual uint is_equal(Create_field *new_field); - /* convert decimal to longlong with overflow check */ - longlong convert_decimal2longlong(const my_decimal *val, bool unsigned_flag, - int *err); - /* The max. number of characters */ - virtual uint32 char_length() const - { - return field_length / charset()->mbmaxlen; - } - - virtual geometry_type get_geometry_type() - { - /* shouldn't get here. */ - DBUG_ASSERT(0); - return GEOM_GEOMETRY; - } - - ha_storage_media field_storage_type() const - { - return (ha_storage_media) - ((flags >> FIELD_FLAGS_STORAGE_MEDIA) & 3); - } - - void set_storage_type(ha_storage_media storage_type_arg) - { - DBUG_ASSERT(field_storage_type() == HA_SM_DEFAULT); - flags |= static_cast(storage_type_arg) << - FIELD_FLAGS_STORAGE_MEDIA; - } - - column_format_type column_format() const - { - return (column_format_type) - ((flags >> FIELD_FLAGS_COLUMN_FORMAT) & 3); - } - - void set_column_format(column_format_type column_format_arg) - { - DBUG_ASSERT(column_format() == COLUMN_FORMAT_TYPE_DEFAULT); - flags |= static_cast(column_format_arg) << - FIELD_FLAGS_COLUMN_FORMAT; - } - - /* - System versioning support. - */ - - bool is_generated() - { - return flags & (GENERATED_ROW_START_FLAG | GENERATED_ROW_END_FLAG); - } - - bool is_generated_row_start() - { - return flags & GENERATED_ROW_START_FLAG; - } - - bool is_generated_row_end() - { - return flags & GENERATED_ROW_END_FLAG; - } - - bool is_versioning_disabled() - { - return flags & WITHOUT_SYSTEM_VERSIONING_FLAG; - } - - /* Mark a field as auto-generated row start column. */ - void set_generated_row_start() - { - //DBUG_ASSERT((flags & GENERATED_ROW_END_FLAG) == 0); - flags |= GENERATED_ROW_START_FLAG; - } - - /* Mark a field as auto-generated row start column. */ - void set_generated_row_end() - { - //DBUG_ASSERT((flags & GENERATED_ROW_START_FLAG) == 0); - flags |= GENERATED_ROW_END_FLAG; - } - - /* Disable a field versioning for a versioned table. */ - void disable_versioning() - { - flags |= WITHOUT_SYSTEM_VERSIONING_FLAG; - } - - /* Inherit a field versioning status from the table. */ - void inherit_versioning() - { - flags &= ~WITHOUT_SYSTEM_VERSIONING_FLAG; - } - - /* - Validate a non-null field value stored in the given record - according to the current thread settings, e.g. sql_mode. - @param thd - the thread - @param record - the record to check in - */ - virtual bool validate_value_in_record(THD *thd, const uchar *record) const - { return false; } - bool validate_value_in_record_with_warn(THD *thd, const uchar *record); - key_map get_possible_keys(); - - /* Hash value */ - virtual void hash(ulong *nr, ulong *nr2); - -/** - Checks whether a string field is part of write_set. - - @return - FALSE - If field is not char/varchar/.... - - If field is char/varchar/.. and is not part of write set. - TRUE - If field is char/varchar/.. and is part of write set. -*/ - virtual bool is_varchar_and_in_write_set() const { return FALSE; } - - /* Check whether the field can be used as a join attribute in hash join */ - virtual bool hash_join_is_possible() { return TRUE; } - virtual bool eq_cmp_as_binary() { return TRUE; } - - /* Position of the field value within the interval of [min, max] */ - virtual double pos_in_interval(Field *min, Field *max) - { - return (double) 0.5; - } - - /* - Check if comparison between the field and an item unambiguously - identifies a distinct field value. - - Example1: SELECT * FROM t1 WHERE int_column=10; - This example returns distinct integer value of 10. - - Example2: SELECT * FROM t1 WHERE varchar_column=DATE'2001-01-01' - This example returns non-distinct values. - Comparison as DATE will return '2001-01-01' and '2001-01-01x', - but these two values are not equal to each other as VARCHARs. - See also the function with the same name in sql_select.cc. - */ - virtual bool test_if_equality_guarantees_uniqueness(const Item *const_item) - const; - virtual bool can_be_substituted_to_equal_item(const Context &ctx, - const Item_equal *item); - virtual Item *get_equal_const_item(THD *thd, const Context &ctx, - Item *const_item) - { - return const_item; - } - virtual bool can_optimize_keypart_ref(const Item_bool_func *cond, - const Item *item) const; - virtual bool can_optimize_hash_join(const Item_bool_func *cond, - const Item *item) const - { - return can_optimize_keypart_ref(cond, item); - } - virtual bool can_optimize_group_min_max(const Item_bool_func *cond, - const Item *const_item) const; - /** - Test if Field can use range optimizer for a standard comparison operation: - <=, <, =, <=>, >, >= - Note, this method does not cover spatial operations. - */ - virtual bool can_optimize_range(const Item_bool_func *cond, - const Item *item, - bool is_eq_func) const; - - bool can_optimize_outer_join_table_elimination(const Item_bool_func *cond, - const Item *item) const - { - // Exactly the same rules with REF access - return can_optimize_keypart_ref(cond, item); - } - - bool save_in_field_default_value(bool view_eror_processing); - bool save_in_field_ignore_value(bool view_error_processing); - - /* Mark field in read map. Updates also virtual fields */ - void register_field_in_read_map(); - - friend int cre_myisam(char * name, register TABLE *form, uint options, - ulonglong auto_increment_value); - friend class Copy_field; - friend class Item_avg_field; - friend class Item_std_field; - friend class Item_sum_num; - friend class Item_sum_sum; - friend class Item_sum_count; - friend class Item_sum_avg; - friend class Item_sum_std; - friend class Item_sum_min; - friend class Item_sum_max; - friend class Item_func_group_concat; - -private: - /* - Primitive for implementing last_null_byte(). - - SYNOPSIS - do_last_null_byte() - - DESCRIPTION - Primitive for the implementation of the last_null_byte() - function. This represents the inheritance interface and can be - overridden by subclasses. - */ - virtual size_t do_last_null_byte() const; - -/** - Retrieve the field metadata for fields. - - This default implementation returns 0 and saves 0 in the metadata_ptr - value. - - @param metadata_ptr First byte of field metadata - - @returns 0 no bytes written. -*/ - virtual int do_save_field_metadata(uchar *metadata_ptr) - { return 0; } - -protected: - uchar *pack_int(uchar *to, const uchar *from, size_t size) - { - memcpy(to, from, size); - return to + size; - } - - const uchar *unpack_int(uchar* to, const uchar *from, - const uchar *from_end, size_t size) - { - if (from + size > from_end) - return 0; - memcpy(to, from, size); - return from + size; - } - - uchar *pack_int16(uchar *to, const uchar *from) - { return pack_int(to, from, 2); } - const uchar *unpack_int16(uchar* to, const uchar *from, const uchar *from_end) - { return unpack_int(to, from, from_end, 2); } - uchar *pack_int24(uchar *to, const uchar *from) - { return pack_int(to, from, 3); } - const uchar *unpack_int24(uchar* to, const uchar *from, const uchar *from_end) - { return unpack_int(to, from, from_end, 3); } - uchar *pack_int32(uchar *to, const uchar *from) - { return pack_int(to, from, 4); } - const uchar *unpack_int32(uchar* to, const uchar *from, const uchar *from_end) - { return unpack_int(to, from, from_end, 4); } - uchar *pack_int64(uchar* to, const uchar *from) - { return pack_int(to, from, 8); } - const uchar *unpack_int64(uchar* to, const uchar *from, const uchar *from_end) - { return unpack_int(to, from, from_end, 8); } - - double pos_in_interval_val_real(Field *min, Field *max); - double pos_in_interval_val_str(Field *min, Field *max, uint data_offset); -}; - - -class Field_num :public Field { -protected: - int check_edom_and_important_data_truncation(const char *type, bool edom, - CHARSET_INFO *cs, - const char *str, uint length, - const char *end_of_num); - int check_edom_and_truncation(const char *type, bool edom, - CHARSET_INFO *cs, - const char *str, uint length, - const char *end_of_num); - int check_int(CHARSET_INFO *cs, const char *str, uint length, - const char *int_end, int error) - { - return check_edom_and_truncation("integer", - error == MY_ERRNO_EDOM || str == int_end, - cs, str, length, int_end); - } - bool get_int(CHARSET_INFO *cs, const char *from, uint len, - longlong *rnd, ulonglong unsigned_max, - longlong signed_min, longlong signed_max); - void prepend_zeros(String *value) const; - Item *get_equal_zerofill_const_item(THD *thd, const Context &ctx, - Item *const_item); -public: - const uint8 dec; - bool zerofill,unsigned_flag; // Purify cannot handle bit fields - Field_num(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, - uchar null_bit_arg, utype unireg_check_arg, - const char *field_name_arg, - uint8 dec_arg, bool zero_arg, bool unsigned_arg); - enum Item_result result_type () const { return INT_RESULT; } - enum Derivation derivation(void) const { return DERIVATION_NUMERIC; } - uint repertoire(void) const { return MY_REPERTOIRE_NUMERIC; } - CHARSET_INFO *charset(void) const { return &my_charset_numeric; } - Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item) - { - return (flags & ZEROFILL_FLAG) ? - get_equal_zerofill_const_item(thd, ctx, const_item) : - const_item; - } - void add_zerofill_and_unsigned(String &res) const; - friend class Create_field; - void make_field(Send_field *); - uint decimals() const { return (uint) dec; } - uint size_of() const { return sizeof(*this); } - bool eq_def(const Field *field) const; - Copy_func *get_copy_func(const Field *from) const - { - return do_field_int; - } - int save_in_field(Field *to) - { - return to->store(val_int(), MY_TEST(flags & UNSIGNED_FLAG)); - } - bool memcpy_field_possible(const Field *from) const - { - return real_type() == from->real_type() && - pack_length() == from->pack_length() && - !((flags & UNSIGNED_FLAG) && !(from->flags & UNSIGNED_FLAG)) && - decimals() == from->decimals(); - } - int store_decimal(const my_decimal *); - my_decimal *val_decimal(my_decimal *); - bool val_bool() { return val_int() != 0; } - uint is_equal(Create_field *new_field); - uint row_pack_length() const { return pack_length(); } - uint32 pack_length_from_metadata(uint field_metadata) { - uint32 length= pack_length(); - DBUG_PRINT("result", ("pack_length_from_metadata(%d): %u", - field_metadata, length)); - return length; - } - int store_time_dec(MYSQL_TIME *ltime, uint dec); - double pos_in_interval(Field *min, Field *max) - { - return pos_in_interval_val_real(min, max); - } - bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); -}; - - -class Field_str :public Field { -protected: - // TODO-10.2: Reuse DTCollation instead of these three members - CHARSET_INFO *field_charset; - enum Derivation field_derivation; - uint field_repertoire; -public: - bool can_be_substituted_to_equal_item(const Context &ctx, - const Item_equal *item_equal); - Field_str(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, - uchar null_bit_arg, utype unireg_check_arg, - const char *field_name_arg, CHARSET_INFO *charset); - Item_result result_type () const { return STRING_RESULT; } - uint decimals() const { return NOT_FIXED_DEC; } - int save_in_field(Field *to) { return save_in_field_str(to); } - bool memcpy_field_possible(const Field *from) const - { - return real_type() == from->real_type() && - pack_length() == from->pack_length() && - charset() == from->charset(); - } - int store(double nr); - int store(longlong nr, bool unsigned_val)=0; - int store_decimal(const my_decimal *); - int store(const char *to,uint length,CHARSET_INFO *cs)=0; - int store_hex_hybrid(const char *str, uint length) - { - return store(str, length, &my_charset_bin); - } - uint repertoire(void) const { return field_repertoire; } - CHARSET_INFO *charset(void) const { return field_charset; } - enum Derivation derivation(void) const { return field_derivation; } - void set_derivation(enum Derivation derivation_arg, - uint repertoire_arg) - { - field_derivation= derivation_arg; - field_repertoire= repertoire_arg; - } - bool binary() const { return field_charset == &my_charset_bin; } - uint32 max_display_length() { return field_length; } - friend class Create_field; - my_decimal *val_decimal(my_decimal *); - bool val_bool() { return val_real() != 0e0; } - virtual bool str_needs_quotes() { return TRUE; } - uint is_equal(Create_field *new_field); - bool eq_cmp_as_binary() { return MY_TEST(flags & BINARY_FLAG); } - virtual uint length_size() { return 0; } - double pos_in_interval(Field *min, Field *max) - { - return pos_in_interval_val_str(min, max, length_size()); - } - bool test_if_equality_guarantees_uniqueness(const Item *const_item) const; -}; - -/* base class for Field_string, Field_varstring and Field_blob */ - -class Field_longstr :public Field_str -{ -protected: - int report_if_important_data(const char *ptr, const char *end, - bool count_spaces); - bool check_string_copy_error(const String_copier *copier, - const char *end, CHARSET_INFO *cs); - int check_conversion_status(const String_copier *copier, - const char *end, CHARSET_INFO *cs, - bool count_spaces) - { - if (check_string_copy_error(copier, end, cs)) - return 2; - return report_if_important_data(copier->source_end_pos(), - end, count_spaces); - } - bool cmp_to_string_with_same_collation(const Item_bool_func *cond, - const Item *item) const; - bool cmp_to_string_with_stricter_collation(const Item_bool_func *cond, - const Item *item) const; -public: - Field_longstr(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, - uchar null_bit_arg, utype unireg_check_arg, - const char *field_name_arg, CHARSET_INFO *charset_arg) - :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, - field_name_arg, charset_arg) - {} - - int store_decimal(const my_decimal *d); - uint32 max_data_length() const; - - bool is_varchar_and_in_write_set() const - { - DBUG_ASSERT(table && table->write_set); - return bitmap_is_set(table->write_set, field_index); - } - bool match_collation_to_optimize_range() const { return true; } - - bool can_optimize_keypart_ref(const Item_bool_func *cond, - const Item *item) const; - bool can_optimize_hash_join(const Item_bool_func *cond, - const Item *item) const; - bool can_optimize_group_min_max(const Item_bool_func *cond, - const Item *const_item) const; - bool can_optimize_range(const Item_bool_func *cond, - const Item *item, - bool is_eq_func) const; -}; - -/* base class for float and double and decimal (old one) */ -class Field_real :public Field_num { -protected: - double get_double(const char *str, uint length, CHARSET_INFO *cs, int *err); -public: - bool not_fixed; - - Field_real(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, - uchar null_bit_arg, utype unireg_check_arg, - const char *field_name_arg, - uint8 dec_arg, bool zero_arg, bool unsigned_arg) - :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, - field_name_arg, dec_arg, zero_arg, unsigned_arg), - not_fixed(dec_arg >= FLOATING_POINT_DECIMALS) - {} - Item_result result_type () const { return REAL_RESULT; } - Copy_func *get_copy_func(const Field *from) const - { - return do_field_real; - } - int save_in_field(Field *to) { return to->store(val_real()); } - bool memcpy_field_possible(const Field *from) const - { - /* - Cannot do memcpy from a longer field to a shorter field, - e.g. a DOUBLE(53,10) into a DOUBLE(10,10). - But it should be OK the other way around. - */ - return Field_num::memcpy_field_possible(from) && - field_length >= from->field_length; - } - int store_decimal(const my_decimal *); - int store_time_dec(MYSQL_TIME *ltime, uint dec); - bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); - my_decimal *val_decimal(my_decimal *); - bool val_bool() { return val_real() != 0e0; } - uint32 max_display_length() { return field_length; } - uint size_of() const { return sizeof(*this); } - Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item); -}; - - -class Field_decimal :public Field_real { -public: - Field_decimal(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, - uchar null_bit_arg, - enum utype unireg_check_arg, const char *field_name_arg, - uint8 dec_arg,bool zero_arg,bool unsigned_arg) - :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, - dec_arg, zero_arg, unsigned_arg) - {} - enum_field_types type() const { return MYSQL_TYPE_DECIMAL;} - enum ha_base_keytype key_type() const - { return zerofill ? HA_KEYTYPE_BINARY : HA_KEYTYPE_NUM; } - Copy_func *get_copy_func(const Field *from) const - { - return eq_def(from) ? get_identical_copy_func() : do_field_string; - } - int reset(void); - int store(const char *to,uint length,CHARSET_INFO *charset); - int store(double nr); - int store(longlong nr, bool unsigned_val); - double val_real(void); - longlong val_int(void); - String *val_str(String*,String *); - int cmp(const uchar *,const uchar *); - void sort_string(uchar *buff,uint length); - void overflow(bool negative); - bool zero_pack() const { return 0; } - void sql_type(String &str) const; - virtual uchar *pack(uchar* to, const uchar *from, uint max_length) - { - return Field::pack(to, from, max_length); - } -}; - - -/* New decimal/numeric field which use fixed point arithmetic */ -class Field_new_decimal :public Field_num { -private: - int do_save_field_metadata(uchar *first_byte); -public: - /* The maximum number of decimal digits can be stored */ - uint precision; - uint bin_size; - /* - Constructors take max_length of the field as a parameter - not the - precision as the number of decimal digits allowed. - So for example we need to count length from precision handling - CREATE TABLE ( DECIMAL(x,y)) - */ - Field_new_decimal(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, - uchar null_bit_arg, - enum utype unireg_check_arg, const char *field_name_arg, - uint8 dec_arg, bool zero_arg, bool unsigned_arg); - Field_new_decimal(uint32 len_arg, bool maybe_null_arg, - const char *field_name_arg, uint8 dec_arg, - bool unsigned_arg); - enum_field_types type() const { return MYSQL_TYPE_NEWDECIMAL;} - enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } - Item_result result_type () const { return DECIMAL_RESULT; } - Copy_func *get_copy_func(const Field *from) const - { - // if (from->real_type() == MYSQL_TYPE_BIT) // QQ: why? - // return do_field_int; - return do_field_decimal; - } - int save_in_field(Field *to) - { - my_decimal buff; - return to->store_decimal(val_decimal(&buff)); - } - bool memcpy_field_possible(const Field *from) const - { - return Field_num::memcpy_field_possible(from) && - field_length == from->field_length; - } - int reset(void); - bool store_value(const my_decimal *decimal_value); - bool store_value(const my_decimal *decimal_value, int *native_error); - void set_value_on_overflow(my_decimal *decimal_value, bool sign); - int store(const char *to, uint length, CHARSET_INFO *charset); - int store(double nr); - int store(longlong nr, bool unsigned_val); - int store_time_dec(MYSQL_TIME *ltime, uint dec); - int store_decimal(const my_decimal *); - double val_real(void); - longlong val_int(void); - my_decimal *val_decimal(my_decimal *); - String *val_str(String*, String *); - bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); - bool val_bool() - { - my_decimal decimal_value; - my_decimal *val= val_decimal(&decimal_value); - return val ? !my_decimal_is_zero(val) : 0; - } - int cmp(const uchar *, const uchar *); - void sort_string(uchar *buff, uint length); - bool zero_pack() const { return 0; } - void sql_type(String &str) const; - uint32 max_display_length() { return field_length; } - uint size_of() const { return sizeof(*this); } - uint32 pack_length() const { return (uint32) bin_size; } - uint pack_length_from_metadata(uint field_metadata); - uint row_pack_length() const { return pack_length(); } - bool compatible_field_size(uint field_metadata, Relay_log_info *rli, - uint16 mflags, int *order_var); - uint is_equal(Create_field *new_field); - virtual const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint param_data); - static Field *create_from_item(MEM_ROOT *root, Item *); - Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item); -}; - - -class Field_tiny :public Field_num { -public: - Field_tiny(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, - uchar null_bit_arg, - enum utype unireg_check_arg, const char *field_name_arg, - bool zero_arg, bool unsigned_arg) - :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, - 0, zero_arg,unsigned_arg) - {} - enum_field_types type() const { return MYSQL_TYPE_TINY;} - enum ha_base_keytype key_type() const - { return unsigned_flag ? HA_KEYTYPE_BINARY : HA_KEYTYPE_INT8; } - int store(const char *to,uint length,CHARSET_INFO *charset); - int store(double nr); - int store(longlong nr, bool unsigned_val); - int reset(void) { ptr[0]=0; return 0; } - double val_real(void); - longlong val_int(void); - String *val_str(String*,String *); - bool send_binary(Protocol *protocol); - int cmp(const uchar *,const uchar *); - void sort_string(uchar *buff,uint length); - uint32 pack_length() const { return 1; } - void sql_type(String &str) const; - uint32 max_display_length() { return 4; } - - virtual uchar *pack(uchar* to, const uchar *from, uint max_length) - { - *to= *from; - return to + 1; - } - - virtual const uchar *unpack(uchar* to, const uchar *from, - const uchar *from_end, uint param_data) - { - if (from == from_end) - return 0; - *to= *from; - return from + 1; - } -}; - - -class Field_short :public Field_num { -public: - Field_short(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, - uchar null_bit_arg, - enum utype unireg_check_arg, const char *field_name_arg, - bool zero_arg, bool unsigned_arg) - :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, - 0, zero_arg,unsigned_arg) - {} - Field_short(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, - bool unsigned_arg) - :Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0, - NONE, field_name_arg, 0, 0, unsigned_arg) - {} - enum_field_types type() const { return MYSQL_TYPE_SHORT;} - enum ha_base_keytype key_type() const - { return unsigned_flag ? HA_KEYTYPE_USHORT_INT : HA_KEYTYPE_SHORT_INT;} - int store(const char *to,uint length,CHARSET_INFO *charset); - int store(double nr); - int store(longlong nr, bool unsigned_val); - int reset(void) { ptr[0]=ptr[1]=0; return 0; } - double val_real(void); - longlong val_int(void); - String *val_str(String*,String *); - bool send_binary(Protocol *protocol); - int cmp(const uchar *,const uchar *); - void sort_string(uchar *buff,uint length); - uint32 pack_length() const { return 2; } - void sql_type(String &str) const; - uint32 max_display_length() { return 6; } - - virtual uchar *pack(uchar* to, const uchar *from, uint max_length) - { return pack_int16(to, from); } - - virtual const uchar *unpack(uchar* to, const uchar *from, - const uchar *from_end, uint param_data) - { return unpack_int16(to, from, from_end); } -}; - -class Field_medium :public Field_num { -public: - Field_medium(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, - uchar null_bit_arg, - enum utype unireg_check_arg, const char *field_name_arg, - bool zero_arg, bool unsigned_arg) - :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, - 0, zero_arg,unsigned_arg) - {} - enum_field_types type() const { return MYSQL_TYPE_INT24;} - enum ha_base_keytype key_type() const - { return unsigned_flag ? HA_KEYTYPE_UINT24 : HA_KEYTYPE_INT24; } - int store(const char *to,uint length,CHARSET_INFO *charset); - int store(double nr); - int store(longlong nr, bool unsigned_val); - int reset(void) { ptr[0]=ptr[1]=ptr[2]=0; return 0; } - double val_real(void); - longlong val_int(void); - String *val_str(String*,String *); - bool send_binary(Protocol *protocol); - int cmp(const uchar *,const uchar *); - void sort_string(uchar *buff,uint length); - uint32 pack_length() const { return 3; } - void sql_type(String &str) const; - uint32 max_display_length() { return 8; } - - virtual uchar *pack(uchar* to, const uchar *from, uint max_length) - { - return Field::pack(to, from, max_length); - } -}; - - -class Field_long :public Field_num { -public: - Field_long(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, - uchar null_bit_arg, - enum utype unireg_check_arg, const char *field_name_arg, - bool zero_arg, bool unsigned_arg) - :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, - 0, zero_arg,unsigned_arg) - {} - Field_long(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, - bool unsigned_arg) - :Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0, - NONE, field_name_arg,0,0,unsigned_arg) - {} - enum_field_types type() const { return MYSQL_TYPE_LONG;} - enum ha_base_keytype key_type() const - { return unsigned_flag ? HA_KEYTYPE_ULONG_INT : HA_KEYTYPE_LONG_INT; } - int store(const char *to,uint length,CHARSET_INFO *charset); - int store(double nr); - int store(longlong nr, bool unsigned_val); - int reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; } - double val_real(void); - longlong val_int(void); - bool send_binary(Protocol *protocol); - String *val_str(String*,String *); - int cmp(const uchar *,const uchar *); - void sort_string(uchar *buff,uint length); - uint32 pack_length() const { return 4; } - void sql_type(String &str) const; - uint32 max_display_length() { return MY_INT32_NUM_DECIMAL_DIGITS; } - virtual uchar *pack(uchar* to, const uchar *from, - uint max_length __attribute__((unused))) - { - return pack_int32(to, from); - } - virtual const uchar *unpack(uchar* to, const uchar *from, - const uchar *from_end, - uint param_data __attribute__((unused))) - { - return unpack_int32(to, from, from_end); - } -}; - - -class Field_longlong :public Field_num { -public: - Field_longlong(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, - uchar null_bit_arg, - enum utype unireg_check_arg, const char *field_name_arg, - bool zero_arg, bool unsigned_arg) - :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, - 0, zero_arg,unsigned_arg) - {} - Field_longlong(uint32 len_arg,bool maybe_null_arg, - const char *field_name_arg, - bool unsigned_arg) - :Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0, - NONE, field_name_arg,0,0,unsigned_arg) - {} - enum_field_types type() const { return MYSQL_TYPE_LONGLONG;} - enum ha_base_keytype key_type() const - { return unsigned_flag ? HA_KEYTYPE_ULONGLONG : HA_KEYTYPE_LONGLONG; } - int store(const char *to,uint length,CHARSET_INFO *charset); - int store(double nr); - int store(longlong nr, bool unsigned_val); - int reset(void) - { - ptr[0]=ptr[1]=ptr[2]=ptr[3]=ptr[4]=ptr[5]=ptr[6]=ptr[7]=0; - return 0; - } - double val_real(void); - longlong val_int(void); - String *val_str(String*,String *); - bool send_binary(Protocol *protocol); - int cmp(const uchar *,const uchar *); - void sort_string(uchar *buff,uint length); - uint32 pack_length() const { return 8; } - void sql_type(String &str) const; - uint32 max_display_length() { return 20; } - virtual uchar *pack(uchar* to, const uchar *from, - uint max_length __attribute__((unused))) - { - return pack_int64(to, from); - } - const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, - uint param_data __attribute__((unused))) - { - return unpack_int64(to, from, from_end); - } - - bool set_max(); - bool is_max(); -}; - - -class Field_float :public Field_real { -public: - Field_float(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, - uchar null_bit_arg, - enum utype unireg_check_arg, const char *field_name_arg, - uint8 dec_arg,bool zero_arg,bool unsigned_arg) - :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, - dec_arg, zero_arg, unsigned_arg) - { - if (dec_arg >= FLOATING_POINT_DECIMALS) - dec_arg= NOT_FIXED_DEC; - } - Field_float(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg, - uint8 dec_arg) - :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0, - NONE, field_name_arg, dec_arg, 0, 0) - { - if (dec_arg >= FLOATING_POINT_DECIMALS) - dec_arg= NOT_FIXED_DEC; - } - enum_field_types type() const { return MYSQL_TYPE_FLOAT;} - enum ha_base_keytype key_type() const { return HA_KEYTYPE_FLOAT; } - int store(const char *to,uint length,CHARSET_INFO *charset); - int store(double nr); - int store(longlong nr, bool unsigned_val); - int reset(void) { bzero(ptr,sizeof(float)); return 0; } - double val_real(void); - longlong val_int(void); - String *val_str(String*,String *); - bool send_binary(Protocol *protocol); - int cmp(const uchar *,const uchar *); - void sort_string(uchar *buff,uint length); - uint32 pack_length() const { return sizeof(float); } - uint row_pack_length() const { return pack_length(); } - void sql_type(String &str) const; -private: - int do_save_field_metadata(uchar *first_byte); -}; - - -class Field_double :public Field_real { -public: - Field_double(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, - uchar null_bit_arg, - enum utype unireg_check_arg, const char *field_name_arg, - uint8 dec_arg,bool zero_arg,bool unsigned_arg) - :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, - dec_arg, zero_arg, unsigned_arg) - { - if (dec_arg >= FLOATING_POINT_DECIMALS) - dec_arg= NOT_FIXED_DEC; - } - Field_double(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg, - uint8 dec_arg) - :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0, - NONE, field_name_arg, dec_arg, 0, 0) - { - if (dec_arg >= FLOATING_POINT_DECIMALS) - dec_arg= NOT_FIXED_DEC; - } - Field_double(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg, - uint8 dec_arg, bool not_fixed_arg) - :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0, - NONE, field_name_arg, dec_arg, 0, 0) - { - not_fixed= not_fixed_arg; - if (dec_arg >= FLOATING_POINT_DECIMALS) - dec_arg= NOT_FIXED_DEC; - } - enum_field_types type() const { return MYSQL_TYPE_DOUBLE;} - enum ha_base_keytype key_type() const { return HA_KEYTYPE_DOUBLE; } - int store(const char *to,uint length,CHARSET_INFO *charset); - int store(double nr); - int store(longlong nr, bool unsigned_val); - int reset(void) { bzero(ptr,sizeof(double)); return 0; } - double val_real(void); - longlong val_int(void) - { - Converter_double_to_longlong conv(Field_double::val_real(), false); - if (conv.error()) - conv.push_warning(get_thd(), Field_double::val_real(), false); - return conv.result(); - } - String *val_str(String*,String *); - bool send_binary(Protocol *protocol); - int cmp(const uchar *,const uchar *); - void sort_string(uchar *buff,uint length); - uint32 pack_length() const { return sizeof(double); } - uint row_pack_length() const { return pack_length(); } - void sql_type(String &str) const; -private: - int do_save_field_metadata(uchar *first_byte); -}; - - -/* Everything saved in this will disappear. It will always return NULL */ - -class Field_null :public Field_str { - static uchar null[1]; -public: - Field_null(uchar *ptr_arg, uint32 len_arg, - enum utype unireg_check_arg, const char *field_name_arg, - CHARSET_INFO *cs) - :Field_str(ptr_arg, len_arg, null, 1, - unireg_check_arg, field_name_arg, cs) - {} - enum_field_types type() const { return MYSQL_TYPE_NULL;} - Copy_func *get_copy_func(const Field *from) const - { - return do_field_string; - } - int store(const char *to, uint length, CHARSET_INFO *cs) - { null[0]=1; return 0; } - int store(double nr) { null[0]=1; return 0; } - int store(longlong nr, bool unsigned_val) { null[0]=1; return 0; } - int store_decimal(const my_decimal *d) { null[0]=1; return 0; } - int reset(void) { return 0; } - double val_real(void) { return 0.0;} - longlong val_int(void) { return 0;} - bool val_bool(void) { return false; } - my_decimal *val_decimal(my_decimal *) { return 0; } - String *val_str(String *value,String *value2) - { value2->length(0); return value2;} - int cmp(const uchar *a, const uchar *b) { return 0;} - void sort_string(uchar *buff, uint length) {} - uint32 pack_length() const { return 0; } - void sql_type(String &str) const; - uint size_of() const { return sizeof(*this); } - uint32 max_display_length() { return 4; } - void move_field_offset(my_ptrdiff_t ptr_diff) {} - bool can_optimize_keypart_ref(const Item_bool_func *cond, - const Item *item) const - { - DBUG_ASSERT(0); - return false; - } - bool can_optimize_group_min_max(const Item_bool_func *cond, - const Item *const_item) const - { - DBUG_ASSERT(0); - return false; - } -}; - - -class Field_temporal: public Field { -protected: - Item *get_equal_const_item_datetime(THD *thd, const Context &ctx, - Item *const_item); -public: - Field_temporal(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, - uchar null_bit_arg, utype unireg_check_arg, - const char *field_name_arg) - :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, - field_name_arg) - { flags|= BINARY_FLAG; } - Item_result result_type () const { return STRING_RESULT; } - int store_hex_hybrid(const char *str, uint length) - { - return store(str, length, &my_charset_bin); - } - Copy_func *get_copy_func(const Field *from) const; - int save_in_field(Field *to) - { - MYSQL_TIME ltime; - if (get_date(<ime, 0)) - return to->reset(); - return to->store_time_dec(<ime, decimals()); - } - bool memcpy_field_possible(const Field *from) const; - uint32 max_display_length() { return field_length; } - bool str_needs_quotes() { return TRUE; } - enum Derivation derivation(void) const { return DERIVATION_NUMERIC; } - uint repertoire(void) const { return MY_REPERTOIRE_NUMERIC; } - CHARSET_INFO *charset(void) const { return &my_charset_numeric; } - CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; } - bool binary() const { return true; } - enum Item_result cmp_type () const { return TIME_RESULT; } - bool val_bool() { return val_real() != 0e0; } - uint is_equal(Create_field *new_field); - bool eq_def(const Field *field) const - { - return (Field::eq_def(field) && decimals() == field->decimals()); - } - my_decimal *val_decimal(my_decimal*); - void set_warnings(Sql_condition::enum_warning_level trunc_level, - const ErrConv *str, int was_cut, timestamp_type ts_type); - double pos_in_interval(Field *min, Field *max) - { - return pos_in_interval_val_real(min, max); - } - bool can_optimize_keypart_ref(const Item_bool_func *cond, - const Item *item) const; - bool can_optimize_group_min_max(const Item_bool_func *cond, - const Item *const_item) const; - bool can_optimize_range(const Item_bool_func *cond, - const Item *item, - bool is_eq_func) const - { - return true; - } -}; - - -/** - Abstract class for: - - DATE - - DATETIME - - DATETIME(1..6) - - DATETIME(0..6) - MySQL56 version -*/ -class Field_temporal_with_date: public Field_temporal { -protected: - int store_TIME_with_warning(MYSQL_TIME *ltime, const ErrConv *str, - int was_cut, int have_smth_to_conv); - virtual void store_TIME(MYSQL_TIME *ltime) = 0; - virtual bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, - ulonglong fuzzydate) const = 0; - bool validate_MMDD(bool not_zero_date, uint month, uint day, - ulonglong fuzzydate) const - { - if (!not_zero_date) - return fuzzydate & TIME_NO_ZERO_DATE; - if (!month || !day) - return fuzzydate & TIME_NO_ZERO_IN_DATE; - return false; - } -public: - Field_temporal_with_date(uchar *ptr_arg, uint32 len_arg, - uchar *null_ptr_arg, uchar null_bit_arg, - utype unireg_check_arg, - const char *field_name_arg) - :Field_temporal(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg) - {} - int store(const char *to, uint length, CHARSET_INFO *charset); - int store(double nr); - int store(longlong nr, bool unsigned_val); - int store_time_dec(MYSQL_TIME *ltime, uint dec); - int store_decimal(const my_decimal *); - bool validate_value_in_record(THD *thd, const uchar *record) const; -}; - - -class Field_timestamp :public Field_temporal { -protected: - int store_TIME_with_warning(THD *, MYSQL_TIME *, const ErrConv *, - int warnings, bool have_smth_to_conv); -public: - Field_timestamp(uchar *ptr_arg, uint32 len_arg, - uchar *null_ptr_arg, uchar null_bit_arg, - enum utype unireg_check_arg, const char *field_name_arg, - TABLE_SHARE *share); - enum_field_types type() const { return MYSQL_TYPE_TIMESTAMP;} - enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; } - int store(const char *to,uint length,CHARSET_INFO *charset); - int store(double nr); - int store(longlong nr, bool unsigned_val); - int store_time_dec(MYSQL_TIME *ltime, uint dec); - int store_decimal(const my_decimal *); - double val_real(void); - longlong val_int(void); - String *val_str(String*,String *); - bool send_binary(Protocol *protocol); - int cmp(const uchar *,const uchar *); - void sort_string(uchar *buff,uint length); - uint32 pack_length() const { return 4; } - void sql_type(String &str) const; - bool zero_pack() const { return 0; } - int set_time(); - bool set_explicit_default(Item *value); - int evaluate_update_default_function() - { - int res= 0; - if (has_update_default_function()) - res= set_time(); - return res; - } - /* Get TIMESTAMP field value as seconds since begging of Unix Epoch */ - virtual my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const; - my_time_t get_timestamp(ulong *sec_part) const - { - return get_timestamp(ptr, sec_part); - } - virtual void store_TIME(my_time_t timestamp, ulong sec_part) - { - int4store(ptr,timestamp); - } - bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); - uchar *pack(uchar *to, const uchar *from, - uint max_length __attribute__((unused))) - { - return pack_int32(to, from); - } - const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, - uint param_data __attribute__((unused))) - { - return unpack_int32(to, from, from_end); - } - bool validate_value_in_record(THD *thd, const uchar *record) const; - Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item) - { - return get_equal_const_item_datetime(thd, ctx, const_item); - } - uint size_of() const { return sizeof(*this); } -}; - - -/** - Abstract class for: - - TIMESTAMP(1..6) - - TIMESTAMP(0..6) - MySQL56 version -*/ -class Field_timestamp_with_dec :public Field_timestamp { -protected: - uint dec; -public: - Field_timestamp_with_dec(uchar *ptr_arg, - uchar *null_ptr_arg, uchar null_bit_arg, - enum utype unireg_check_arg, - const char *field_name_arg, - TABLE_SHARE *share, uint dec_arg) : - Field_timestamp(ptr_arg, - MAX_DATETIME_WIDTH + dec_arg + MY_TEST(dec_arg), null_ptr_arg, - null_bit_arg, unireg_check_arg, field_name_arg, share), - dec(dec_arg) - { - DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS); - } - uint decimals() const { return dec; } - enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } - uchar *pack(uchar *to, const uchar *from, uint max_length) - { return Field::pack(to, from, max_length); } - const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, - uint param_data) - { return Field::unpack(to, from, from_end, param_data); } - void make_field(Send_field *field); - void sort_string(uchar *to, uint length) - { - DBUG_ASSERT(length == pack_length()); - memcpy(to, ptr, length); - } - bool send_binary(Protocol *protocol); - double val_real(void); - my_decimal* val_decimal(my_decimal*); - int set_time(); -}; - - -class Field_timestamp_hires :public Field_timestamp_with_dec { -public: - Field_timestamp_hires(uchar *ptr_arg, - uchar *null_ptr_arg, uchar null_bit_arg, - enum utype unireg_check_arg, - const char *field_name_arg, - TABLE_SHARE *share, uint dec_arg) : - Field_timestamp_with_dec(ptr_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, share, dec_arg) - { - DBUG_ASSERT(dec); - } - my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const; - void store_TIME(my_time_t timestamp, ulong sec_part); - int cmp(const uchar *,const uchar *); - uint32 pack_length() const; - uint size_of() const { return sizeof(*this); } -}; - - -/** - TIMESTAMP(0..6) - MySQL56 version -*/ -class Field_timestampf :public Field_timestamp_with_dec { - int do_save_field_metadata(uchar *metadata_ptr) - { - *metadata_ptr= decimals(); - return 1; - } -public: - Field_timestampf(uchar *ptr_arg, - uchar *null_ptr_arg, uchar null_bit_arg, - enum utype unireg_check_arg, - const char *field_name_arg, - TABLE_SHARE *share, uint dec_arg) : - Field_timestamp_with_dec(ptr_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, share, dec_arg) - {} - enum_field_types real_type() const { return MYSQL_TYPE_TIMESTAMP2; } - enum_field_types binlog_type() const { return MYSQL_TYPE_TIMESTAMP2; } - uint32 pack_length() const - { - return my_timestamp_binary_length(dec); - } - uint row_pack_length() const { return pack_length(); } - uint pack_length_from_metadata(uint field_metadata) - { - DBUG_ENTER("Field_timestampf::pack_length_from_metadata"); - uint tmp= my_timestamp_binary_length(field_metadata); - DBUG_RETURN(tmp); - } - int cmp(const uchar *a_ptr,const uchar *b_ptr) - { - return memcmp(a_ptr, b_ptr, pack_length()); - } - bool set_max(); - bool is_max(); - void store_TIME(my_time_t timestamp, ulong sec_part); - my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const; - uint size_of() const { return sizeof(*this); } -}; - - -class Field_year :public Field_tiny { -public: - Field_year(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, - uchar null_bit_arg, - enum utype unireg_check_arg, const char *field_name_arg) - :Field_tiny(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, 1, 1) - {} - enum_field_types type() const { return MYSQL_TYPE_YEAR;} - Copy_func *get_copy_func(const Field *from) const - { - if (eq_def(from)) - return get_identical_copy_func(); - switch (from->cmp_type()) { - case STRING_RESULT: - return do_field_string; - case TIME_RESULT: - return do_field_temporal; - case DECIMAL_RESULT: - return do_field_decimal; - case REAL_RESULT: - return do_field_real; - case INT_RESULT: - break; - case ROW_RESULT: - default: - DBUG_ASSERT(0); - break; - } - return do_field_int; - } - int store(const char *to,uint length,CHARSET_INFO *charset); - int store(double nr); - int store(longlong nr, bool unsigned_val); - int store_time_dec(MYSQL_TIME *ltime, uint dec); - double val_real(void); - longlong val_int(void); - String *val_str(String*,String *); - bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); - bool send_binary(Protocol *protocol); - uint32 max_display_length() { return field_length; } - void sql_type(String &str) const; -}; - - -class Field_date :public Field_temporal_with_date { - void store_TIME(MYSQL_TIME *ltime); - bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const; -public: - Field_date(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, - enum utype unireg_check_arg, const char *field_name_arg) - :Field_temporal_with_date(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg) {} - enum_field_types type() const { return MYSQL_TYPE_DATE;} - enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; } - int reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; } - bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) - { return Field_date::get_TIME(ltime, ptr, fuzzydate); } - double val_real(void); - longlong val_int(void); - String *val_str(String*,String *); - bool send_binary(Protocol *protocol); - int cmp(const uchar *,const uchar *); - void sort_string(uchar *buff,uint length); - uint32 pack_length() const { return 4; } - void sql_type(String &str) const; - uchar *pack(uchar* to, const uchar *from, - uint max_length __attribute__((unused))) - { - return pack_int32(to, from); - } - const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, - uint param_data __attribute__((unused))) - { - return unpack_int32(to, from, from_end); - } - uint size_of() const { return sizeof(*this); } -}; - - -class Field_newdate :public Field_temporal_with_date { - void store_TIME(MYSQL_TIME *ltime); - bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const; -public: - Field_newdate(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, - enum utype unireg_check_arg, const char *field_name_arg) - :Field_temporal_with_date(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg) - {} - enum_field_types type() const { return MYSQL_TYPE_DATE;} - enum_field_types real_type() const { return MYSQL_TYPE_NEWDATE; } - enum ha_base_keytype key_type() const { return HA_KEYTYPE_UINT24; } - int reset(void) { ptr[0]=ptr[1]=ptr[2]=0; return 0; } - double val_real(void); - longlong val_int(void); - String *val_str(String*,String *); - bool send_binary(Protocol *protocol); - int cmp(const uchar *,const uchar *); - void sort_string(uchar *buff,uint length); - uint32 pack_length() const { return 3; } - void sql_type(String &str) const; - bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) - { return Field_newdate::get_TIME(ltime, ptr, fuzzydate); } - uint size_of() const { return sizeof(*this); } - Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item); -}; - - -class Field_time :public Field_temporal { - /* - when this Field_time instance is used for storing values for index lookups - (see class store_key, Field::new_key_field(), etc), the following - might be set to TO_DAYS(CURDATE()). See also Field_time::store_time_dec() - */ - long curdays; -protected: - virtual void store_TIME(MYSQL_TIME *ltime); - int store_TIME_with_warning(MYSQL_TIME *ltime, const ErrConv *str, - int was_cut, int have_smth_to_conv); - bool check_zero_in_date_with_warn(ulonglong fuzzydate); - static void do_field_time(Copy_field *copy); -public: - Field_time(uchar *ptr_arg, uint length_arg, uchar *null_ptr_arg, - uchar null_bit_arg, enum utype unireg_check_arg, - const char *field_name_arg) - :Field_temporal(ptr_arg, length_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg), curdays(0) - {} - enum_field_types type() const { return MYSQL_TYPE_TIME;} - enum ha_base_keytype key_type() const { return HA_KEYTYPE_INT24; } - Copy_func *get_copy_func(const Field *from) const - { - return from->cmp_type() == REAL_RESULT ? do_field_string : // MDEV-9344 - from->type() == MYSQL_TYPE_YEAR ? do_field_int : - from->type() == MYSQL_TYPE_BIT ? do_field_int : - eq_def(from) ? get_identical_copy_func() : - do_field_time; - } - bool memcpy_field_possible(const Field *from) const - { - return real_type() == from->real_type() && - decimals() == from->decimals(); - } - int store_time_dec(MYSQL_TIME *ltime, uint dec); - int store(const char *to,uint length,CHARSET_INFO *charset); - int store(double nr); - int store(longlong nr, bool unsigned_val); - int store_decimal(const my_decimal *); - double val_real(void); - longlong val_int(void); - String *val_str(String*,String *); - bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); - bool send_binary(Protocol *protocol); - int cmp(const uchar *,const uchar *); - void sort_string(uchar *buff,uint length); - uint32 pack_length() const { return 3; } - void sql_type(String &str) const; - uint size_of() const { return sizeof(*this); } - void set_curdays(THD *thd); - Field *new_key_field(MEM_ROOT *root, TABLE *new_table, - uchar *new_ptr, uint32 length, - uchar *new_null_ptr, uint new_null_bit); - Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item); -}; - - -/** - Abstract class for: - - TIME(1..6) - - TIME(0..6) - MySQL56 version -*/ -class Field_time_with_dec :public Field_time { -protected: - uint dec; -public: - Field_time_with_dec(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, - enum utype unireg_check_arg, const char *field_name_arg, - uint dec_arg) - :Field_time(ptr_arg, MIN_TIME_WIDTH + dec_arg + MY_TEST(dec_arg), - null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg), - dec(dec_arg) - { - DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS); - } - uint decimals() const { return dec; } - enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } - longlong val_int(void); - double val_real(void); - void make_field(Send_field *); -}; - - -/** - TIME(1..6) -*/ -class Field_time_hires :public Field_time_with_dec { - longlong zero_point; - void store_TIME(MYSQL_TIME *ltime); -public: - Field_time_hires(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, - enum utype unireg_check_arg, const char *field_name_arg, - uint dec_arg) - :Field_time_with_dec(ptr_arg, null_ptr_arg, - null_bit_arg, unireg_check_arg, field_name_arg, - dec_arg) - { - DBUG_ASSERT(dec); - zero_point= sec_part_shift( - ((TIME_MAX_VALUE_SECONDS+1LL)*TIME_SECOND_PART_FACTOR), dec); - } - int reset(void); - bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); - int cmp(const uchar *,const uchar *); - void sort_string(uchar *buff,uint length); - uint32 pack_length() const; - uint size_of() const { return sizeof(*this); } -}; - - -/** - TIME(0..6) - MySQL56 version -*/ -class Field_timef :public Field_time_with_dec { - void store_TIME(MYSQL_TIME *ltime); - int do_save_field_metadata(uchar *metadata_ptr) - { - *metadata_ptr= decimals(); - return 1; - } -public: - Field_timef(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, - enum utype unireg_check_arg, const char *field_name_arg, - uint dec_arg) - :Field_time_with_dec(ptr_arg, null_ptr_arg, - null_bit_arg, unireg_check_arg, field_name_arg, - dec_arg) - { - DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS); - } - enum_field_types real_type() const { return MYSQL_TYPE_TIME2; } - enum_field_types binlog_type() const { return MYSQL_TYPE_TIME2; } - uint32 pack_length() const - { - return my_time_binary_length(dec); - } - uint row_pack_length() const { return pack_length(); } - uint pack_length_from_metadata(uint field_metadata) - { - DBUG_ENTER("Field_timef::pack_length_from_metadata"); - uint tmp= my_time_binary_length(field_metadata); - DBUG_RETURN(tmp); - } - void sort_string(uchar *to, uint length) - { - DBUG_ASSERT(length == Field_timef::pack_length()); - memcpy(to, ptr, length); - } - int cmp(const uchar *a_ptr, const uchar *b_ptr) - { - return memcmp(a_ptr, b_ptr, pack_length()); - } - int reset(); - bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); - uint size_of() const { return sizeof(*this); } -}; - - -class Field_datetime :public Field_temporal_with_date { - void store_TIME(MYSQL_TIME *ltime); - bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const; -public: - Field_datetime(uchar *ptr_arg, uint length_arg, uchar *null_ptr_arg, - uchar null_bit_arg, enum utype unireg_check_arg, - const char *field_name_arg) - :Field_temporal_with_date(ptr_arg, length_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg) - { - if (unireg_check == TIMESTAMP_UN_FIELD || - unireg_check == TIMESTAMP_DNUN_FIELD) - flags|= ON_UPDATE_NOW_FLAG; - } - enum_field_types type() const { return MYSQL_TYPE_DATETIME;} - enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONGLONG; } - double val_real(void); - longlong val_int(void); - String *val_str(String*,String *); - bool send_binary(Protocol *protocol); - int cmp(const uchar *,const uchar *); - void sort_string(uchar *buff,uint length); - uint32 pack_length() const { return 8; } - void sql_type(String &str) const; - bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) - { return Field_datetime::get_TIME(ltime, ptr, fuzzydate); } - int set_time(); - int evaluate_update_default_function() - { - int res= 0; - if (has_update_default_function()) - res= set_time(); - return res; - } - uchar *pack(uchar* to, const uchar *from, - uint max_length __attribute__((unused))) - { - return pack_int64(to, from); - } - const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, - uint param_data __attribute__((unused))) - { - return unpack_int64(to, from, from_end); - } - Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item) - { - return get_equal_const_item_datetime(thd, ctx, const_item); - } - uint size_of() const { return sizeof(*this); } -}; - - -/** - Abstract class for: - - DATETIME(1..6) - - DATETIME(0..6) - MySQL56 version -*/ -class Field_datetime_with_dec :public Field_datetime { -protected: - uint dec; -public: - Field_datetime_with_dec(uchar *ptr_arg, uchar *null_ptr_arg, - uchar null_bit_arg, enum utype unireg_check_arg, - const char *field_name_arg, uint dec_arg) - :Field_datetime(ptr_arg, MAX_DATETIME_WIDTH + dec_arg + MY_TEST(dec_arg), - null_ptr_arg, null_bit_arg, unireg_check_arg, - field_name_arg), dec(dec_arg) - { - DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS); - } - uint decimals() const { return dec; } - enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } - void make_field(Send_field *field); - bool send_binary(Protocol *protocol); - uchar *pack(uchar *to, const uchar *from, uint max_length) - { return Field::pack(to, from, max_length); } - const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, - uint param_data) - { return Field::unpack(to, from, from_end, param_data); } - void sort_string(uchar *to, uint length) - { - DBUG_ASSERT(length == pack_length()); - memcpy(to, ptr, length); - } - double val_real(void); - longlong val_int(void); - String *val_str(String*,String *); -}; - - -/** - DATETIME(1..6) -*/ -class Field_datetime_hires :public Field_datetime_with_dec { - void store_TIME(MYSQL_TIME *ltime); - bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const; -public: - Field_datetime_hires(uchar *ptr_arg, uchar *null_ptr_arg, - uchar null_bit_arg, enum utype unireg_check_arg, - const char *field_name_arg, uint dec_arg) - :Field_datetime_with_dec(ptr_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, dec_arg) - { - DBUG_ASSERT(dec); - } - int cmp(const uchar *,const uchar *); - uint32 pack_length() const; - bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) - { return Field_datetime_hires::get_TIME(ltime, ptr, fuzzydate); } - uint size_of() const { return sizeof(*this); } -}; - - -/** - DATETIME(0..6) - MySQL56 version -*/ -class Field_datetimef :public Field_datetime_with_dec { - void store_TIME(MYSQL_TIME *ltime); - bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const; - int do_save_field_metadata(uchar *metadata_ptr) - { - *metadata_ptr= decimals(); - return 1; - } -public: - Field_datetimef(uchar *ptr_arg, uchar *null_ptr_arg, - uchar null_bit_arg, enum utype unireg_check_arg, - const char *field_name_arg, uint dec_arg) - :Field_datetime_with_dec(ptr_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, dec_arg) - {} - enum_field_types real_type() const { return MYSQL_TYPE_DATETIME2; } - enum_field_types binlog_type() const { return MYSQL_TYPE_DATETIME2; } - uint32 pack_length() const - { - return my_datetime_binary_length(dec); - } - uint row_pack_length() const { return pack_length(); } - uint pack_length_from_metadata(uint field_metadata) - { - DBUG_ENTER("Field_datetimef::pack_length_from_metadata"); - uint tmp= my_datetime_binary_length(field_metadata); - DBUG_RETURN(tmp); - } - int cmp(const uchar *a_ptr, const uchar *b_ptr) - { - return memcmp(a_ptr, b_ptr, pack_length()); - } - int reset(); - bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) - { return Field_datetimef::get_TIME(ltime, ptr, fuzzydate); } - uint size_of() const { return sizeof(*this); } -}; - - -static inline Field_timestamp * -new_Field_timestamp(MEM_ROOT *root,uchar *ptr, uchar *null_ptr, uchar null_bit, - enum Field::utype unireg_check, const char *field_name, - TABLE_SHARE *share, uint dec) -{ - if (dec==0) - return new (root) - Field_timestamp(ptr, MAX_DATETIME_WIDTH, null_ptr, - null_bit, unireg_check, field_name, share); - if (dec >= FLOATING_POINT_DECIMALS) - dec= MAX_DATETIME_PRECISION; - return new (root) - Field_timestamp_hires(ptr, null_ptr, null_bit, unireg_check, - field_name, share, dec); -} - -static inline Field_time * -new_Field_time(MEM_ROOT *root, uchar *ptr, uchar *null_ptr, uchar null_bit, - enum Field::utype unireg_check, const char *field_name, - uint dec) -{ - if (dec == 0) - return new (root) - Field_time(ptr, MIN_TIME_WIDTH, null_ptr, null_bit, unireg_check, - field_name); - if (dec >= FLOATING_POINT_DECIMALS) - dec= MAX_DATETIME_PRECISION; - return new (root) - Field_time_hires(ptr, null_ptr, null_bit, unireg_check, field_name, dec); -} - -static inline Field_datetime * -new_Field_datetime(MEM_ROOT *root, uchar *ptr, uchar *null_ptr, uchar null_bit, - enum Field::utype unireg_check, - const char *field_name, uint dec) -{ - if (dec == 0) - return new (root) - Field_datetime(ptr, MAX_DATETIME_WIDTH, null_ptr, null_bit, - unireg_check, field_name); - if (dec >= FLOATING_POINT_DECIMALS) - dec= MAX_DATETIME_PRECISION; - return new (root) - Field_datetime_hires(ptr, null_ptr, null_bit, - unireg_check, field_name, dec); -} - -class Field_string :public Field_longstr { - class Warn_filter_string: public Warn_filter - { - public: - Warn_filter_string(const THD *thd, const Field_string *field); - }; -public: - bool can_alter_field_type; - Field_string(uchar *ptr_arg, uint32 len_arg,uchar *null_ptr_arg, - uchar null_bit_arg, - enum utype unireg_check_arg, const char *field_name_arg, - CHARSET_INFO *cs) - :Field_longstr(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, cs), - can_alter_field_type(1) {}; - Field_string(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, - CHARSET_INFO *cs) - :Field_longstr((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, 0, - NONE, field_name_arg, cs), - can_alter_field_type(1) {}; - - enum_field_types type() const - { - return ((can_alter_field_type && orig_table && - orig_table->s->db_create_options & HA_OPTION_PACK_RECORD && - field_length >= 4) && - orig_table->s->frm_version < FRM_VER_TRUE_VARCHAR ? - MYSQL_TYPE_VAR_STRING : MYSQL_TYPE_STRING); - } - enum ha_base_keytype key_type() const - { return binary() ? HA_KEYTYPE_BINARY : HA_KEYTYPE_TEXT; } - bool zero_pack() const { return 0; } - Copy_func *get_copy_func(const Field *from) const; - int reset(void) - { - charset()->cset->fill(charset(),(char*) ptr, field_length, - (has_charset() ? ' ' : 0)); - return 0; - } - int store(const char *to,uint length,CHARSET_INFO *charset); - int store(longlong nr, bool unsigned_val); - int store(double nr) { return Field_str::store(nr); } /* QQ: To be deleted */ - double val_real(void); - longlong val_int(void); - String *val_str(String*,String *); - my_decimal *val_decimal(my_decimal *); - int cmp(const uchar *,const uchar *); - void sort_string(uchar *buff,uint length); - void sql_type(String &str) const; - virtual uchar *pack(uchar *to, const uchar *from, - uint max_length); - virtual const uchar *unpack(uchar* to, const uchar *from, - const uchar *from_end,uint param_data); - uint pack_length_from_metadata(uint field_metadata) - { - DBUG_PRINT("debug", ("field_metadata: 0x%04x", field_metadata)); - if (field_metadata == 0) - return row_pack_length(); - return (((field_metadata >> 4) & 0x300) ^ 0x300) + (field_metadata & 0x00ff); - } - bool compatible_field_size(uint field_metadata, Relay_log_info *rli, - uint16 mflags, int *order_var); - uint row_pack_length() const { return field_length; } - int pack_cmp(const uchar *a,const uchar *b,uint key_length, - bool insert_or_update); - int pack_cmp(const uchar *b,uint key_length,bool insert_or_update); - uint packed_col_length(const uchar *to, uint length); - uint max_packed_col_length(uint max_length); - uint size_of() const { return sizeof(*this); } - enum_field_types real_type() const { return MYSQL_TYPE_STRING; } - bool has_charset(void) const - { return charset() == &my_charset_bin ? FALSE : TRUE; } - Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type); - virtual uint get_key_image(uchar *buff,uint length, imagetype type); -private: - int do_save_field_metadata(uchar *first_byte); -}; - - -class Field_varstring :public Field_longstr { - uchar *get_data() const - { - return ptr + length_bytes; - } - uint get_length() const - { - return length_bytes == 1 ? (uint) *ptr : uint2korr(ptr); - } -public: - /* - The maximum space available in a Field_varstring, in bytes. See - length_bytes. - */ - static const uint MAX_SIZE; - /* Store number of bytes used to store length (1 or 2) */ - uint32 length_bytes; - Field_varstring(uchar *ptr_arg, - uint32 len_arg, uint length_bytes_arg, - uchar *null_ptr_arg, uchar null_bit_arg, - enum utype unireg_check_arg, const char *field_name_arg, - TABLE_SHARE *share, CHARSET_INFO *cs) - :Field_longstr(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, cs), - length_bytes(length_bytes_arg) - { - share->varchar_fields++; - } - Field_varstring(uint32 len_arg,bool maybe_null_arg, - const char *field_name_arg, - TABLE_SHARE *share, CHARSET_INFO *cs) - :Field_longstr((uchar*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0, - NONE, field_name_arg, cs), - length_bytes(len_arg < 256 ? 1 :2) - { - share->varchar_fields++; - } - - enum_field_types type() const { return MYSQL_TYPE_VARCHAR; } - enum ha_base_keytype key_type() const; - uint row_pack_length() const { return field_length; } - bool zero_pack() const { return 0; } - int reset(void) { bzero(ptr,field_length+length_bytes); return 0; } - uint32 pack_length() const { return (uint32) field_length+length_bytes; } - uint32 key_length() const { return (uint32) field_length; } - uint32 sort_length() const - { - return (uint32) field_length + (field_charset == &my_charset_bin ? - length_bytes : 0); - } - Copy_func *get_copy_func(const Field *from) const; - bool memcpy_field_possible(const Field *from) const - { - return Field_str::memcpy_field_possible(from) && - length_bytes == ((Field_varstring*) from)->length_bytes; - } - int store(const char *to,uint length,CHARSET_INFO *charset); - int store(longlong nr, bool unsigned_val); - int store(double nr) { return Field_str::store(nr); } /* QQ: To be deleted */ - double val_real(void); - longlong val_int(void); - String *val_str(String*,String *); - my_decimal *val_decimal(my_decimal *); - int cmp_max(const uchar *, const uchar *, uint max_length); - int cmp(const uchar *a,const uchar *b) - { - return cmp_max(a, b, ~0U); - } - void sort_string(uchar *buff,uint length); - uint get_key_image(uchar *buff,uint length, imagetype type); - void set_key_image(const uchar *buff,uint length); - void sql_type(String &str) const; - virtual uchar *pack(uchar *to, const uchar *from, uint max_length); - virtual const uchar *unpack(uchar* to, const uchar *from, - const uchar *from_end, uint param_data); - int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0U); - int key_cmp(const uchar *,const uchar*); - int key_cmp(const uchar *str, uint length); - uint packed_col_length(const uchar *to, uint length); - uint max_packed_col_length(uint max_length); - uint32 data_length(); - uint size_of() const { return sizeof(*this); } - enum_field_types real_type() const { return MYSQL_TYPE_VARCHAR; } - bool has_charset(void) const - { return charset() == &my_charset_bin ? FALSE : TRUE; } - Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type); - Field *new_key_field(MEM_ROOT *root, TABLE *new_table, - uchar *new_ptr, uint32 length, - uchar *new_null_ptr, uint new_null_bit); - uint is_equal(Create_field *new_field); - void hash(ulong *nr, ulong *nr2); - uint length_size() { return length_bytes; } -private: - int do_save_field_metadata(uchar *first_byte); -}; - - -class Field_blob :public Field_longstr { -protected: - /** - The number of bytes used to represent the length of the blob. - */ - uint packlength; - - /** - The 'value'-object is a cache fronting the storage engine. - */ - String value; - /** - Cache for blob values when reading a row with a virtual blob - field. This is needed to not destroy the old cached value when - updating the blob with a new value when creating the new row. - */ - String read_value; - - static void do_copy_blob(Copy_field *copy); - static void do_conv_blob(Copy_field *copy); -public: - Field_blob(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, - enum utype unireg_check_arg, const char *field_name_arg, - TABLE_SHARE *share, uint blob_pack_length, CHARSET_INFO *cs); - Field_blob(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, - CHARSET_INFO *cs) - :Field_longstr((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, 0, - NONE, field_name_arg, cs), - packlength(4) - { - flags|= BLOB_FLAG; - } - Field_blob(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, - CHARSET_INFO *cs, bool set_packlength) - :Field_longstr((uchar*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0, - NONE, field_name_arg, cs) - { - flags|= BLOB_FLAG; - packlength= 4; - if (set_packlength) - { - packlength= len_arg <= 255 ? 1 : - len_arg <= 65535 ? 2 : - len_arg <= 16777215 ? 3 : 4; - } - } - Field_blob(uint32 packlength_arg) - :Field_longstr((uchar*) 0, 0, (uchar*) "", 0, NONE, "temp", system_charset_info), - packlength(packlength_arg) {} - /* Note that the default copy constructor is used, in clone() */ - enum_field_types type() const { return MYSQL_TYPE_BLOB;} - enum ha_base_keytype key_type() const - { return binary() ? HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2; } - Copy_func *get_copy_func(const Field *from) const - { - /* - TODO: MDEV-9331 - if (from->type() == MYSQL_TYPE_BIT) - return do_field_int; - */ - if (!(from->flags & BLOB_FLAG) || from->charset() != charset()) - return do_conv_blob; - if (from->pack_length() != Field_blob::pack_length()) - return do_copy_blob; - return get_identical_copy_func(); - } - int store_field(Field *from) - { // Be sure the value is stored - from->val_str(&value); - if (table->copy_blobs || - (!value.is_alloced() && from->is_varchar_and_in_write_set())) - value.copy(); - return store(value.ptr(), value.length(), from->charset()); - } - bool memcpy_field_possible(const Field *from) const - { - return Field_str::memcpy_field_possible(from) && - !table->copy_blobs; - } - int store(const char *to,uint length,CHARSET_INFO *charset); - int store(double nr); - int store(longlong nr, bool unsigned_val); - double val_real(void); - longlong val_int(void); - String *val_str(String*,String *); - my_decimal *val_decimal(my_decimal *); - int cmp_max(const uchar *, const uchar *, uint max_length); - int cmp(const uchar *a,const uchar *b) - { return cmp_max(a, b, ~0U); } - int cmp(const uchar *a, uint32 a_length, const uchar *b, uint32 b_length); - int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0U); - int key_cmp(const uchar *,const uchar*); - int key_cmp(const uchar *str, uint length); - /* Never update the value of min_val for a blob field */ - bool update_min(Field *min_val, bool force_update) { return FALSE; } - /* Never update the value of max_val for a blob field */ - bool update_max(Field *max_val, bool force_update) { return FALSE; } - uint32 key_length() const { return 0; } - void sort_string(uchar *buff,uint length); - uint32 pack_length() const - { return (uint32) (packlength + portable_sizeof_char_ptr); } - - /** - Return the packed length without the pointer size added. - - This is used to determine the size of the actual data in the row - buffer. - - @returns The length of the raw data itself without the pointer. - */ - uint32 pack_length_no_ptr() const - { return (uint32) (packlength); } - uint row_pack_length() const { return pack_length_no_ptr(); } - uint32 sort_length() const; - uint32 value_length() { return get_length(); } - virtual uint32 max_data_length() const - { - return (uint32) (((ulonglong) 1 << (packlength*8)) -1); - } - int reset(void) { bzero(ptr, packlength+sizeof(uchar*)); return 0; } - void reset_fields() { bzero((uchar*) &value,sizeof(value)); bzero((uchar*) &read_value,sizeof(read_value)); } - uint32 get_field_buffer_size(void) { return value.alloced_length(); } - void store_length(uchar *i_ptr, uint i_packlength, uint32 i_number); - inline void store_length(uint32 number) - { - store_length(ptr, packlength, number); - } - inline uint32 get_length(uint row_offset= 0) const - { return get_length(ptr+row_offset, this->packlength); } - uint32 get_length(const uchar *ptr, uint packlength) const; - uint32 get_length(const uchar *ptr_arg) const - { return get_length(ptr_arg, this->packlength); } - inline uchar *get_ptr() const { return get_ptr(0); } - inline uchar *get_ptr(my_ptrdiff_t row_offset) const - { - uchar *s; - memcpy(&s, ptr + packlength + row_offset, sizeof(uchar*)); - return s; - } - inline void set_ptr(uchar *length, uchar *data) - { - memcpy(ptr,length,packlength); - memcpy(ptr+packlength, &data,sizeof(char*)); - } - void set_ptr_offset(my_ptrdiff_t ptr_diff, uint32 length, uchar *data) - { - uchar *ptr_ofs= ADD_TO_PTR(ptr,ptr_diff,uchar*); - store_length(ptr_ofs, packlength, length); - memcpy(ptr_ofs+packlength, &data, sizeof(char*)); - } - inline void set_ptr(uint32 length, uchar *data) - { - set_ptr_offset(0, length, data); - } - int copy_value(Field_blob *from); - uint get_key_image(uchar *buff,uint length, imagetype type); - void set_key_image(const uchar *buff,uint length); - Field *new_key_field(MEM_ROOT *root, TABLE *new_table, - uchar *new_ptr, uint32 length, - uchar *new_null_ptr, uint new_null_bit); - void sql_type(String &str) const; - inline bool copy() - { - uchar *tmp= get_ptr(); - if (value.copy((char*) tmp, get_length(), charset())) - { - Field_blob::reset(); - return 1; - } - tmp=(uchar*) value.ptr(); - memcpy(ptr+packlength, &tmp, sizeof(char*)); - return 0; - } - /* store value for the duration of the current read record */ - inline void swap_value_and_read_value() - { - read_value.swap(value); - } - inline void set_value(uchar *data) - { - /* Set value pointer. Lengths are not important */ - value.reset((char*) data, 1, 1, &my_charset_bin); - } - virtual uchar *pack(uchar *to, const uchar *from, uint max_length); - virtual const uchar *unpack(uchar *to, const uchar *from, - const uchar *from_end, uint param_data); - uint packed_col_length(const uchar *col_ptr, uint length); - uint max_packed_col_length(uint max_length); - void free() - { - value.free(); - read_value.free(); - } - inline void clear_temporary() - { - uchar *tmp= get_ptr(); - if (likely(value.ptr() == (char*) tmp)) - bzero((uchar*) &value, sizeof(value)); - else - { - /* - Currently read_value should never point to tmp, the following code - is mainly here to make things future proof. - */ - if (unlikely(read_value.ptr() == (char*) tmp)) - bzero((uchar*) &read_value, sizeof(read_value)); - } - } - uint size_of() const { return sizeof(*this); } - bool has_charset(void) const - { return charset() == &my_charset_bin ? FALSE : TRUE; } - uint32 max_display_length(); - uint32 char_length() const; - uint is_equal(Create_field *new_field); -private: - int do_save_field_metadata(uchar *first_byte); -}; - - -#ifdef HAVE_SPATIAL -class Field_geom :public Field_blob { -public: - enum geometry_type geom_type; - uint srid; - uint precision; - enum storage_type { GEOM_STORAGE_WKB= 0, GEOM_STORAGE_BINARY= 1}; - enum storage_type storage; - - Field_geom(uchar *ptr_arg, uchar *null_ptr_arg, uint null_bit_arg, - enum utype unireg_check_arg, const char *field_name_arg, - TABLE_SHARE *share, uint blob_pack_length, - enum geometry_type geom_type_arg, uint field_srid) - :Field_blob(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, - field_name_arg, share, blob_pack_length, &my_charset_bin) - { geom_type= geom_type_arg; srid= field_srid; } - Field_geom(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, - TABLE_SHARE *share, enum geometry_type geom_type_arg) - :Field_blob(len_arg, maybe_null_arg, field_name_arg, &my_charset_bin) - { geom_type= geom_type_arg; srid= 0; } - enum ha_base_keytype key_type() const { return HA_KEYTYPE_VARBINARY2; } - enum_field_types type() const { return MYSQL_TYPE_GEOMETRY; } - bool can_optimize_range(const Item_bool_func *cond, - const Item *item, - bool is_eq_func) const; - void sql_type(String &str) const; - uint is_equal(Create_field *new_field); - int store(const char *to, uint length, CHARSET_INFO *charset); - int store(double nr); - int store(longlong nr, bool unsigned_val); - int store_decimal(const my_decimal *); - uint size_of() const { return sizeof(*this); } - /** - Key length is provided only to support hash joins. (compared byte for byte) - Ex: SELECT .. FROM t1,t2 WHERE t1.field_geom1=t2.field_geom2. - - The comparison is not very relevant, as identical geometry might be - represented differently, but we need to support it either way. - */ - uint32 key_length() const { return packlength; } - - /** - Non-nullable GEOMETRY types cannot have defaults, - but the underlying blob must still be reset. - */ - int reset(void) { return Field_blob::reset() || !maybe_null(); } - - geometry_type get_geometry_type() { return geom_type; }; - static geometry_type geometry_type_merge(geometry_type, geometry_type); - uint get_srid() { return srid; } -}; - -uint gis_field_options_image(uchar *buff, List &create_fields); -uint gis_field_options_read(const uchar *buf, uint buf_len, - Field_geom::storage_type *st_type,uint *precision, uint *scale, uint *srid); - -#endif /*HAVE_SPATIAL*/ - - -class Field_enum :public Field_str { - static void do_field_enum(Copy_field *copy_field); -protected: - uint packlength; -public: - TYPELIB *typelib; - Field_enum(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, - uchar null_bit_arg, - enum utype unireg_check_arg, const char *field_name_arg, - uint packlength_arg, - TYPELIB *typelib_arg, - CHARSET_INFO *charset_arg) - :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, charset_arg), - packlength(packlength_arg),typelib(typelib_arg) - { - flags|=ENUM_FLAG; - } - Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type); - enum_field_types type() const { return MYSQL_TYPE_STRING; } - enum Item_result cmp_type () const { return INT_RESULT; } - const Type_handler *cast_to_int_type_handler() const - { - return &type_handler_longlong; - } - enum ha_base_keytype key_type() const; - Copy_func *get_copy_func(const Field *from) const - { - if (eq_def(from)) - return get_identical_copy_func(); - if (real_type() == MYSQL_TYPE_ENUM && - from->real_type() == MYSQL_TYPE_ENUM) - return do_field_enum; - if (from->result_type() == STRING_RESULT) - return do_field_string; - return do_field_int; - } - int store_field(Field *from) - { - if (from->real_type() == MYSQL_TYPE_ENUM && from->val_int() == 0) - { - store_type(0); - return 0; - } - return from->save_in_field(this); - } - int save_in_field(Field *to) - { - if (to->result_type() != STRING_RESULT) - return to->store(val_int(), 0); - return save_in_field_str(to); - } - bool memcpy_field_possible(const Field *from) const { return false; } - int store(const char *to,uint length,CHARSET_INFO *charset); - int store(double nr); - int store(longlong nr, bool unsigned_val); - double val_real(void); - longlong val_int(void); - String *val_str(String*,String *); - int cmp(const uchar *,const uchar *); - void sort_string(uchar *buff,uint length); - uint32 pack_length() const { return (uint32) packlength; } - void store_type(ulonglong value); - void sql_type(String &str) const; - uint size_of() const { return sizeof(*this); } - enum_field_types real_type() const { return MYSQL_TYPE_ENUM; } - uint pack_length_from_metadata(uint field_metadata) - { return (field_metadata & 0x00ff); } - uint row_pack_length() const { return pack_length(); } - virtual bool zero_pack() const { return 0; } - bool optimize_range(uint idx, uint part) { return 0; } - bool eq_def(const Field *field) const; - bool has_charset(void) const { return TRUE; } - /* enum and set are sorted as integers */ - CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; } - uint decimals() const { return 0; } - - virtual uchar *pack(uchar *to, const uchar *from, uint max_length); - virtual const uchar *unpack(uchar *to, const uchar *from, - const uchar *from_end, uint param_data); - - bool can_optimize_keypart_ref(const Item_bool_func *cond, - const Item *item) const; - bool can_optimize_group_min_max(const Item_bool_func *cond, - const Item *const_item) const - { - /* - Can't use GROUP_MIN_MAX optimization for ENUM and SET, - because the values are stored as numbers in index, - while MIN() and MAX() work as strings. - It would return the records with min and max enum numeric indexes. - "Bug#45300 MAX() and ENUM type" should be fixed first. - */ - return false; - } -private: - int do_save_field_metadata(uchar *first_byte); - uint is_equal(Create_field *new_field); -}; - - -class Field_set :public Field_enum { -public: - Field_set(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, - uchar null_bit_arg, - enum utype unireg_check_arg, const char *field_name_arg, - uint32 packlength_arg, - TYPELIB *typelib_arg, CHARSET_INFO *charset_arg) - :Field_enum(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, - packlength_arg, - typelib_arg,charset_arg), - empty_set_string("", 0, charset_arg) - { - flags=(flags & ~ENUM_FLAG) | SET_FLAG; - } - int store_field(Field *from) { return from->save_in_field(this); } - int store(const char *to,uint length,CHARSET_INFO *charset); - int store(double nr) { return Field_set::store((longlong) nr, FALSE); } - int store(longlong nr, bool unsigned_val); - - virtual bool zero_pack() const { return 1; } - String *val_str(String*,String *); - void sql_type(String &str) const; - uint size_of() const { return sizeof(*this); } - enum_field_types real_type() const { return MYSQL_TYPE_SET; } - bool has_charset(void) const { return TRUE; } -private: - const String empty_set_string; -}; - - -/* - Note: - To use Field_bit::cmp_binary() you need to copy the bits stored in - the beginning of the record (the NULL bytes) to each memory you - want to compare (where the arguments point). - - This is the reason: - - Field_bit::cmp_binary() is only implemented in the base class - (Field::cmp_binary()). - - Field::cmp_binary() currenly use pack_length() to calculate how - long the data is. - - pack_length() includes size of the bits stored in the NULL bytes - of the record. -*/ -class Field_bit :public Field { -public: - uchar *bit_ptr; // position in record where 'uneven' bits store - uchar bit_ofs; // offset to 'uneven' high bits - uint bit_len; // number of 'uneven' high bits - uint bytes_in_rec; - Field_bit(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, - uchar null_bit_arg, uchar *bit_ptr_arg, uchar bit_ofs_arg, - enum utype unireg_check_arg, const char *field_name_arg); - enum_field_types type() const { return MYSQL_TYPE_BIT; } - enum ha_base_keytype key_type() const { return HA_KEYTYPE_BIT; } - uint32 key_length() const { return (uint32) (field_length + 7) / 8; } - uint32 max_data_length() const { return (field_length + 7) / 8; } - uint32 max_display_length() { return field_length; } - uint size_of() const { return sizeof(*this); } - Item_result result_type () const { return INT_RESULT; } - int reset(void) { - bzero(ptr, bytes_in_rec); - if (bit_ptr && (bit_len > 0)) // reset odd bits among null bits - clr_rec_bits(bit_ptr, bit_ofs, bit_len); - return 0; - } - Copy_func *get_copy_func(const Field *from) const - { - return do_field_int; - } - int save_in_field(Field *to) { return to->store(val_int(), true); } - bool memcpy_field_possible(const Field *from) const { return false; } - int store(const char *to, uint length, CHARSET_INFO *charset); - int store(double nr); - int store(longlong nr, bool unsigned_val); - int store_decimal(const my_decimal *); - double val_real(void); - longlong val_int(void); - String *val_str(String*, String *); - virtual bool str_needs_quotes() { return TRUE; } - my_decimal *val_decimal(my_decimal *); - bool val_bool() { return val_int() != 0; } - int cmp(const uchar *a, const uchar *b) - { - DBUG_ASSERT(ptr == a || ptr == b); - if (ptr == a) - return Field_bit::key_cmp(b, bytes_in_rec + MY_TEST(bit_len)); - else - return Field_bit::key_cmp(a, bytes_in_rec + MY_TEST(bit_len)) * -1; - } - int cmp_binary_offset(uint row_offset) - { return cmp_offset(row_offset); } - int cmp_max(const uchar *a, const uchar *b, uint max_length); - int key_cmp(const uchar *a, const uchar *b) - { return cmp_binary((uchar *) a, (uchar *) b); } - int key_cmp(const uchar *str, uint length); - int cmp_offset(uint row_offset); - bool update_min(Field *min_val, bool force_update) - { - longlong val= val_int(); - bool update_fl= force_update || val < min_val->val_int(); - if (update_fl) - { - min_val->set_notnull(); - min_val->store(val, FALSE); - } - return update_fl; - } - bool update_max(Field *max_val, bool force_update) - { - longlong val= val_int(); - bool update_fl= force_update || val > max_val->val_int(); - if (update_fl) - { - max_val->set_notnull(); - max_val->store(val, FALSE); - } - return update_fl; - } - void store_field_value(uchar *val, uint len) - { - store(*((longlong *)val), TRUE); - } - double pos_in_interval(Field *min, Field *max) - { - return pos_in_interval_val_real(min, max); - } - void get_image(uchar *buff, uint length, CHARSET_INFO *cs) - { get_key_image(buff, length, itRAW); } - void set_image(const uchar *buff,uint length, CHARSET_INFO *cs) - { Field_bit::store((char *) buff, length, cs); } - uint get_key_image(uchar *buff, uint length, imagetype type); - void set_key_image(const uchar *buff, uint length) - { Field_bit::store((char*) buff, length, &my_charset_bin); } - void sort_string(uchar *buff, uint length) - { get_key_image(buff, length, itRAW); } - uint32 pack_length() const { return (uint32) (field_length + 7) / 8; } - uint32 pack_length_in_rec() const { return bytes_in_rec; } - uint pack_length_from_metadata(uint field_metadata); - uint row_pack_length() const - { return (bytes_in_rec + ((bit_len > 0) ? 1 : 0)); } - bool compatible_field_size(uint metadata, Relay_log_info *rli, - uint16 mflags, int *order_var); - void sql_type(String &str) const; - virtual uchar *pack(uchar *to, const uchar *from, uint max_length); - virtual const uchar *unpack(uchar *to, const uchar *from, - const uchar *from_end, uint param_data); - virtual void set_default(); - - Field *new_key_field(MEM_ROOT *root, TABLE *new_table, - uchar *new_ptr, uint32 length, - uchar *new_null_ptr, uint new_null_bit); - void set_bit_ptr(uchar *bit_ptr_arg, uchar bit_ofs_arg) - { - bit_ptr= bit_ptr_arg; - bit_ofs= bit_ofs_arg; - } - bool eq(Field *field) - { - return (Field::eq(field) && - bit_ptr == ((Field_bit *)field)->bit_ptr && - bit_ofs == ((Field_bit *)field)->bit_ofs); - } - uint is_equal(Create_field *new_field); - void move_field_offset(my_ptrdiff_t ptr_diff) - { - Field::move_field_offset(ptr_diff); - bit_ptr= ADD_TO_PTR(bit_ptr, ptr_diff, uchar*); - } - void hash(ulong *nr, ulong *nr2); - -private: - virtual size_t do_last_null_byte() const; - int do_save_field_metadata(uchar *first_byte); -}; - - -/** - BIT field represented as chars for non-MyISAM tables. - - @todo The inheritance relationship is backwards since Field_bit is - an extended version of Field_bit_as_char and not the other way - around. Hence, we should refactor it to fix the hierarchy order. - */ -class Field_bit_as_char: public Field_bit { -public: - Field_bit_as_char(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, - uchar null_bit_arg, - enum utype unireg_check_arg, const char *field_name_arg); - enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } - uint size_of() const { return sizeof(*this); } - int store(const char *to, uint length, CHARSET_INFO *charset); - int store(double nr) { return Field_bit::store(nr); } - int store(longlong nr, bool unsigned_val) - { return Field_bit::store(nr, unsigned_val); } - void sql_type(String &str) const; -}; - - -extern const LEX_STRING null_lex_str; - - -Field *make_field(TABLE_SHARE *share, MEM_ROOT *mem_root, - uchar *ptr, uint32 field_length, - uchar *null_pos, uchar null_bit, - uint pack_flag, enum_field_types field_type, - CHARSET_INFO *cs, - Field::geometry_type geom_type, uint srid, - Field::utype unireg_check, - TYPELIB *interval, const char *field_name); - -/* - Create field class for CREATE TABLE -*/ -class Column_definition: public Sql_alloc -{ - /** - Create "interval" from "interval_list". - @param mem_root - memory root to create the TYPELIB - instance and its values on - @param reuse_interval_list_values - determines if TYPELIB can reuse strings - from interval_list, or should always - allocate a copy on mem_root, even if - character set conversion is not needed - @retval false on success - @retval true on error (bad values, or EOM) - */ - bool create_interval_from_interval_list(MEM_ROOT *mem_root, - bool reuse_interval_list_values); - - /* - Calculate TYPELIB (set or enum) max and total lengths - - @param cs charset+collation pair of the interval - @param max_length length of the longest item - @param tot_length sum of the item lengths - - After this method call: - - ENUM uses max_length - - SET uses tot_length. - */ - void calculate_interval_lengths(uint32 *max_length, uint32 *tot_length) - { - const char **pos; - uint *len; - *max_length= *tot_length= 0; - for (pos= interval->type_names, len= interval->type_lengths; - *pos ; pos++, len++) - { - size_t length= charset->cset->numchars(charset, *pos, *pos + *len); - *tot_length+= length; - set_if_bigger(*max_length, (uint32)length); - } - } -public: - enum enum_column_versioning - { - VERSIONING_NOT_SET, - WITH_VERSIONING, - WITHOUT_VERSIONING - }; - - const char *field_name; - LEX_STRING comment; // Comment for field - Item *on_update; // ON UPDATE NOW() - enum enum_field_types sql_type; - /* - At various stages in execution this can be length of field in bytes or - max number of characters. - */ - ulonglong length; - /* - The value of `length' as set by parser: is the number of characters - for most of the types, or of bytes for BLOBs or numeric types. - */ - uint32 char_length; - uint decimals, flags, pack_length, key_length; - Field::utype unireg_check; - TYPELIB *interval; // Which interval to use - List interval_list; - CHARSET_INFO *charset; - uint32 srid; - Field::geometry_type geom_type; - engine_option_value *option_list; - - uint pack_flag; - - /* - This is additinal data provided for any computed(virtual) field. - In particular it includes a pointer to the item by which this field - can be computed from other fields. - */ - Virtual_column_info - *vcol_info, // Virtual field - *default_value, // Default value - *check_constraint; // Check constraint - - enum_column_versioning versioning; - - Column_definition(): - comment(null_lex_str), - on_update(NULL), sql_type(MYSQL_TYPE_NULL), length(0), decimals(0), - flags(0), pack_length(0), key_length(0), unireg_check(Field::NONE), - interval(0), charset(&my_charset_bin), - srid(0), geom_type(Field::GEOM_GEOMETRY), - option_list(NULL), - vcol_info(0), default_value(0), check_constraint(0), - versioning(VERSIONING_NOT_SET) - { - interval_list.empty(); - } - - Column_definition(THD *thd, Field *field, Field *orig_field); - void set_attributes(const Lex_field_type_st &type, CHARSET_INFO *cs); - void create_length_to_internal_length(void); - - /** - Prepare a SET/ENUM field. - Create "interval" from "interval_list" if needed, and adjust "length". - @param mem_root - Memory root to allocate TYPELIB and - its values on - @param reuse_interval_list_values - determines if TYPELIB can reuse value - buffers from interval_list, or should - always allocate a copy on mem_root, - even if character set conversion - is not needed - */ - bool prepare_interval_field(MEM_ROOT *mem_root, - bool reuse_interval_list_values); - - void prepare_interval_field_calc_length() - { - uint32 field_length, dummy; - if (sql_type == MYSQL_TYPE_SET) - { - calculate_interval_lengths(&dummy, &field_length); - length= field_length + (interval->count - 1); - } - else /* MYSQL_TYPE_ENUM */ - { - calculate_interval_lengths(&field_length, &dummy); - length= field_length; - } - set_if_smaller(length, MAX_FIELD_WIDTH - 1); - } - - bool prepare_blob_field(THD *thd); - - bool sp_prepare_create_field(THD *thd, MEM_ROOT *mem_root); - - bool prepare_create_field(uint *blob_columns, ulonglong table_flags); - - bool check(THD *thd); - - bool stored_in_db() const { return !vcol_info || vcol_info->stored_in_db; } - - ha_storage_media field_storage_type() const - { - return (ha_storage_media) - ((flags >> FIELD_FLAGS_STORAGE_MEDIA) & 3); - } - - column_format_type column_format() const - { - return (column_format_type) - ((flags >> FIELD_FLAGS_COLUMN_FORMAT) & 3); - } - - bool has_default_function() const - { - return unireg_check != Field::NONE; - } - - Field *make_field(TABLE_SHARE *share, MEM_ROOT *mem_root, - uchar *ptr, uchar *null_pos, uchar null_bit, - const char *field_name_arg) const - { - return ::make_field(share, mem_root, ptr, - (uint32)length, null_pos, null_bit, - pack_flag, sql_type, charset, - geom_type, srid, unireg_check, interval, - field_name_arg); - } - Field *make_field(TABLE_SHARE *share, MEM_ROOT *mem_root, - const char *field_name_arg) - { - return make_field(share, mem_root, (uchar *) 0, (uchar *) "", 0, - field_name_arg); - } - /* Return true if default is an expression that must be saved explicitely */ - bool has_default_expression(); - - bool has_default_now_unireg_check() const - { - return unireg_check == Field::TIMESTAMP_DN_FIELD - || unireg_check == Field::TIMESTAMP_DNUN_FIELD; - } -}; - - -class Create_field :public Column_definition -{ -public: - const char *change; // If done with alter table - const char *after; // Put column after this one - Field *field; // For alter table - TYPELIB *save_interval; // Temporary copy for the above - // Used only for UCS2 intervals - - /** structure with parsed options (for comparing fields in ALTER TABLE) */ - ha_field_option_struct *option_struct; - uint offset; - uint8 interval_id; // For rea_create_table - bool create_if_not_exists; // Used in ALTER TABLE IF NOT EXISTS - - Create_field(): - Column_definition(), change(0), after(0), - field(0), option_struct(NULL), - create_if_not_exists(false) - { } - Create_field(THD *thd, Field *old_field, Field *orig_field): - Column_definition(thd, old_field, orig_field), - change(old_field->field_name), after(0), - field(old_field), option_struct(old_field->option_struct), - create_if_not_exists(false) - { } - /* Used to make a clone of this object for ALTER/CREATE TABLE */ - Create_field *clone(MEM_ROOT *mem_root) const; -}; - - -/* - A class for sending info to the client -*/ - -class Send_field :public Sql_alloc { - public: - const char *db_name; - const char *table_name,*org_table_name; - const char *col_name,*org_col_name; - ulong length; - uint flags, decimals; - enum_field_types type; - Send_field() {} -}; - - -/* - A class for quick copying data to fields -*/ - -class Copy_field :public Sql_alloc { -public: - uchar *from_ptr,*to_ptr; - uchar *from_null_ptr,*to_null_ptr; - bool *null_row; - uint from_bit,to_bit; - /** - Number of bytes in the fields pointed to by 'from_ptr' and - 'to_ptr'. Usually this is the number of bytes that are copied from - 'from_ptr' to 'to_ptr'. - - For variable-length fields (VARCHAR), the first byte(s) describe - the actual length of the text. For VARCHARs with length - < 256 there is 1 length byte - >= 256 there is 2 length bytes - Thus, if from_field is VARCHAR(10), from_length (and in most cases - to_length) is 11. For VARCHAR(1024), the length is 1026. @see - Field_varstring::length_bytes - - Note that for VARCHARs, do_copy() will be do_varstring*() which - only copies the length-bytes (1 or 2) + the actual length of the - text instead of from/to_length bytes. - */ - uint from_length,to_length; - Field *from_field,*to_field; - String tmp; // For items - - Copy_field() {} - ~Copy_field() {} - void set(Field *to,Field *from,bool save); // Field to field - void set(uchar *to,Field *from); // Field to string - void (*do_copy)(Copy_field *); - void (*do_copy2)(Copy_field *); // Used to handle null values -}; - - -uint pack_length_to_packflag(uint type); -enum_field_types get_blob_type_from_length(ulong length); -uint32 calc_pack_length(enum_field_types type,uint32 length); -int set_field_to_null(Field *field); -int set_field_to_null_with_conversions(Field *field, bool no_conversions); -int convert_null_to_field_value_or_error(Field *field); -bool check_expression(Virtual_column_info *vcol, const char *name, - enum_vcol_info_type type); - -/* - The following are for the interface with the .frm file -*/ - -#define FIELDFLAG_DECIMAL 1U -#define FIELDFLAG_BINARY 1U // Shares same flag -#define FIELDFLAG_NUMBER 2U -#define FIELDFLAG_ZEROFILL 4U -#define FIELDFLAG_PACK 120U // Bits used for packing -#define FIELDFLAG_INTERVAL 256U // mangled with decimals! -#define FIELDFLAG_BITFIELD 512U // mangled with decimals! -#define FIELDFLAG_BLOB 1024U // mangled with decimals! -#define FIELDFLAG_GEOM 2048U // mangled with decimals! - -#define FIELDFLAG_TREAT_BIT_AS_CHAR 4096U /* use Field_bit_as_char */ -#define FIELDFLAG_LONG_DECIMAL 8192U -#define FIELDFLAG_WITHOUT_SYSTEM_VERSIONING 8192U -#define FIELDFLAG_NO_DEFAULT 16384U /* sql */ -#define FIELDFLAG_MAYBE_NULL 32768U // sql -#define FIELDFLAG_HEX_ESCAPE 0x10000U -#define FIELDFLAG_PACK_SHIFT 3 -#define FIELDFLAG_DEC_SHIFT 8 -#define FIELDFLAG_MAX_DEC 63U - -#define MTYP_TYPENR(type) (type & 127U) /* Remove bits from type */ - -#define f_is_dec(x) ((x) & FIELDFLAG_DECIMAL) -#define f_is_num(x) ((x) & FIELDFLAG_NUMBER) -#define f_is_zerofill(x) ((x) & FIELDFLAG_ZEROFILL) -#define f_is_packed(x) ((x) & FIELDFLAG_PACK) -#define f_packtype(x) (((x) >> FIELDFLAG_PACK_SHIFT) & 15) -#define f_decimals(x) ((uint8) (((x) >> FIELDFLAG_DEC_SHIFT) & FIELDFLAG_MAX_DEC)) -#define f_is_alpha(x) (!f_is_num(x)) -#define f_is_binary(x) ((x) & FIELDFLAG_BINARY) // 4.0- compatibility -#define f_is_enum(x) (((x) & (FIELDFLAG_INTERVAL | FIELDFLAG_NUMBER)) == FIELDFLAG_INTERVAL) -#define f_is_bitfield(x) (((x) & (FIELDFLAG_BITFIELD | FIELDFLAG_NUMBER)) == FIELDFLAG_BITFIELD) -#define f_is_blob(x) (((x) & (FIELDFLAG_BLOB | FIELDFLAG_NUMBER)) == FIELDFLAG_BLOB) -#define f_is_geom(x) (((x) & (FIELDFLAG_GEOM | FIELDFLAG_NUMBER)) == FIELDFLAG_GEOM) -#define f_settype(x) (((uint) (x)) << FIELDFLAG_PACK_SHIFT) -#define f_maybe_null(x) ((x) & FIELDFLAG_MAYBE_NULL) -#define f_no_default(x) ((x) & FIELDFLAG_NO_DEFAULT) -#define f_bit_as_char(x) ((x) & FIELDFLAG_TREAT_BIT_AS_CHAR) -#define f_is_hex_escape(x) ((x) & FIELDFLAG_HEX_ESCAPE) -#define f_without_system_versioning(x) ((x) & FIELDFLAG_WITHOUT_SYSTEM_VERSIONING) -#define f_hidden(x) ((x) & FIELDFLAG_HIDDEN) - -#endif /* FIELD_INCLUDED */ -- cgit v1.2.1 From 448374a228aee3cd867d89f1a1eae9884f5bf434 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Thu, 15 Jun 2017 16:02:32 +0300 Subject: SQL, IB: (0.10) VTMD tracking [closes #124] IB: Fixes in logic when to do versioned or usual row updates. Now it is able to do unversioned updates for versioned tables just by disabling `TABLE_SHARE::versioned` flag. SQL: DDL tracking for: * RENAME TABLE, ALTER TABLE .. RENAME TO; * DROP TABLE; * data-modifying operations (f.ex. ALTER TABLE .. ADD/DROP COLUMN). --- include/m_string.h | 1 + libmysqld/CMakeLists.txt | 2 + mysql-test/suite/versioning/r/ddl.result | 22 +- mysql-test/suite/versioning/r/vtmd.result | 271 ++++++++++++++++ mysql-test/suite/versioning/t/ddl.test | 17 +- mysql-test/suite/versioning/t/vtmd.opt | 1 + mysql-test/suite/versioning/t/vtmd.test | 161 ++++++++++ scripts/mysql_system_tables.sql | 7 +- sql/CMakeLists.txt | 1 + sql/handler.h | 6 + sql/share/errmsg-utf8.txt | 3 + sql/sql_alter.h | 16 + sql/sql_error.h | 2 +- sql/sql_lex.cc | 13 + sql/sql_lex.h | 12 + sql/sql_rename.cc | 22 +- sql/sql_table.cc | 115 +++++-- sql/table.cc | 33 +- sql/table.h | 2 + sql/unireg.cc | 12 + sql/unireg.h | 1 + sql/vers_utils.h | 165 ++++++++++ sql/vtmd.cc | 495 ++++++++++++++++++++++++++++++ sql/vtmd.h | 175 +++++++++++ storage/innobase/handler/ha_innodb.cc | 30 +- storage/innobase/row/row0mysql.cc | 4 +- 26 files changed, 1537 insertions(+), 52 deletions(-) create mode 100644 mysql-test/suite/versioning/r/vtmd.result create mode 100644 mysql-test/suite/versioning/t/vtmd.opt create mode 100644 mysql-test/suite/versioning/t/vtmd.test create mode 100644 sql/vers_utils.h create mode 100644 sql/vtmd.cc create mode 100644 sql/vtmd.h diff --git a/include/m_string.h b/include/m_string.h index 708c2562e0f..767bc828daa 100644 --- a/include/m_string.h +++ b/include/m_string.h @@ -211,6 +211,7 @@ extern ulonglong strtoull(const char *str, char **ptr, int base); #define STRING_WITH_LEN(X) (X), ((size_t) (sizeof(X) - 1)) #define USTRING_WITH_LEN(X) ((uchar*) X), ((size_t) (sizeof(X) - 1)) #define C_STRING_WITH_LEN(X) ((char *) (X)), ((size_t) (sizeof(X) - 1)) +#define LEX_STRING_WITH_LEN(X) (X).str, (X).length struct st_mysql_const_lex_string { diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt index 6dabc5e0192..54a26639026 100644 --- a/libmysqld/CMakeLists.txt +++ b/libmysqld/CMakeLists.txt @@ -117,6 +117,8 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc ../sql/ha_sequence.cc ../sql/ha_sequence.h ../sql/temporary_tables.cc ../sql/session_tracker.cc + ../sql/item_vers.cc + ../sql/vtmd.cc ${GEN_SOURCES} ${MYSYS_LIBWRAP_SOURCE} ) diff --git a/mysql-test/suite/versioning/r/ddl.result b/mysql-test/suite/versioning/r/ddl.result index f5d7b024e14..5accb5e63cf 100644 --- a/mysql-test/suite/versioning/r/ddl.result +++ b/mysql-test/suite/versioning/r/ddl.result @@ -82,7 +82,7 @@ create procedure drop_last_historical(table_name_arg varchar(255)) begin call concat_exec2('drop table ', get_historical_table_name(table_name_arg)); end~~ -set versioning_ddl_survival = 1; +set versioning_ddl_survival= on; create or replace table t (a int) with system versioning; insert into t values (1); update t set a=2 where a=1; @@ -106,6 +106,10 @@ call concat_exec3('select @tm=sys_trx_end from ', get_historical_table_name('t') @tm=sys_trx_end 1 call drop_last_historical('t'); +set versioning_ddl_survival= off; +drop table t_vtmd; +drop table t; +set versioning_ddl_survival= on; create or replace table t (a int) with system versioning; insert into t values (1); update t set a=2 where a=1; @@ -129,6 +133,10 @@ call concat_exec3('select @tm=sys_trx_end from ', get_historical_table_name('t') @tm=sys_trx_end 1 call drop_last_historical('t'); +set versioning_ddl_survival= off; +drop table t_vtmd; +drop table t; +set versioning_ddl_survival= on; create or replace table t (a int) with system versioning engine innodb; insert into t values (1); update t set a=2 where a=1; @@ -152,6 +160,10 @@ call concat_exec3('select @tm=sys_trx_end from ', get_historical_table_name('t') @tm=sys_trx_end 1 call drop_last_historical('t'); +set versioning_ddl_survival= off; +drop table t_vtmd; +drop table t; +set versioning_ddl_survival= on; create or replace table t (a int) with system versioning engine innodb; insert into t values (1); update t set a=2 where a=1; @@ -172,6 +184,7 @@ vtmd_template CREATE TABLE `vtmd_template` ( `archive_name` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT 'Name of archive table', `col_renames` blob DEFAULT NULL COMMENT 'Column name mappings from previous lifetime', PRIMARY KEY (`end`), + KEY `archive_name` (`archive_name`), PERIOD FOR SYSTEM_TIME (`start`, `end`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin STATS_PERSISTENT=0 WITH SYSTEM VERSIONING call verify_vtq; @@ -181,6 +194,13 @@ No A B C D 3 1 1 1 1 4 1 1 1 1 5 1 1 1 1 +6 1 1 1 1 +7 1 1 1 1 +8 1 1 1 1 +9 1 1 1 1 +10 1 1 1 1 +11 1 1 1 1 +12 1 1 1 1 drop table t; drop procedure verify_vtq; drop procedure innodb_verify_vtq; diff --git a/mysql-test/suite/versioning/r/vtmd.result b/mysql-test/suite/versioning/r/vtmd.result new file mode 100644 index 00000000000..f2e7956bfa8 --- /dev/null +++ b/mysql-test/suite/versioning/r/vtmd.result @@ -0,0 +1,271 @@ +create or replace procedure drop_archives (in vtmd_name varchar(64)) +begin +declare archive_name varchar(64); +declare cur_done bool default false; +declare cur cursor for +select cur_tmp.archive_name from cur_tmp; +declare continue handler for not found set cur_done = true; +set @tmp= concat(' + create or replace temporary table + cur_tmp as + select vtmd.archive_name from ', vtmd_name, ' as vtmd + for system_time all + where vtmd.archive_name is not null + group by vtmd.archive_name'); +prepare stmt from @tmp; execute stmt; drop prepare stmt; +open cur; +fetch_loop: loop +fetch cur into archive_name; +if cur_done then +leave fetch_loop; +end if; +set @tmp= concat('drop table ', archive_name); +prepare stmt from @tmp; execute stmt; drop prepare stmt; +end loop; +drop table cur_tmp; +end~~ +create or replace procedure check_vtmd (in vtmd_name varchar(64)) +begin +set @tmp= concat(' + create or replace temporary table + tmp_vtmd as + select * from ', vtmd_name, ' as vtmd + for system_time all'); +prepare stmt from @tmp; execute stmt; drop prepare stmt; +set @inf= 0xFFFFFFFFFFFFFFFF + 0; +set @start= null; +select start from tmp_vtmd for system_time all order by start limit 1 into @start; +select @start > 0 and @start < @inf; +select +start = @start as A_start, +(@start:= end) and end = @inf as B_end, +name, +substr(archive_name, 1, instr(archive_name, '_')) as C_archive_name +from tmp_vtmd for system_time all; +drop table tmp_vtmd; +end~~ +set versioning_ddl_survival= off; +create or replace table t0 (x int) with system versioning; +show tables; +Tables_in_test +t0 +set versioning_ddl_survival= on; +create or replace table t0 (x int) with system versioning; +show tables; +Tables_in_test +t0 +t0_vtmd +show create table t0_vtmd; +Table Create Table +t0_vtmd CREATE TABLE `t0_vtmd` ( + `start` bigint(20) unsigned GENERATED ALWAYS AS ROW START COMMENT 'TRX_ID of table lifetime start', + `end` bigint(20) unsigned GENERATED ALWAYS AS ROW END NOT NULL COMMENT 'TRX_ID of table lifetime end', + `name` varchar(64) COLLATE utf8_bin NOT NULL COMMENT 'Table name during period [start, end)', + `archive_name` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT 'Name of archive table', + `col_renames` blob DEFAULT NULL COMMENT 'Column name mappings from previous lifetime', + PRIMARY KEY (`end`), + KEY `archive_name` (`archive_name`), + PERIOD FOR SYSTEM_TIME (`start`, `end`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin STATS_PERSISTENT=0 WITH SYSTEM VERSIONING +call check_vtmd('t0_vtmd'); +@start > 0 and @start < @inf +1 +A_start B_end name C_archive_name +1 1 t0 NULL +set versioning_ddl_survival= off; +drop table t0; +set versioning_ddl_survival= on; +create or replace table t0 (x int) with system versioning; +ERROR HY000: VTMD error: `test.t0_vtmd` exists and not empty! +alter table t0 add column (y int); +call check_vtmd('t0_vtmd'); +@start > 0 and @start < @inf +1 +A_start B_end name C_archive_name +1 0 t0 t0_ +1 1 t0 NULL +call drop_archives('t0_vtmd'); +drop table t0_vtmd; +alter table t0 drop column y; +call check_vtmd('t0_vtmd'); +@start > 0 and @start < @inf +1 +A_start B_end name C_archive_name +1 1 t0 t0_ +call drop_archives('t0_vtmd'); +set versioning_ddl_survival= off; +drop tables t0, t0_vtmd; +set versioning_ddl_survival= on; +set versioning_ddl_survival= off; +create or replace table x0 (x int) with system versioning; +set versioning_ddl_survival= on; +rename table x0 to d0; +show tables; +Tables_in_test +d0 +set versioning_ddl_survival= off; +drop table d0; +set versioning_ddl_survival= on; +create or replace table x0 (x int) with system versioning; +rename table x0 to d0; +show tables; +Tables_in_test +d0 +d0_vtmd +call check_vtmd('d0_vtmd'); +@start > 0 and @start < @inf +1 +A_start B_end name C_archive_name +1 0 x0 NULL +1 1 d0 NULL +set versioning_ddl_survival= off; +drop table d0; +set versioning_ddl_survival= on; +create or replace table x0 (x int) with system versioning; +rename table x0 to d0; +ERROR HY000: VTMD error: `test.d0_vtmd` table already exists! +show tables; +Tables_in_test +d0_vtmd +x0 +x0_vtmd +drop table x0_vtmd; +rename table x0 to d0; +Warnings: +Warning 4088 `test.d0_vtmd` table already exists! +show tables; +Tables_in_test +d0 +d0_vtmd +rename table d0 to duck; +rename table duck to bay; +rename table bay to sheer; +rename table sheer to t0; +call check_vtmd('t0_vtmd'); +@start > 0 and @start < @inf +1 +A_start B_end name C_archive_name +1 0 x0 NULL +1 0 d0 NULL +1 0 duck NULL +1 0 bay NULL +1 0 sheer NULL +1 1 t0 NULL +alter table t0 add column (y int); +call check_vtmd('t0_vtmd'); +@start > 0 and @start < @inf +1 +A_start B_end name C_archive_name +1 0 x0 t0_ +1 0 d0 t0_ +1 0 duck t0_ +1 0 bay t0_ +1 0 sheer t0_ +1 0 t0 t0_ +1 1 t0 NULL +alter table t0 add column (z int); +alter table t0 drop column y; +alter table t0 drop column z; +create database db0; +rename table t0 to db0.t0; +show tables; +Tables_in_test +use db0; +show tables; +Tables_in_db0 +t0 +t0_TIMESTAMP_SUFFIX +t0_TIMESTAMP_SUFFIX +t0_TIMESTAMP_SUFFIX +t0_TIMESTAMP_SUFFIX +t0_vtmd +call test.check_vtmd('db0.t0_vtmd'); +@start > 0 and @start < @inf +1 +A_start B_end name C_archive_name +1 0 x0 t0_ +1 0 d0 t0_ +1 0 duck t0_ +1 0 bay t0_ +1 0 sheer t0_ +1 0 t0 t0_ +1 0 t0 t0_ +1 0 t0 t0_ +1 0 t0 t0_ +1 1 t0 NULL +create database db1; +rename table t0 to db1.other_name; +show tables; +Tables_in_db0 +use db1; +show tables; +Tables_in_db1 +other_name +other_name_vtmd +t0_TIMESTAMP_SUFFIX +t0_TIMESTAMP_SUFFIX +t0_TIMESTAMP_SUFFIX +t0_TIMESTAMP_SUFFIX +call test.check_vtmd('db1.other_name_vtmd'); +@start > 0 and @start < @inf +1 +A_start B_end name C_archive_name +1 0 x0 t0_ +1 0 d0 t0_ +1 0 duck t0_ +1 0 bay t0_ +1 0 sheer t0_ +1 0 t0 t0_ +1 0 t0 t0_ +1 0 t0 t0_ +1 0 t0 t0_ +1 0 t0 NULL +1 1 other_name NULL +alter table other_name rename to t1; +call test.check_vtmd('db1.t1_vtmd'); +@start > 0 and @start < @inf +1 +A_start B_end name C_archive_name +1 0 x0 t0_ +1 0 d0 t0_ +1 0 duck t0_ +1 0 bay t0_ +1 0 sheer t0_ +1 0 t0 t0_ +1 0 t0 t0_ +1 0 t0 t0_ +1 0 t0 t0_ +1 0 t0 NULL +1 0 other_name NULL +1 1 t1 NULL +alter table t1 rename to test.t2, add column (y int); +use test; +show tables; +Tables_in_test +t0_TIMESTAMP_SUFFIX +t0_TIMESTAMP_SUFFIX +t0_TIMESTAMP_SUFFIX +t0_TIMESTAMP_SUFFIX +t2 +t2_vtmd +call check_vtmd('t2_vtmd'); +@start > 0 and @start < @inf +1 +A_start B_end name C_archive_name +1 0 x0 t0_ +1 0 d0 t0_ +1 0 duck t0_ +1 0 bay t0_ +1 0 sheer t0_ +1 0 t0 t0_ +1 0 t0 t0_ +1 0 t0 t0_ +1 0 t0 t0_ +1 0 t0 t1_ +1 0 other_name t1_ +1 0 t1 t1_ +1 1 t2 NULL +drop database db0; +drop database db1; +drop database test; +create database test; diff --git a/mysql-test/suite/versioning/t/ddl.test b/mysql-test/suite/versioning/t/ddl.test index 43c0d588a4f..c169dee15a6 100644 --- a/mysql-test/suite/versioning/t/ddl.test +++ b/mysql-test/suite/versioning/t/ddl.test @@ -30,7 +30,7 @@ end~~ delimiter ;~~ -set versioning_ddl_survival = 1; +set versioning_ddl_survival= on; create or replace table t (a int) with system versioning; insert into t values (1); @@ -49,6 +49,11 @@ call concat_exec3('select @tm=sys_trx_end from ', get_historical_table_name('t') call drop_last_historical('t'); +set versioning_ddl_survival= off; +drop table t_vtmd; +drop table t; +set versioning_ddl_survival= on; + # same for INNODB ALGORITHM=COPY create or replace table t (a int) with system versioning; insert into t values (1); @@ -67,6 +72,11 @@ call concat_exec3('select @tm=sys_trx_end from ', get_historical_table_name('t') call drop_last_historical('t'); +set versioning_ddl_survival= off; +drop table t_vtmd; +drop table t; +set versioning_ddl_survival= on; + # same for INNODB default ALGORITHM create or replace table t (a int) with system versioning engine innodb; insert into t values (1); @@ -85,6 +95,11 @@ call concat_exec3('select @tm=sys_trx_end from ', get_historical_table_name('t') call drop_last_historical('t'); +set versioning_ddl_survival= off; +drop table t_vtmd; +drop table t; +set versioning_ddl_survival= on; + # no DDL for INNODB explicit ALGORITHM=INPLACE create or replace table t (a int) with system versioning engine innodb; insert into t values (1); diff --git a/mysql-test/suite/versioning/t/vtmd.opt b/mysql-test/suite/versioning/t/vtmd.opt new file mode 100644 index 00000000000..3596fc4d3bd --- /dev/null +++ b/mysql-test/suite/versioning/t/vtmd.opt @@ -0,0 +1 @@ +--innodb --default-storage-engine=innodb diff --git a/mysql-test/suite/versioning/t/vtmd.test b/mysql-test/suite/versioning/t/vtmd.test new file mode 100644 index 00000000000..299d31ee036 --- /dev/null +++ b/mysql-test/suite/versioning/t/vtmd.test @@ -0,0 +1,161 @@ +-- source include/have_innodb.inc +delimiter ~~; +create or replace procedure drop_archives (in vtmd_name varchar(64)) +begin + declare archive_name varchar(64); + declare cur_done bool default false; + declare cur cursor for + select cur_tmp.archive_name from cur_tmp; + declare continue handler for not found set cur_done = true; + + set @tmp= concat(' + create or replace temporary table + cur_tmp as + select vtmd.archive_name from ', vtmd_name, ' as vtmd + for system_time all + where vtmd.archive_name is not null + group by vtmd.archive_name'); + prepare stmt from @tmp; execute stmt; drop prepare stmt; + + open cur; + fetch_loop: loop + fetch cur into archive_name; + if cur_done then + leave fetch_loop; + end if; + set @tmp= concat('drop table ', archive_name); + prepare stmt from @tmp; execute stmt; drop prepare stmt; + end loop; + + drop table cur_tmp; +end~~ +delimiter ;~~ + +delimiter ~~; +create or replace procedure check_vtmd (in vtmd_name varchar(64)) +begin + set @tmp= concat(' + create or replace temporary table + tmp_vtmd as + select * from ', vtmd_name, ' as vtmd + for system_time all'); + prepare stmt from @tmp; execute stmt; drop prepare stmt; + + set @inf= 0xFFFFFFFFFFFFFFFF + 0; + set @start= null; + select start from tmp_vtmd for system_time all order by start limit 1 into @start; + select @start > 0 and @start < @inf; + select + start = @start as A_start, + (@start:= end) and end = @inf as B_end, + name, + substr(archive_name, 1, instr(archive_name, '_')) as C_archive_name + from tmp_vtmd for system_time all; + + drop table tmp_vtmd; +end~~ +delimiter ;~~ + +# create +set versioning_ddl_survival= off; +create or replace table t0 (x int) with system versioning; +show tables; +set versioning_ddl_survival= on; +create or replace table t0 (x int) with system versioning; +show tables; +show create table t0_vtmd; +call check_vtmd('t0_vtmd'); + +set versioning_ddl_survival= off; +drop table t0; +set versioning_ddl_survival= on; +--error ER_VERS_VTMD_ERROR +create or replace table t0 (x int) with system versioning; + +# alter +alter table t0 add column (y int); +call check_vtmd('t0_vtmd'); + +call drop_archives('t0_vtmd'); +drop table t0_vtmd; +alter table t0 drop column y; +call check_vtmd('t0_vtmd'); + +call drop_archives('t0_vtmd'); +set versioning_ddl_survival= off; +drop tables t0, t0_vtmd; +set versioning_ddl_survival= on; + +# rename +set versioning_ddl_survival= off; +create or replace table x0 (x int) with system versioning; +set versioning_ddl_survival= on; +rename table x0 to d0; +show tables; + +set versioning_ddl_survival= off; +drop table d0; +set versioning_ddl_survival= on; +create or replace table x0 (x int) with system versioning; +rename table x0 to d0; +show tables; +call check_vtmd('d0_vtmd'); + +set versioning_ddl_survival= off; +drop table d0; +set versioning_ddl_survival= on; +create or replace table x0 (x int) with system versioning; + +--error ER_VERS_VTMD_ERROR +rename table x0 to d0; +show tables; + +drop table x0_vtmd; +rename table x0 to d0; +show tables; + +rename table d0 to duck; +rename table duck to bay; +rename table bay to sheer; +rename table sheer to t0; +call check_vtmd('t0_vtmd'); + +alter table t0 add column (y int); +call check_vtmd('t0_vtmd'); + +# rename to different schema +alter table t0 add column (z int); +alter table t0 drop column y; +alter table t0 drop column z; + +create database db0; +rename table t0 to db0.t0; +show tables; +use db0; +--replace_regex /\d{8}_\d{6}_\d{6}/TIMESTAMP_SUFFIX/ +show tables; +call test.check_vtmd('db0.t0_vtmd'); + +create database db1; +rename table t0 to db1.other_name; +show tables; +use db1; +--replace_regex /\d{8}_\d{6}_\d{6}/TIMESTAMP_SUFFIX/ +show tables; +call test.check_vtmd('db1.other_name_vtmd'); + +# alter rename +alter table other_name rename to t1; +call test.check_vtmd('db1.t1_vtmd'); + +# alter rename and modify to different schema +alter table t1 rename to test.t2, add column (y int); +use test; +--replace_regex /\d{8}_\d{6}_\d{6}/TIMESTAMP_SUFFIX/ +show tables; +call check_vtmd('t2_vtmd'); + +drop database db0; +drop database db1; +drop database test; +create database test; diff --git a/scripts/mysql_system_tables.sql b/scripts/mysql_system_tables.sql index ae115b37b9f..28ca9292602 100644 --- a/scripts/mysql_system_tables.sql +++ b/scripts/mysql_system_tables.sql @@ -23,6 +23,8 @@ set sql_mode=''; set @orig_storage_engine=@@storage_engine; set storage_engine=myisam; +set versioning_ddl_survival=off; + set @have_innodb= (select count(engine) from information_schema.engines where engine='INNODB' and support != 'NO'); SET @innodb_or_myisam=IF(@have_innodb <> 0, 'InnoDB', 'MyISAM'); @@ -129,14 +131,15 @@ SET @create_innodb_index_stats="CREATE TABLE IF NOT EXISTS innodb_index_stats ( PRIMARY KEY (database_name, table_name, index_name, stat_name) ) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_bin STATS_PERSISTENT=0"; -SET @create_vtmd_template="CREATE TABLE IF NOT EXISTS vtmd_template ( +SET @create_vtmd_template="CREATE OR REPLACE TABLE vtmd_template ( start BIGINT UNSIGNED GENERATED ALWAYS AS ROW START COMMENT 'TRX_ID of table lifetime start', end BIGINT UNSIGNED GENERATED ALWAYS AS ROW END COMMENT 'TRX_ID of table lifetime end', name VARCHAR(64) NOT NULL COMMENT 'Table name during period [start, end)', archive_name VARCHAR(64) NULL COMMENT 'Name of archive table', col_renames BLOB COMMENT 'Column name mappings from previous lifetime', PERIOD FOR SYSTEM_TIME(start, end), - PRIMARY KEY (end) + PRIMARY KEY (end), + INDEX (archive_name) ) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_bin STATS_PERSISTENT=0 WITH SYSTEM VERSIONING"; SET @str=IF(@have_innodb <> 0, @create_innodb_table_stats, "SET @dummy = 0"); diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index ee34891d0c9..bb9e844a120 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -152,6 +152,7 @@ SET (SQL_SOURCE ${GEN_SOURCES} ${GEN_DIGEST_SOURCES} ${MYSYS_LIBWRAP_SOURCE} + vtmd.cc ) IF (CMAKE_SYSTEM_NAME MATCHES "Linux" OR diff --git a/sql/handler.h b/sql/handler.h index c46ee422565..807ae234fef 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -403,6 +403,7 @@ enum enum_alter_inplace_result { #define HA_CREATE_TMP_ALTER 8U #define HA_LEX_CREATE_SEQUENCE 16U #define HA_VERSIONED_TABLE 32U +#define HA_VTMD 64U #define HA_MAX_REC_LENGTH 65535 @@ -1840,6 +1841,11 @@ struct Table_scope_and_contents_source_st { return options & HA_VERSIONED_TABLE; } + + bool vtmd() const + { + return options & HA_VTMD; + } }; diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 13408634738..17bd8a983a7 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7547,5 +7547,8 @@ ER_VERS_WRONG_QUERY WARN_VERS_ALIAS_TOO_LONG eng "Auto generated alias for `%s.%s` is too long; using `%s`." +ER_VERS_VTMD_ERROR + eng "VTMD error: %s" + ER_WRONG_TABLESPACE_NAME 42000 eng "Incorrect tablespace name `%-.192s`" diff --git a/sql/sql_alter.h b/sql/sql_alter.h index 5668a0f52be..a1c2d87440b 100644 --- a/sql/sql_alter.h +++ b/sql/sql_alter.h @@ -126,6 +126,22 @@ public: enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE }; + bool vers_data_modifying() const + { + return flags & ( + ALTER_ADD_COLUMN | + ALTER_DROP_COLUMN | + ALTER_CHANGE_COLUMN | + ALTER_DROP_PARTITION | + ALTER_COALESCE_PARTITION | + ALTER_REORGANIZE_PARTITION | + ALTER_TABLE_REORG | + ALTER_REMOVE_PARTITIONING | + ALTER_EXCHANGE_PARTITION | + ALTER_TRUNCATE_PARTITION | + ALTER_COLUMN_ORDER); + } + /** The different values of the ALGORITHM clause. Describes which algorithm to use when altering the table. diff --git a/sql/sql_error.h b/sql/sql_error.h index bbe97333210..0d8aa48a11a 100644 --- a/sql/sql_error.h +++ b/sql/sql_error.h @@ -1171,7 +1171,7 @@ public: void copy_non_errors_from_wi(THD *thd, const Warning_info *src_wi); -private: +protected: Warning_info *get_warning_info() { return m_wi_stack.front(); } const Warning_info *get_warning_info() const { return m_wi_stack.front(); } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 7c334d7ce67..067b78e3a05 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -7029,6 +7029,19 @@ int set_statement_var_if_exists(THD *thd, const char *var_name, } +Query_tables_backup::Query_tables_backup(THD* _thd) : + thd(_thd) +{ + thd->lex->reset_n_backup_query_tables_list(&backup); +} + + +Query_tables_backup::~Query_tables_backup() +{ + thd->lex->restore_backup_query_tables_list(&backup); +} + + bool LEX::sp_add_cfetch(THD *thd, const LEX_STRING &name) { uint offset; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 66f943e9f17..5f6232c2c50 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1914,6 +1914,18 @@ private: }; +class Query_tables_backup +{ + THD *thd; + Query_tables_list backup; + +public: + Query_tables_backup(THD *_thd); + ~Query_tables_backup(); + const Query_tables_list& get() const { return backup; } +}; + + /* st_parsing_options contains the flags for constructions that are allowed in the current statement. diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index 1588644f0e1..9b80ef78c63 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -30,6 +30,7 @@ #include "sql_base.h" // tdc_remove_table, lock_table_names, #include "sql_handler.h" // mysql_ha_rm_tables #include "sql_statistics.h" +#include "vtmd.h" static TABLE_LIST *rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error); @@ -298,12 +299,23 @@ do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db, char *new_table_name, LEX_STRING new_db_name= { (char*)new_db, strlen(new_db)}; (void) rename_table_in_stat_tables(thd, &db_name, &table_name, &new_db_name, &new_table); - if ((rc= Table_triggers_list::change_table_name(thd, ren_table->db, - old_alias, - ren_table->table_name, - new_db, - new_alias))) + VTMD_rename vtmd(*ren_table); + if (thd->variables.vers_ddl_survival) { + rc= vtmd.try_rename(thd, new_db_name, new_table); + if (rc) + goto revert_table_name; + } + rc= Table_triggers_list::change_table_name(thd, ren_table->db, + old_alias, + ren_table->table_name, + new_db, + new_alias); + if (rc) + { + if (thd->variables.vers_ddl_survival) + vtmd.revert_rename(thd, new_db_name); +revert_table_name: /* We've succeeded in renaming table's .frm and in updating corresponding handler data, but have failed to update table's diff --git a/sql/sql_table.cc b/sql/sql_table.cc index efb2969f548..7aeb1854e24 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -56,6 +56,7 @@ #include "sql_audit.h" #include "sql_sequence.h" #include "tztime.h" +#include "vtmd.h" // System Versioning #ifdef __WIN__ @@ -2276,6 +2277,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, char *db=table->db; size_t db_length= table->db_length; handlerton *table_type= 0; + VTMD_drop vtmd(*table); DBUG_PRINT("table", ("table_l: '%s'.'%s' table: 0x%lx s: 0x%lx", table->db, table->table_name, (long) table->table, @@ -2474,8 +2476,24 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, // Remove extension for delete *(end= path + path_length - reg_ext_length)= '\0'; - error= ha_delete_table(thd, table_type, path, db, table->table_name, - !dont_log_query); + if (thd->lex->sql_command == SQLCOM_DROP_TABLE && + thd->variables.vers_ddl_survival && + table_type && table_type != view_pseudo_hton) + { + error= vtmd.check_exists(thd); + if (error) + goto non_tmp_err; + if (!vtmd.exists) + goto drop_table; + error= mysql_rename_table(table_type, table->db, table->table_name, + table->db, vtmd.archive_name(thd), NO_FK_CHECKS); + } + else + { + drop_table: + error= ha_delete_table(thd, table_type, path, db, table->table_name, + !dont_log_query); + } if (!error) { @@ -2510,8 +2528,18 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, else if (frm_delete_error && if_exists) thd->clear_error(); } + non_tmp_err: non_tmp_error|= MY_TEST(error); } + + if (!error && vtmd.exists) + { + error= vtmd.update(thd); + if (error) + mysql_rename_table(table_type, table->db, vtmd.archive_name(), + table->db, table->table_name, NO_FK_CHECKS); + } + if (error) { if (wrong_tables.length()) @@ -5040,6 +5068,7 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, { thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0); result= 1; + goto err; } else { @@ -5048,6 +5077,16 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, } } + if (create_info->versioned() && thd->variables.vers_ddl_survival) + { + VTMD_table vtmd(*create_table); + if (vtmd.update(thd)) + { + result= 1; + goto err; + } + } + err: /* In RBR we don't need to log CREATE TEMPORARY TABLE */ if (thd->is_current_stmt_binlog_format_row() && create_info->tmp_table()) @@ -5155,15 +5194,6 @@ static void make_unique_constraint_name(THD *thd, LEX_STRING *name, ** Alter a table definition ****************************************************************************/ -static void vers_table_name_date(THD *thd, const char *table_name, - char *new_name, size_t new_name_size) -{ - const MYSQL_TIME now= thd->query_start_TIME(); - my_snprintf(new_name, new_name_size, "%s_%04d%02d%02d_%02d%02d%02d_%06d", - table_name, now.year, now.month, now.day, now.hour, now.minute, - now.second, now.second_part); -} - bool operator!=(const MYSQL_TIME &lhs, const MYSQL_TIME &rhs) { return lhs.year != rhs.year || lhs.month != rhs.month || lhs.day != rhs.day || @@ -5466,6 +5496,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, /* Replace type of source table with one specified in the statement. */ local_create_info.options&= ~HA_LEX_CREATE_TMP_TABLE; local_create_info.options|= create_info->tmp_table(); + local_create_info.options|= create_info->options; /* Reset auto-increment counter for the new table. */ local_create_info.auto_increment_value= 0; /* @@ -8529,18 +8560,27 @@ simple_rename_or_index_change(THD *thd, TABLE_LIST *table_list, if (mysql_rename_table(old_db_type, alter_ctx->db, alter_ctx->table_name, alter_ctx->new_db, alter_ctx->new_alias, 0)) error= -1; - else if (Table_triggers_list::change_table_name(thd, - alter_ctx->db, - alter_ctx->alias, - alter_ctx->table_name, - alter_ctx->new_db, - alter_ctx->new_alias)) - { - (void) mysql_rename_table(old_db_type, - alter_ctx->new_db, alter_ctx->new_alias, - alter_ctx->db, alter_ctx->table_name, - NO_FK_CHECKS); - error= -1; + else + { + VTMD_rename vtmd(*table_list); + if (thd->variables.vers_ddl_survival && vtmd.try_rename(thd, new_db_name, new_table_name)) + goto revert_table_name; + else if (Table_triggers_list::change_table_name(thd, + alter_ctx->db, + alter_ctx->alias, + alter_ctx->table_name, + alter_ctx->new_db, + alter_ctx->new_alias)) + { + if (thd->variables.vers_ddl_survival) + vtmd.revert_rename(thd, new_db_name); +revert_table_name: + (void) mysql_rename_table(old_db_type, + alter_ctx->new_db, alter_ctx->new_alias, + alter_ctx->db, alter_ctx->table_name, + NO_FK_CHECKS); + error= -1; + } } } @@ -8672,7 +8712,11 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, &alter_prelocking_strategy); thd->open_options&= ~HA_OPEN_FOR_ALTER; bool versioned= table_list->table && table_list->table->versioned(); - if (versioned && thd->variables.vers_ddl_survival) + bool vers_data_mod= versioned && + thd->variables.vers_ddl_survival && + alter_info->vers_data_modifying(); + + if (vers_data_mod) { table_list->set_lock_type(thd, TL_WRITE); if (thd->mdl_context.upgrade_shared_lock(table_list->table->mdl_ticket, @@ -9003,7 +9047,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, Upgrade from MDL_SHARED_UPGRADABLE to MDL_SHARED_NO_WRITE. Afterwards it's safe to take the table level lock. */ - if ((!(versioned && thd->variables.vers_ddl_survival) && + if ((!vers_data_mod && thd->mdl_context.upgrade_shared_lock( mdl_ticket, MDL_SHARED_NO_WRITE, thd->variables.lock_wait_timeout)) || @@ -9435,8 +9479,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, alter_info->keys_onoff, &alter_ctx)) { - if (table->versioned_by_sql() && new_versioned && - thd->variables.vers_ddl_survival) + if (vers_data_mod && new_versioned && table->versioned_by_sql()) { // Failure of this function may result in corruption of an original table. vers_reset_alter_copy(thd, table); @@ -9538,8 +9581,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, anything goes wrong while renaming the new table. */ char backup_name[FN_LEN]; - if (versioned && thd->variables.vers_ddl_survival) - vers_table_name_date(thd, alter_ctx.table_name, backup_name, + if (vers_data_mod) + VTMD_table::archive_name(thd, alter_ctx.table_name, backup_name, sizeof(backup_name)); else my_snprintf(backup_name, sizeof(backup_name), "%s2-%lx-%lx", @@ -9572,6 +9615,17 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, goto err_with_mdl; } + if (vers_data_mod && new_versioned) + { + DBUG_ASSERT(alter_info && table_list); + VTMD_rename vtmd(*table_list); + bool rc= alter_info->flags & Alter_info::ALTER_RENAME ? + vtmd.try_rename(thd, alter_ctx.new_db, alter_ctx.new_alias, backup_name) : + vtmd.update(thd, backup_name); + if (rc) + goto err_after_rename; + } + // Check if we renamed the table and if so update trigger files. if (alter_ctx.is_table_renamed()) { @@ -9582,6 +9636,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, alter_ctx.new_db, alter_ctx.new_alias)) { +err_after_rename: // Rename succeeded, delete the new table. (void) quick_rm_table(thd, new_db_type, alter_ctx.new_db, alter_ctx.new_alias, 0); @@ -9596,7 +9651,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, } // ALTER TABLE succeeded, delete the backup of the old table. - if (!(versioned && new_versioned && thd->variables.vers_ddl_survival) && + if (!(vers_data_mod && new_versioned) && quick_rm_table(thd, old_db_type, alter_ctx.db, backup_name, FN_IS_TMP)) { /* diff --git a/sql/table.cc b/sql/table.cc index c4f3a05f5c5..b2a511d89f4 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1201,6 +1201,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, uint ext_key_parts= 0; plugin_ref se_plugin= 0; const uchar *system_period= 0; + bool vtmd_used= false; + share->vtmd= false; const uchar *extra2_field_flags= 0; size_t extra2_field_flags_length= 0; @@ -1239,7 +1241,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, if (*extra2 != '/') // old frm had '/' there { const uchar *e2end= extra2 + len; - while (extra2 + 3 < e2end) + while (extra2 + 3 <= e2end) { uchar type= *extra2++; size_t length= *extra2++; @@ -1308,6 +1310,14 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, extra2_field_flags= extra2; extra2_field_flags_length= length; break; + case EXTRA2_VTMD: + if (vtmd_used) + goto err; + share->vtmd= *extra2; + if (share->vtmd) + share->table_category= TABLE_CATEGORY_LOG; + vtmd_used= true; + break; default: /* abort frm parsing if it's an unknown but important extra2 value */ if (type >= EXTRA2_ENGINE_IMPORTANT) @@ -7642,6 +7652,27 @@ void TABLE::vers_update_fields() DBUG_VOID_RETURN; } + +bool TABLE_LIST::vers_vtmd_name(String& out) const +{ + static const char *vtmd_suffix= "_vtmd"; + static const size_t vtmd_suffix_len= strlen(vtmd_suffix); + if (table_name_length > NAME_CHAR_LEN - vtmd_suffix_len) + { + my_printf_error(ER_VERS_VTMD_ERROR, "Table name is longer than %d characters", MYF(0), int(NAME_CHAR_LEN - vtmd_suffix_len)); + return true; + } + out.set(table_name, table_name_length, table_alias_charset); + if (out.append(vtmd_suffix, vtmd_suffix_len + 1)) + { + my_message(ER_VERS_VTMD_ERROR, "Failed allocate VTMD name", MYF(0)); + return true; + } + out.length(out.length() - 1); + return false; +} + + /** Reset markers that fields are being updated */ diff --git a/sql/table.h b/sql/table.h index 32ad43b0ae9..ae04c58c407 100644 --- a/sql/table.h +++ b/sql/table.h @@ -751,6 +751,7 @@ struct TABLE_SHARE */ bool versioned; + bool vtmd; uint16 row_start_field; uint16 row_end_field; uint32 hist_part_id; @@ -2354,6 +2355,7 @@ struct TABLE_LIST /* System Versioning */ vers_select_conds_t vers_conditions; + bool vers_vtmd_name(String &out) const; /** @brief diff --git a/sql/unireg.cc b/sql/unireg.cc index 9b4ee324aa3..cffc98d2e35 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -268,6 +268,11 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table, extra2_size+= 1 + 1 + 2 * sizeof(uint16); } + if (create_info->vtmd()) + { + extra2_size+= 1 + 1 + 1; + } + bool has_extra2_field_flags_= has_extra2_field_flags(create_fields); if (has_extra2_field_flags_) { @@ -340,6 +345,13 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table, pos+= sizeof(uint16); } + if (create_info->vtmd()) + { + *pos++= EXTRA2_VTMD; + *pos++= 1; + *pos++= 1; + } + if (has_extra2_field_flags_) { *pos++= EXTRA2_FIELD_FLAGS; diff --git a/sql/unireg.h b/sql/unireg.h index a47114054e1..bf6f0b0209c 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -174,6 +174,7 @@ enum extra2_frm_value_type { EXTRA2_GIS=2, EXTRA2_PERIOD_FOR_SYSTEM_TIME=4, EXTRA2_FIELD_FLAGS=8, + EXTRA2_VTMD=16, #define EXTRA2_ENGINE_IMPORTANT 128 diff --git a/sql/vers_utils.h b/sql/vers_utils.h new file mode 100644 index 00000000000..ee08fcbb2bc --- /dev/null +++ b/sql/vers_utils.h @@ -0,0 +1,165 @@ +#ifndef VERS_UTILS_INCLUDED +#define VERS_UTILS_INCLUDED + +#include "table.h" +#include "sql_class.h" + +class MDL_auto_lock +{ + THD *thd; + TABLE_LIST &table; + bool error; + +public: + MDL_auto_lock(THD *_thd, TABLE_LIST &_table) : + thd(_thd), table(_table) + { + DBUG_ASSERT(thd); + table.mdl_request.init(MDL_key::TABLE, table.db, table.table_name, MDL_EXCLUSIVE, MDL_EXPLICIT); + error= thd->mdl_context.acquire_lock(&table.mdl_request, thd->variables.lock_wait_timeout); + } + ~MDL_auto_lock() + { + if (!error) + { + DBUG_ASSERT(table.mdl_request.ticket); + thd->mdl_context.release_lock(table.mdl_request.ticket); + table.mdl_request.ticket= NULL; + } + } + bool acquire_error() const { return error; } +}; + +struct Compare_strncmp +{ + int operator()(const LEX_STRING& a, const LEX_STRING& b) const + { + return strncmp(a.str, b.str, a.length); + } + static CHARSET_INFO* charset() + { + return system_charset_info; + } +}; + +template +struct Compare_my_strcasecmp +{ + int operator()(const LEX_STRING& a, const LEX_STRING& b) const + { + DBUG_ASSERT(a.str[a.length] == 0 && b.str[b.length] == 0); + return my_strcasecmp(CS, a.str, b.str); + } + static CHARSET_INFO* charset() + { + return CS; + } +}; + +typedef Compare_my_strcasecmp Compare_fs; +typedef Compare_my_strcasecmp Compare_t; + +struct LEX_STRING_u : public LEX_STRING +{ + LEX_STRING_u() + { + str= NULL; + LEX_STRING::length= 0; + } + LEX_STRING_u(const char *_str, uint32 _len, CHARSET_INFO *) + { + str= const_cast(_str); + LEX_STRING::length= _len; + } + uint32 length() const + { + return LEX_STRING::length; + } + const char *ptr() const + { + return LEX_STRING::str; + } + const LEX_STRING& lex_string() const + { + return *this; + } +}; + +template +struct XString : public Storage +{ +public: + XString() {} + XString(char *_str, size_t _len) : + Storage(_str, _len, Compare::charset()) + { + } + XString(LEX_STRING& src) : + Storage(src.str, src.length, Compare::charset()) + { + } + XString(char *_str) : + Storage(_str, strlen(_str), Compare::charset()) + { + } + bool operator== (const XString& b) const + { + return Storage::length() == b.length() && 0 == Compare()(this->lex_string(), b.lex_string()); + } + bool operator!= (const XString& b) const + { + return !(*this == b); + } + operator const char* () const + { + return Storage::ptr(); + } +}; + +typedef XString<> LString; +typedef XString LString_fs; + +typedef XString SString; +typedef XString SString_fs; +typedef XString SString_t; + + +#define XSTRING_WITH_LEN(X) (X).ptr(), (X).length() +#define DB_WITH_LEN(X) (X).db, (X).db_length +#define TABLE_NAME_WITH_LEN(X) (X).table_name, (X).table_name_length + + +class Local_da : public Diagnostics_area +{ + THD *thd; + uint sql_error; + Diagnostics_area *saved_da; + +public: + Local_da(THD *_thd, uint _sql_error= 0) : + Diagnostics_area(_thd->query_id, false, true), + thd(_thd), + sql_error(_sql_error), + saved_da(_thd->get_stmt_da()) + { + thd->set_stmt_da(this); + } + ~Local_da() + { + if (saved_da) + finish(); + } + void finish() + { + DBUG_ASSERT(saved_da && thd); + thd->set_stmt_da(saved_da); + if (is_error()) + my_error(sql_error ? sql_error : sql_errno(), MYF(0), message()); + if (warn_count() > error_count()) + saved_da->copy_non_errors_from_wi(thd, get_warning_info()); + saved_da= NULL; + } +}; + + +#endif // VERS_UTILS_INCLUDED diff --git a/sql/vtmd.cc b/sql/vtmd.cc new file mode 100644 index 00000000000..552a3cd7078 --- /dev/null +++ b/sql/vtmd.cc @@ -0,0 +1,495 @@ +#include "vtmd.h" +#include "sql_base.h" +#include "sql_class.h" +#include "sql_handler.h" // mysql_ha_rm_tables() +#include "sql_table.h" +#include "table_cache.h" // tdc_remove_table() +#include "key.h" + +LString VERS_VTMD_TEMPLATE(C_STRING_WITH_LEN("vtmd_template")); + +bool +VTMD_table::create(THD *thd) +{ + Table_specification_st create_info; + TABLE_LIST src_table, table; + create_info.init(DDL_options_st::OPT_LIKE); + create_info.options|= HA_VTMD; + create_info.alias= vtmd_name; + table.init_one_table( + DB_WITH_LEN(about), + XSTRING_WITH_LEN(vtmd_name), + vtmd_name, + TL_READ); + src_table.init_one_table( + LEX_STRING_WITH_LEN(MYSQL_SCHEMA_NAME), + XSTRING_WITH_LEN(VERS_VTMD_TEMPLATE), + VERS_VTMD_TEMPLATE, + TL_READ); + + Query_tables_backup backup(thd); + thd->lex->sql_command= backup.get().sql_command; + thd->lex->add_to_query_tables(&src_table); + + MDL_auto_lock mdl_lock(thd, table); + if (mdl_lock.acquire_error()) + return true; + + Reprepare_observer *reprepare_observer= thd->m_reprepare_observer; + partition_info *work_part_info= thd->work_part_info; + thd->m_reprepare_observer= NULL; + thd->work_part_info= NULL; + bool rc= mysql_create_like_table(thd, &table, &src_table, &create_info); + thd->m_reprepare_observer= reprepare_observer; + thd->work_part_info= work_part_info; + return rc; +} + +bool +VTMD_table::find_record(ulonglong sys_trx_end, bool &found) +{ + int error; + key_buf_t key; + found= false; + + DBUG_ASSERT(vtmd); + + if (key.allocate(vtmd->s->max_unique_length)) + return true; + + DBUG_ASSERT(sys_trx_end); + vtmd->vers_end_field()->set_notnull(); + vtmd->vers_end_field()->store(sys_trx_end, true); + key_copy(key, vtmd->record[0], vtmd->key_info + IDX_TRX_END, 0); + + error= vtmd->file->ha_index_read_idx_map(vtmd->record[1], IDX_TRX_END, + key, + HA_WHOLE_KEY, + HA_READ_KEY_EXACT); + if (error) + { + if (error == HA_ERR_RECORD_DELETED || error == HA_ERR_KEY_NOT_FOUND) + return false; + vtmd->file->print_error(error, MYF(0)); + return true; + } + + restore_record(vtmd, record[1]); + + found= true; + return false; +} + +bool +VTMD_table::update(THD *thd, const char* archive_name) +{ + TABLE_LIST vtmd_tl; + bool result= true; + bool close_log= false; + bool found= false; + bool created= false; + int error; + size_t an_len= 0; + Open_tables_backup open_tables_backup; + ulonglong save_thd_options; + { + Local_da local_da(thd, ER_VERS_VTMD_ERROR); + + save_thd_options= thd->variables.option_bits; + thd->variables.option_bits&= ~OPTION_BIN_LOG; + + if (about.vers_vtmd_name(vtmd_name)) + goto quit; + + while (true) // max 2 iterations + { + vtmd_tl.init_one_table( + DB_WITH_LEN(about), + XSTRING_WITH_LEN(vtmd_name), + vtmd_name, + TL_WRITE_CONCURRENT_INSERT); + + vtmd= open_log_table(thd, &vtmd_tl, &open_tables_backup); + if (vtmd) + break; + + if (!created && local_da.is_error() && local_da.sql_errno() == ER_NO_SUCH_TABLE) + { + local_da.reset_diagnostics_area(); + if (create(thd)) + goto quit; + created= true; + continue; + } + goto quit; + } + close_log= true; + + if (!vtmd->versioned()) + { + my_message(ER_VERS_VTMD_ERROR, "VTMD is not versioned", MYF(0)); + goto quit; + } + + if (!created && find_record(ULONGLONG_MAX, found)) + goto quit; + + if ((error= vtmd->file->extra(HA_EXTRA_MARK_AS_LOG_TABLE))) + { + vtmd->file->print_error(error, MYF(0)); + goto quit; + } + + /* Honor next number columns if present */ + vtmd->next_number_field= vtmd->found_next_number_field; + + if (vtmd->s->fields != FIELD_COUNT) + { + my_printf_error(ER_VERS_VTMD_ERROR, "`%s.%s` unexpected fields count: %d", MYF(0), + vtmd->s->db.str, vtmd->s->table_name.str, vtmd->s->fields); + goto quit; + } + + if (archive_name) + { + an_len= strlen(archive_name); + vtmd->field[FLD_ARCHIVE_NAME]->store(archive_name, an_len, table_alias_charset); + vtmd->field[FLD_ARCHIVE_NAME]->set_notnull(); + } + else + { + vtmd->field[FLD_ARCHIVE_NAME]->set_null(); + } + vtmd->field[FLD_COL_RENAMES]->set_null(); + + if (found) + { + if (thd->lex->sql_command == SQLCOM_CREATE_TABLE) + { + my_printf_error(ER_VERS_VTMD_ERROR, "`%s.%s` exists and not empty!", MYF(0), + vtmd->s->db.str, vtmd->s->table_name.str); + goto quit; + } + vtmd->mark_columns_needed_for_update(); // not needed? + if (archive_name) + { + vtmd->s->versioned= false; + error= vtmd->file->ha_update_row(vtmd->record[1], vtmd->record[0]); + vtmd->s->versioned= true; + + if (!error) + { + if (thd->lex->sql_command == SQLCOM_DROP_TABLE) + { + error= vtmd->file->ha_delete_row(vtmd->record[0]); + } + else + { + DBUG_ASSERT(thd->lex->sql_command == SQLCOM_ALTER_TABLE); + ulonglong sys_trx_end= (ulonglong) vtmd->vers_start_field()->val_int(); + store_record(vtmd, record[1]); + vtmd->field[FLD_NAME]->store(TABLE_NAME_WITH_LEN(about), system_charset_info); + vtmd->field[FLD_NAME]->set_notnull(); + vtmd->field[FLD_ARCHIVE_NAME]->set_null(); + error= vtmd->file->ha_update_row(vtmd->record[1], vtmd->record[0]); + if (error) + goto err; + + DBUG_ASSERT(an_len); + while (true) + { // fill archive_name of last sequential renames + bool found; + if (find_record(sys_trx_end, found)) + goto quit; + if (!found || !vtmd->field[FLD_ARCHIVE_NAME]->is_null()) + break; + + store_record(vtmd, record[1]); + vtmd->field[FLD_ARCHIVE_NAME]->store(archive_name, an_len, table_alias_charset); + vtmd->field[FLD_ARCHIVE_NAME]->set_notnull(); + vtmd->s->versioned= false; + error= vtmd->file->ha_update_row(vtmd->record[1], vtmd->record[0]); + vtmd->s->versioned= true; + if (error) + goto err; + sys_trx_end= (ulonglong) vtmd->vers_start_field()->val_int(); + } // while (true) + } // else (thd->lex->sql_command != SQLCOM_DROP_TABLE) + } // if (!error) + } // if (archive_name) + else + { + vtmd->field[FLD_NAME]->store(TABLE_NAME_WITH_LEN(about), system_charset_info); + vtmd->field[FLD_NAME]->set_notnull(); + error= vtmd->file->ha_update_row(vtmd->record[1], vtmd->record[0]); + } + } // if (found) + else + { + vtmd->field[FLD_NAME]->store(TABLE_NAME_WITH_LEN(about), system_charset_info); + vtmd->field[FLD_NAME]->set_notnull(); + vtmd->mark_columns_needed_for_insert(); // not needed? + error= vtmd->file->ha_write_row(vtmd->record[0]); + } + + if (error) + { +err: + vtmd->file->print_error(error, MYF(0)); + goto quit; + } + + result= false; + } + +quit: + if (close_log) + close_log_table(thd, &open_tables_backup); + + thd->variables.option_bits= save_thd_options; + return result; +} + + +bool +VTMD_rename::move_archives(THD *thd, LString &new_db) +{ + TABLE_LIST vtmd_tl; + vtmd_tl.init_one_table( + DB_WITH_LEN(about), + XSTRING_WITH_LEN(vtmd_name), + vtmd_name, + TL_READ); + int error; + bool rc= false; + SString_fs archive; + bool end_keyread= false; + bool index_end= false; + Open_tables_backup open_tables_backup; + key_buf_t key; + + vtmd= open_log_table(thd, &vtmd_tl, &open_tables_backup); + if (!vtmd) + return true; + + if (key.allocate(vtmd->key_info[IDX_ARCHIVE_NAME].key_length)) + { + close_log_table(thd, &open_tables_backup); + return true; + } + + if ((error= vtmd->file->ha_start_keyread(IDX_ARCHIVE_NAME))) + goto err; + end_keyread= true; + + if ((error= vtmd->file->ha_index_init(IDX_ARCHIVE_NAME, true))) + goto err; + index_end= true; + + error= vtmd->file->ha_index_first(vtmd->record[0]); + while (!error) + { + if (!vtmd->field[FLD_ARCHIVE_NAME]->is_null()) + { + vtmd->field[FLD_ARCHIVE_NAME]->val_str(&archive); + key_copy(key, + vtmd->record[0], + &vtmd->key_info[IDX_ARCHIVE_NAME], + vtmd->key_info[IDX_ARCHIVE_NAME].key_length, + false); + error= vtmd->file->ha_index_read_map( + vtmd->record[0], + key, + vtmd->key_info[IDX_ARCHIVE_NAME].ext_key_part_map, + HA_READ_PREFIX_LAST); + if (!error) + { + if ((rc= move_table(thd, archive, new_db))) + break; + + error= vtmd->file->ha_index_next(vtmd->record[0]); + } + } + else + { + archive.length(0); + error= vtmd->file->ha_index_next(vtmd->record[0]); + } + } + + if (error && error != HA_ERR_END_OF_FILE) + { +err: + vtmd->file->print_error(error, MYF(0)); + rc= true; + } + + if (index_end) + vtmd->file->ha_index_end(); + if (end_keyread) + vtmd->file->ha_end_keyread(); + + close_log_table(thd, &open_tables_backup); + return rc; +} + +bool +VTMD_rename::move_table(THD *thd, SString_fs &table_name, LString &new_db) +{ + handlerton *table_hton= NULL; + if (!ha_table_exists(thd, about.db, table_name, &table_hton) || !table_hton) + { + push_warning_printf( + thd, Sql_condition::WARN_LEVEL_WARN, + ER_VERS_VTMD_ERROR, + "`%s.%s` archive doesn't exist", + about.db, table_name.ptr()); + return false; + } + + if (ha_table_exists(thd, new_db, table_name)) + { + my_printf_error(ER_VERS_VTMD_ERROR, "`%s.%s` archive already exists!", MYF(0), + new_db.ptr(), table_name.ptr()); + return true; + } + + TABLE_LIST tl; + tl.init_one_table( + DB_WITH_LEN(about), + XSTRING_WITH_LEN(table_name), + table_name, + TL_WRITE_ONLY); + tl.mdl_request.set_type(MDL_EXCLUSIVE); + + mysql_ha_rm_tables(thd, &tl); + if (lock_table_names(thd, &tl, 0, thd->variables.lock_wait_timeout, 0)) + return true; + tdc_remove_table(thd, TDC_RT_REMOVE_ALL, about.db, table_name, false); + + bool rc= mysql_rename_table( + table_hton, + about.db, table_name, + new_db, table_name, + NO_FK_CHECKS); + if (!rc) + query_cache_invalidate3(thd, &tl, 0); + + return rc; +} + +bool +VTMD_rename::try_rename(THD *thd, LString new_db, LString new_alias, const char *archive_name) +{ + Local_da local_da(thd, ER_VERS_VTMD_ERROR); + TABLE_LIST new_table; + + if (check_exists(thd)) + return true; + + new_table.init_one_table( + XSTRING_WITH_LEN(new_db), + XSTRING_WITH_LEN(new_alias), + new_alias, TL_READ); + + if (new_table.vers_vtmd_name(vtmd_new_name)) + return true; + + if (ha_table_exists(thd, new_db, vtmd_new_name)) + { + if (exists) + { + my_printf_error(ER_VERS_VTMD_ERROR, "`%s.%s` table already exists!", MYF(0), + new_db.ptr(), vtmd_new_name.ptr()); + return true; + } + push_warning_printf( + thd, Sql_condition::WARN_LEVEL_WARN, + ER_VERS_VTMD_ERROR, + "`%s.%s` table already exists!", + new_db.ptr(), vtmd_new_name.ptr()); + return false; + } + + if (!exists) + return false; + + bool same_db= true; + if (LString_fs(DB_WITH_LEN(about)) != new_db) + { + // Move archives before VTMD so if the operation is interrupted, it could be continued. + if (move_archives(thd, new_db)) + return true; + same_db= false; + } + + TABLE_LIST vtmd_tl; + vtmd_tl.init_one_table( + DB_WITH_LEN(about), + XSTRING_WITH_LEN(vtmd_name), + vtmd_name, + TL_WRITE_ONLY); + vtmd_tl.mdl_request.set_type(MDL_EXCLUSIVE); + + mysql_ha_rm_tables(thd, &vtmd_tl); + if (lock_table_names(thd, &vtmd_tl, 0, thd->variables.lock_wait_timeout, 0)) + return true; + tdc_remove_table(thd, TDC_RT_REMOVE_ALL, about.db, vtmd_name, false); + bool rc= mysql_rename_table(hton, + about.db, vtmd_name, + new_db, vtmd_new_name, + NO_FK_CHECKS); + if (!rc) + { + query_cache_invalidate3(thd, &vtmd_tl, 0); + if (same_db || archive_name || new_alias != LString(TABLE_NAME_WITH_LEN(about))) + { + local_da.finish(); + VTMD_table new_vtmd(new_table); + rc= new_vtmd.update(thd, archive_name); + } + } + return rc; +} + +bool +VTMD_rename::revert_rename(THD *thd, LString new_db) +{ + DBUG_ASSERT(hton); + Local_da local_da(thd, ER_VERS_VTMD_ERROR); + + TABLE_LIST vtmd_tl; + vtmd_tl.init_one_table( + DB_WITH_LEN(about), + XSTRING_WITH_LEN(vtmd_new_name), + vtmd_new_name, + TL_WRITE_ONLY); + vtmd_tl.mdl_request.set_type(MDL_EXCLUSIVE); + mysql_ha_rm_tables(thd, &vtmd_tl); + if (lock_table_names(thd, &vtmd_tl, 0, thd->variables.lock_wait_timeout, 0)) + return true; + tdc_remove_table(thd, TDC_RT_REMOVE_ALL, new_db, vtmd_new_name, false); + + bool rc= mysql_rename_table( + hton, + new_db, vtmd_new_name, + new_db, vtmd_name, + NO_FK_CHECKS); + + if (!rc) + query_cache_invalidate3(thd, &vtmd_tl, 0); + + return rc; +} + +void VTMD_table::archive_name( + THD* thd, + const char* table_name, + char* new_name, + size_t new_name_size) +{ + const MYSQL_TIME now= thd->query_start_TIME(); + my_snprintf(new_name, new_name_size, "%s_%04d%02d%02d_%02d%02d%02d_%06d", + table_name, now.year, now.month, now.day, now.hour, now.minute, + now.second, now.second_part); +} diff --git a/sql/vtmd.h b/sql/vtmd.h new file mode 100644 index 00000000000..94a1a422313 --- /dev/null +++ b/sql/vtmd.h @@ -0,0 +1,175 @@ +#ifndef VTMD_INCLUDED +#define VTMD_INCLUDED + +#include "table.h" +#include "unireg.h" +#include +#include "my_sys.h" + +#include "vers_utils.h" + +class key_buf_t +{ + uchar* buf; + + key_buf_t(const key_buf_t&); // disabled + key_buf_t& operator= (const key_buf_t&); // disabled + +public: + key_buf_t() : buf(NULL) + {} + + ~key_buf_t() + { + if (buf) + my_free(buf); + } + + bool allocate(size_t alloc_size) + { + DBUG_ASSERT(!buf); + buf= static_cast(my_malloc(alloc_size, MYF(0))); + if (!buf) + { + my_message(ER_VERS_VTMD_ERROR, "failed to allocate key buffer", MYF(0)); + return true; + } + return false; + } + + operator uchar* () + { + DBUG_ASSERT(buf); + return reinterpret_cast(buf); + } +}; + +class THD; + +class VTMD_table +{ +protected: + TABLE *vtmd; + const TABLE_LIST &about; + SString_t vtmd_name; + +private: + VTMD_table(const VTMD_table&); // prohibit copying references + +public: + enum { + FLD_START= 0, + FLD_END, + FLD_NAME, + FLD_ARCHIVE_NAME, + FLD_COL_RENAMES, + FIELD_COUNT + }; + + enum { + IDX_TRX_END= 0, + IDX_ARCHIVE_NAME + }; + + VTMD_table(TABLE_LIST &_about) : + vtmd(NULL), + about(_about) + {} + + bool create(THD *thd); + bool find_record(ulonglong sys_trx_end, bool &found); + bool update(THD *thd, const char* archive_name= NULL); + + static void archive_name(THD *thd, const char *table_name, char *new_name, size_t new_name_size); + void archive_name(THD *thd, char *new_name, size_t new_name_size) + { + archive_name(thd, about.table_name, new_name, new_name_size); + } + +}; + +class VTMD_exists : public VTMD_table +{ +protected: + handlerton *hton; + +public: + bool exists; + +public: + VTMD_exists(TABLE_LIST &_about) : + VTMD_table(_about), + hton(NULL), + exists(false) + {} + + bool check_exists(THD *thd); // returns error status +}; + +class VTMD_rename : public VTMD_exists +{ + SString_t vtmd_new_name; + +public: + VTMD_rename(TABLE_LIST &_about) : + VTMD_exists(_about) + {} + + bool try_rename(THD *thd, LString new_db, LString new_alias, const char* archive_name= NULL); + bool revert_rename(THD *thd, LString new_db); + +private: + bool move_archives(THD *thd, LString &new_db); + bool move_table(THD *thd, SString_fs &table_name, LString &new_db); +}; + +class VTMD_drop : public VTMD_exists +{ + char archive_name_[NAME_CHAR_LEN]; + +public: + VTMD_drop(TABLE_LIST &_about) : + VTMD_exists(_about) + { + *archive_name_= 0; + } + + const char* archive_name(THD *thd) + { + VTMD_table::archive_name(thd, archive_name_, sizeof(archive_name_)); + return archive_name_; + } + + const char* archive_name() const + { + DBUG_ASSERT(*archive_name_); + return archive_name_; + } + + bool update(THD *thd) + { + DBUG_ASSERT(*archive_name_); + return VTMD_exists::update(thd, archive_name_); + } +}; + + +inline +bool +VTMD_exists::check_exists(THD *thd) +{ + if (about.vers_vtmd_name(vtmd_name)) + return true; + + exists= ha_table_exists(thd, about.db, vtmd_name, &hton); + + if (exists && !hton) + { + my_printf_error(ER_VERS_VTMD_ERROR, "`%s.%s` handlerton empty!", MYF(0), + about.db, vtmd_name.ptr()); + return true; + } + return false; +} + +#endif // VTMD_INCLUDED diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index bf21abe765c..5e3a3621185 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -8717,11 +8717,11 @@ no_commit: innobase_srv_conc_enter_innodb(m_prebuilt); - vers_set_fields = table->versioned() && ( - !is_innopart() && - sql_command != SQLCOM_CREATE_TABLE) ? - ROW_INS_VERSIONED : - ROW_INS_NORMAL; + vers_set_fields = (table->versioned() && !is_innopart() && + (sql_command != SQLCOM_CREATE_TABLE || table->s->vtmd)) + ? + ROW_INS_VERSIONED : + ROW_INS_NORMAL; /* Step-5: Execute insert graph that will result in actual insert. */ error = row_insert_for_mysql((byte*) record, m_prebuilt, vers_set_fields); @@ -9500,7 +9500,8 @@ ha_innobase::update_row( upd_t* uvect = row_get_prebuilt_update_vector(m_prebuilt); ib_uint64_t autoinc; - bool vers_set_fields; + bool vers_set_fields = false; + bool vers_ins_row = false; /* Build an update vector from the modified fields in the rows (uses m_upd_buf of the handle) */ @@ -9526,12 +9527,23 @@ ha_innobase::update_row( innobase_srv_conc_enter_innodb(m_prebuilt); - vers_set_fields = m_prebuilt->upd_node->versioned && !is_innopart(); + if (!table->versioned()) + m_prebuilt->upd_node->versioned = false; + + if (m_prebuilt->upd_node->versioned && !is_innopart()) { + vers_set_fields = true; + if (thd_sql_command(m_user_thd) == SQLCOM_ALTER_TABLE && !table->s->vtmd) + { + m_prebuilt->upd_node->vers_delete = true; + } else { + m_prebuilt->upd_node->vers_delete = false; + vers_ins_row = true; + } + } error = row_update_for_mysql((byte*) old_row, m_prebuilt, vers_set_fields); - if (error == DB_SUCCESS && vers_set_fields && - thd_sql_command(m_user_thd) != SQLCOM_ALTER_TABLE) { + if (error == DB_SUCCESS && vers_ins_row) { if (trx->id != static_cast(table->vers_start_field()->val_int())) error = row_insert_for_mysql((byte*) old_row, m_prebuilt, ROW_INS_HISTORICAL); } diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 07150dbaaa3..a40f6e96d7c 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -1875,6 +1875,7 @@ row_update_for_mysql_using_upd_graph( upd_cascade_t* new_upd_nodes; upd_cascade_t* processed_cascades; bool got_s_lock = false; + bool vers_delete = prebuilt->upd_node->vers_delete; DBUG_ENTER("row_update_for_mysql_using_upd_graph"); @@ -2004,8 +2005,7 @@ run_again: upd_field_t* ufield; dict_col_t* col; unsigned col_idx; - if (node->is_delete || - thd_sql_command(trx->mysql_thd) == SQLCOM_ALTER_TABLE) { + if (node->is_delete || vers_delete) { ufield = &uvect->fields[0]; uvect->n_fields = 0; node->is_delete = false; -- cgit v1.2.1 From ac5eb9771e4c07dc0442a44d863da6dafdf127e0 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Sat, 17 Jun 2017 17:59:22 +0300 Subject: SQL: Versioned SHOW CREATE TABLE [closes #125] --- mysql-test/suite/versioning/r/ddl.result | 1 + mysql-test/suite/versioning/r/vtmd_show.result | 231 +++++++++++++++++++++++++ mysql-test/suite/versioning/t/ddl.test | 1 + mysql-test/suite/versioning/t/vtmd_show.opt | 1 + mysql-test/suite/versioning/t/vtmd_show.test | 92 ++++++++++ sql/sql_show.cc | 33 +++- sql/sql_yacc.yy | 12 +- sql/table.h | 3 +- sql/vtmd.cc | 79 +++++++++ sql/vtmd.h | 1 + 10 files changed, 449 insertions(+), 5 deletions(-) create mode 100644 mysql-test/suite/versioning/r/vtmd_show.result create mode 100644 mysql-test/suite/versioning/t/vtmd_show.opt create mode 100644 mysql-test/suite/versioning/t/vtmd_show.test diff --git a/mysql-test/suite/versioning/r/ddl.result b/mysql-test/suite/versioning/r/ddl.result index 5accb5e63cf..36998f7bc98 100644 --- a/mysql-test/suite/versioning/r/ddl.result +++ b/mysql-test/suite/versioning/r/ddl.result @@ -202,6 +202,7 @@ No A B C D 11 1 1 1 1 12 1 1 1 1 drop table t; +drop table t_vtmd; drop procedure verify_vtq; drop procedure innodb_verify_vtq; drop function default_engine; diff --git a/mysql-test/suite/versioning/r/vtmd_show.result b/mysql-test/suite/versioning/r/vtmd_show.result new file mode 100644 index 00000000000..01d96f9a427 --- /dev/null +++ b/mysql-test/suite/versioning/r/vtmd_show.result @@ -0,0 +1,231 @@ +create or replace procedure drop_archives (in vtmd_name varchar(64)) +begin +declare archive_name varchar(64); +declare cur_done bool default false; +declare cur cursor for +select cur_tmp.archive_name from cur_tmp; +declare continue handler for not found set cur_done = true; +set @tmp= concat(' + create or replace temporary table + cur_tmp as + select vtmd.archive_name from ', vtmd_name, ' as vtmd + for system_time all + where vtmd.archive_name is not null + group by vtmd.archive_name'); +prepare stmt from @tmp; execute stmt; drop prepare stmt; +open cur; +fetch_loop: loop +fetch cur into archive_name; +if cur_done then +leave fetch_loop; +end if; +set @tmp= concat('drop table ', archive_name); +prepare stmt from @tmp; execute stmt; drop prepare stmt; +end loop; +drop table cur_tmp; +end~~ +create procedure test_01(in engine varchar(64)) +begin +set @tmp = concat('create table t (a int) with system versioning engine ', engine); +prepare stmt from @tmp; execute stmt; drop prepare stmt; +set @tm1 = now(6); +alter table t add column b int; +set @tm2 = now(6); +alter table t add column c int; +show create table t for system_time as of timestamp @tm1; +show create table t for system_time as of timestamp @tm2; +show create table t for system_time as of now; +show create table t for system_time as of timestamp now(6); +show create table t; +set @tm3 = now(6); +rename table t to tt; +show create table tt for system_time as of timestamp @tm3; +set @tm4 = now(6); +alter table tt add column d int; +show create table tt for system_time as of timestamp @tm3; +show create table tt for system_time as of timestamp @tm4; +show create table tt; +drop table tt; +call drop_archives('tt_vtmd'); +drop table tt_vtmd; +end~~ +create table t (a int) with system versioning; +show create table t for system_time as of now; +ERROR 42S02: Table 'test.t_vtmd' doesn't exist +set versioning_ddl_survival=on; +create or replace table t (a int) with system versioning; +show create table t for system_time between timestamp @tm1 and timestamp @tm1; +ERROR HY000: Wrong parameters for `FOR SYSTEM_TIME`: only AS OF allowed here +show create table t for system_time from timestamp @tm1 to timestamp @tm1; +ERROR HY000: Wrong parameters for `FOR SYSTEM_TIME`: only AS OF allowed here +show create table t for system_time before timestamp @tm1; +ERROR HY000: Wrong parameters for `FOR SYSTEM_TIME`: only AS OF allowed here +show create table t for system_time as of timestamp '01-01-1990'; +ERROR HY000: VTMD error: failed to query VTMD table +show create table t for system_time as of timestamp '01-01-2020'; +ERROR HY000: VTMD error: failed to query VTMD table +drop table t; +call drop_archives('t_vtmd'); +drop table t_vtmd; +call test_01('myisam'); +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + `b` int(11) DEFAULT NULL, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +Table Create Table +tt CREATE TABLE `tt` ( + `a` int(11) DEFAULT NULL, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +Table Create Table +tt CREATE TABLE `tt` ( + `a` int(11) DEFAULT NULL, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +Table Create Table +tt CREATE TABLE `tt` ( + `a` int(11) DEFAULT NULL, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +Table Create Table +tt CREATE TABLE `tt` ( + `a` int(11) DEFAULT NULL, + `sys_trx_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `sys_trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL, + `d` int(11) DEFAULT NULL, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +call test_01('innodb'); +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL, + `sys_trx_start` bigint(20) unsigned GENERATED ALWAYS AS ROW START, + `sys_trx_end` bigint(20) unsigned GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL, + `sys_trx_start` bigint(20) unsigned GENERATED ALWAYS AS ROW START, + `sys_trx_end` bigint(20) unsigned GENERATED ALWAYS AS ROW END, + `b` int(11) DEFAULT NULL, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL, + `sys_trx_start` bigint(20) unsigned GENERATED ALWAYS AS ROW START, + `sys_trx_end` bigint(20) unsigned GENERATED ALWAYS AS ROW END, + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL, + `sys_trx_start` bigint(20) unsigned GENERATED ALWAYS AS ROW START, + `sys_trx_end` bigint(20) unsigned GENERATED ALWAYS AS ROW END, + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL, + `sys_trx_start` bigint(20) unsigned GENERATED ALWAYS AS ROW START, + `sys_trx_end` bigint(20) unsigned GENERATED ALWAYS AS ROW END, + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +Table Create Table +tt CREATE TABLE `tt` ( + `a` int(11) DEFAULT NULL, + `sys_trx_start` bigint(20) unsigned GENERATED ALWAYS AS ROW START, + `sys_trx_end` bigint(20) unsigned GENERATED ALWAYS AS ROW END, + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +Table Create Table +tt CREATE TABLE `tt` ( + `a` int(11) DEFAULT NULL, + `sys_trx_start` bigint(20) unsigned GENERATED ALWAYS AS ROW START, + `sys_trx_end` bigint(20) unsigned GENERATED ALWAYS AS ROW END, + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +Table Create Table +tt CREATE TABLE `tt` ( + `a` int(11) DEFAULT NULL, + `sys_trx_start` bigint(20) unsigned GENERATED ALWAYS AS ROW START, + `sys_trx_end` bigint(20) unsigned GENERATED ALWAYS AS ROW END, + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +Table Create Table +tt CREATE TABLE `tt` ( + `a` int(11) DEFAULT NULL, + `sys_trx_start` bigint(20) unsigned GENERATED ALWAYS AS ROW START, + `sys_trx_end` bigint(20) unsigned GENERATED ALWAYS AS ROW END, + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL, + `d` int(11) DEFAULT NULL, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +drop procedure test_01; +drop procedure drop_archives; diff --git a/mysql-test/suite/versioning/t/ddl.test b/mysql-test/suite/versioning/t/ddl.test index c169dee15a6..9ef77e9ca0b 100644 --- a/mysql-test/suite/versioning/t/ddl.test +++ b/mysql-test/suite/versioning/t/ddl.test @@ -118,5 +118,6 @@ show create table mysql.vtmd_template; call verify_vtq; drop table t; +drop table t_vtmd; -- source suite/versioning/common_finish.inc diff --git a/mysql-test/suite/versioning/t/vtmd_show.opt b/mysql-test/suite/versioning/t/vtmd_show.opt new file mode 100644 index 00000000000..627becdbfb5 --- /dev/null +++ b/mysql-test/suite/versioning/t/vtmd_show.opt @@ -0,0 +1 @@ +--innodb diff --git a/mysql-test/suite/versioning/t/vtmd_show.test b/mysql-test/suite/versioning/t/vtmd_show.test new file mode 100644 index 00000000000..7610db179ab --- /dev/null +++ b/mysql-test/suite/versioning/t/vtmd_show.test @@ -0,0 +1,92 @@ +delimiter ~~; +create or replace procedure drop_archives (in vtmd_name varchar(64)) +begin + declare archive_name varchar(64); + declare cur_done bool default false; + declare cur cursor for + select cur_tmp.archive_name from cur_tmp; + declare continue handler for not found set cur_done = true; + + set @tmp= concat(' + create or replace temporary table + cur_tmp as + select vtmd.archive_name from ', vtmd_name, ' as vtmd + for system_time all + where vtmd.archive_name is not null + group by vtmd.archive_name'); + prepare stmt from @tmp; execute stmt; drop prepare stmt; + + open cur; + fetch_loop: loop + fetch cur into archive_name; + if cur_done then + leave fetch_loop; + end if; + set @tmp= concat('drop table ', archive_name); + prepare stmt from @tmp; execute stmt; drop prepare stmt; + end loop; + + drop table cur_tmp; +end~~ +delimiter ;~~ + +delimiter ~~; +create procedure test_01(in engine varchar(64)) +begin + set @tmp = concat('create table t (a int) with system versioning engine ', engine); + prepare stmt from @tmp; execute stmt; drop prepare stmt; + + set @tm1 = now(6); + alter table t add column b int; + + set @tm2 = now(6); + alter table t add column c int; + + show create table t for system_time as of timestamp @tm1; + show create table t for system_time as of timestamp @tm2; + show create table t for system_time as of now; + show create table t for system_time as of timestamp now(6); + show create table t; + + set @tm3 = now(6); + rename table t to tt; + show create table tt for system_time as of timestamp @tm3; + + set @tm4 = now(6); + alter table tt add column d int; + show create table tt for system_time as of timestamp @tm3; + show create table tt for system_time as of timestamp @tm4; + show create table tt; + + drop table tt; + call drop_archives('tt_vtmd'); + drop table tt_vtmd; +end~~ +delimiter ;~~ + +create table t (a int) with system versioning; +--error ER_NO_SUCH_TABLE +show create table t for system_time as of now; + +set versioning_ddl_survival=on; + +create or replace table t (a int) with system versioning; +--error ER_VERS_WRONG_PARAMS +show create table t for system_time between timestamp @tm1 and timestamp @tm1; +--error ER_VERS_WRONG_PARAMS +show create table t for system_time from timestamp @tm1 to timestamp @tm1; +--error ER_VERS_WRONG_PARAMS +show create table t for system_time before timestamp @tm1; +--error ER_VERS_VTMD_ERROR +show create table t for system_time as of timestamp '01-01-1990'; +--error ER_VERS_VTMD_ERROR +show create table t for system_time as of timestamp '01-01-2020'; +drop table t; +call drop_archives('t_vtmd'); +drop table t_vtmd; + +call test_01('myisam'); +call test_01('innodb'); + +drop procedure test_01; +drop procedure drop_archives; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index f6e046a8d34..d36d222fb07 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -62,6 +62,8 @@ #ifdef WITH_PARTITION_STORAGE_ENGINE #include "ha_partition.h" #endif +#include "vtmd.h" +#include "transaction.h" enum enum_i_s_events_fields { @@ -1267,6 +1269,24 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) */ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint(); + TABLE_LIST tl; + bool versioned_query= + table_list->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED; + String archive_name; + if (versioned_query) + { + DBUG_ASSERT(table_list->vers_conditions.type == FOR_SYSTEM_TIME_AS_OF); + VTMD_table vtmd(*table_list); + if (vtmd.find_archive_name(thd, archive_name)) + goto exit; + + tl.init_one_table(table_list->db, table_list->db_length, archive_name.ptr(), + archive_name.length(), archive_name.ptr(), TL_READ); + + tl.alias= table_list->table_name; + tl.vers_force_alias= true; + table_list= &tl; + } if (mysqld_show_create_get_fields(thd, table_list, &field_list, &buffer)) goto exit; @@ -1281,7 +1301,9 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) protocol->store(table_list->view_name.str, system_charset_info); else { - if (table_list->schema_table) + if (versioned_query) + protocol->store(tl.alias, system_charset_info); + else if (table_list->schema_table) protocol->store(table_list->schema_table->table_name, system_charset_info); else @@ -1309,6 +1331,13 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) my_eof(thd); exit: + if (versioned_query) + { + /* If commit fails, we should be able to reset the OK status. */ + thd->get_stmt_da()->set_overwrite_status(true); + trans_commit_stmt(thd); + thd->get_stmt_da()->set_overwrite_status(false); + } close_thread_tables(thd); /* Release any metadata locks taken during SHOW CREATE. */ thd->mdl_context.rollback_to_savepoint(mdl_savepoint); @@ -2026,7 +2055,7 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, alias= table_list->schema_table->table_name; else { - if (lower_case_table_names == 2) + if (lower_case_table_names == 2 || table_list->vers_force_alias) alias= table->alias.c_ptr(); else { diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 8f02a033210..ec09803a46e 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1905,7 +1905,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); parse_vcol_expr vcol_opt_specifier vcol_opt_attribute vcol_opt_attribute_list vcol_attribute opt_serial_attribute opt_serial_attribute_list serial_attribute - explainable_command opt_lock_wait_timeout + explainable_command opt_lock_wait_timeout asrow_attribute END_OF_INPUT %type call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt @@ -13330,13 +13330,21 @@ show_param: Lex->set_command(SQLCOM_SHOW_CREATE_DB, $3); Lex->name= $4; } - | CREATE TABLE_SYM table_ident + | CREATE TABLE_SYM table_ident opt_for_system_time_clause { LEX *lex= Lex; lex->sql_command = SQLCOM_SHOW_CREATE; if (!lex->select_lex.add_table_to_list(thd, $3, NULL,0)) MYSQL_YYABORT; lex->create_info.storage_media= HA_SM_DEFAULT; + + if (lex->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED && + lex->vers_conditions.type != FOR_SYSTEM_TIME_AS_OF) { + my_yyabort_error((ER_VERS_WRONG_PARAMS, MYF(0), "FOR SYSTEM_TIME", + "only AS OF allowed here")); + } + if ($4) + Lex->last_table()->vers_conditions= Lex->vers_conditions; } | CREATE VIEW_SYM table_ident { diff --git a/sql/table.h b/sql/table.h index ae04c58c407..8bcdb001d59 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1890,7 +1890,7 @@ struct vers_select_conds_t { return type != b; } - operator bool() + operator bool() const { return type != FOR_SYSTEM_TIME_UNSPECIFIED; } @@ -2356,6 +2356,7 @@ struct TABLE_LIST /* System Versioning */ vers_select_conds_t vers_conditions; bool vers_vtmd_name(String &out) const; + bool vers_force_alias; /** @brief diff --git a/sql/vtmd.cc b/sql/vtmd.cc index 552a3cd7078..65620bd2cb0 100644 --- a/sql/vtmd.cc +++ b/sql/vtmd.cc @@ -3,6 +3,7 @@ #include "sql_class.h" #include "sql_handler.h" // mysql_ha_rm_tables() #include "sql_table.h" +#include "sql_select.h" #include "table_cache.h" // tdc_remove_table() #include "key.h" @@ -493,3 +494,81 @@ void VTMD_table::archive_name( table_name, now.year, now.month, now.day, now.hour, now.minute, now.second, now.second_part); } + +bool VTMD_table::find_archive_name(THD *thd, String &out) +{ + String vtmd_name; + if (about.vers_vtmd_name(vtmd_name)) + return true; + + READ_RECORD info; + int error= 0; + SQL_SELECT *select= NULL; + COND *conds= NULL; + List dummy; + SELECT_LEX &select_lex= thd->lex->select_lex; + + TABLE_LIST tl; + tl.init_one_table(about.db, about.db_length, vtmd_name.ptr(), + vtmd_name.length(), vtmd_name.ptr(), TL_READ); + + Open_tables_backup open_tables_backup; + if (!(vtmd= open_log_table(thd, &tl, &open_tables_backup))) + { + my_error(ER_VERS_VTMD_ERROR, MYF(0), "failed to open VTMD table"); + return true; + } + + Name_resolution_context &ctx= thd->lex->select_lex.context; + TABLE_LIST *table_list= ctx.table_list; + TABLE_LIST *first_name_resolution_table= ctx.first_name_resolution_table; + table_map map = tl.table->map; + ctx.table_list= &tl; + ctx.first_name_resolution_table= &tl; + tl.table->map= 1; + + tl.vers_conditions= about.vers_conditions; + if ((error= vers_setup_select(thd, &tl, &conds, &select_lex)) || + (error= setup_conds(thd, &tl, dummy, &conds))) + { + my_error(ER_VERS_VTMD_ERROR, MYF(0), + "failed to setup conditions for querying VTMD table"); + goto err; + } + + select= make_select(tl.table, 0, 0, conds, NULL, 0, &error); + if (error) + goto loc_err; + if ((error= + init_read_record(&info, thd, tl.table, select, NULL, 1, 1, false))) + goto loc_err; + + while (!(error= info.read_record(&info)) && !thd->killed && !thd->is_error()) + { + if (select->skip_record(thd) > 0) + { + tl.table->field[FLD_ARCHIVE_NAME]->val_str(&out); + + if (out.length() == 0) + { + // Handle AS OF NOW or just RENAMEd case + out.set(about.table_name, about.table_name_length, + system_charset_info); + } + break; + } + } + +loc_err: + if (error) + my_error(ER_VERS_VTMD_ERROR, MYF(0), "failed to query VTMD table"); + + end_read_record(&info); +err: + delete select; + ctx.table_list= table_list; + ctx.first_name_resolution_table= first_name_resolution_table; + tl.table->map= map; + close_log_table(thd, &open_tables_backup); + return error ? true : false; +} diff --git a/sql/vtmd.h b/sql/vtmd.h index 94a1a422313..8588462f83f 100644 --- a/sql/vtmd.h +++ b/sql/vtmd.h @@ -86,6 +86,7 @@ public: archive_name(thd, about.table_name, new_name, new_name_size); } + bool find_archive_name(THD *thd, String &out); }; class VTMD_exists : public VTMD_table -- cgit v1.2.1 From 2442a81eff012416883d401425e356f0c6e8afdd Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Tue, 20 Jun 2017 11:37:12 +0300 Subject: IB: read lock on partitioned table read [closes #200] Closes #204 --- mysql-test/suite/versioning/r/partition.result | 14 ++++++++++++++ mysql-test/suite/versioning/t/partition.test | 6 ++++++ storage/innobase/handler/ha_innopart.cc | 7 +++++++ 3 files changed, 27 insertions(+) diff --git a/mysql-test/suite/versioning/r/partition.result b/mysql-test/suite/versioning/r/partition.result index 2f203ba68ec..b76f01a340e 100644 --- a/mysql-test/suite/versioning/r/partition.result +++ b/mysql-test/suite/versioning/r/partition.result @@ -230,6 +230,20 @@ partition by system_time limit 1 ( partition p0 versioning, partition p1 versioning, partition pn as of now); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `x` int(11) DEFAULT NULL, + `sys_trx_start` ${SYS_TRX_TYPE} GENERATED ALWAYS AS ROW START, + `sys_trx_end` ${SYS_TRX_TYPE} GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=${INNODB_OR_MYISAM} DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING + PARTITION BY SYSTEM_TIME LIMIT 1 +(PARTITION p0 VERSIONING ENGINE = ${INNODB_OR_MYISAM}, + PARTITION p1 VERSIONING ENGINE = ${INNODB_OR_MYISAM}, + PARTITION pn AS OF NOW ENGINE = ${INNODB_OR_MYISAM}) +alter table t1 drop partition non_existent; +ERROR HY000: Error in list of partitions to DROP insert into t1 values (1), (2); select * from t1 partition (pn); x diff --git a/mysql-test/suite/versioning/t/partition.test b/mysql-test/suite/versioning/t/partition.test index 6dc7f56923b..ca998757515 100644 --- a/mysql-test/suite/versioning/t/partition.test +++ b/mysql-test/suite/versioning/t/partition.test @@ -145,6 +145,12 @@ partition by system_time limit 1 ( partition p1 versioning, partition pn as of now); +--replace_result InnoDB ${INNODB_OR_MYISAM} MyISAM ${INNODB_OR_MYISAM} "bigint(20) unsigned" ${SYS_TRX_TYPE} timestamp(6) ${SYS_TRX_TYPE} +show create table t1; + +--error ER_DROP_PARTITION_NON_EXISTENT +alter table t1 drop partition non_existent; + insert into t1 values (1), (2); select * from t1 partition (pn); delete from t1; diff --git a/storage/innobase/handler/ha_innopart.cc b/storage/innobase/handler/ha_innopart.cc index 38af9e44de9..35c77d1d5ec 100644 --- a/storage/innobase/handler/ha_innopart.cc +++ b/storage/innobase/handler/ha_innopart.cc @@ -3059,7 +3059,14 @@ ha_innopart::part_recs_slow(void *_part_elem) { DBUG_ASSERT(bitmap_is_set(&(m_part_info->read_partitions), part_id)); set_partition(part_id); + bool read_lock_needed = get_lock_type() == F_UNLCK; + if (read_lock_needed) + ha_external_lock(ha_thd(), F_RDLCK); ha_rows n = ha_innobase::records_new(); + if (read_lock_needed) { + ha_external_lock(ha_thd(), F_UNLCK); + ha_commit_one_phase(ha_thd(), false); + } update_partition(part_id); if (n == HA_POS_ERROR) { return HA_POS_ERROR; -- cgit v1.2.1 From 670b7f5fd4a4cdf82493fec56ddc6fa5de80ba90 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Thu, 22 Jun 2017 20:15:03 +0300 Subject: Style: API renames part_recs_slow() -> part_records(); HTON_SUPPORTS_SYS_VERSIONING -> HTON_NATIVE_SYS_VERSIONING. --- sql/ha_partition.h | 2 +- sql/handler.cc | 4 ++-- sql/handler.h | 6 +++--- sql/item_vers.cc | 2 +- sql/partition_info.h | 2 +- storage/innobase/handler/ha_innodb.cc | 2 +- storage/innobase/handler/ha_innopart.cc | 2 +- storage/innobase/handler/ha_innopart.h | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 861ba47b94e..98e0c1baafe 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -1360,7 +1360,7 @@ public: return m_innodb; } - virtual ha_rows part_recs_slow(void *_part_elem) + virtual ha_rows part_records(void *_part_elem) { partition_element *part_elem= reinterpret_cast(_part_elem); DBUG_ASSERT(m_part_info); diff --git a/sql/handler.cc b/sql/handler.cc index f2e74d936fd..8ec9feab7c5 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6674,7 +6674,7 @@ bool Vers_parse_info::check_and_fix_implicit( const char* table_name) { bool integer_fields= - create_info->db_type->flags & HTON_SUPPORTS_SYS_VERSIONING; + create_info->db_type->flags & HTON_NATIVE_SYS_VERSIONING; SELECT_LEX &slex= thd->lex->select_lex; int vers_tables= 0; @@ -6826,7 +6826,7 @@ bool Vers_parse_info::check_and_fix_alter(THD *thd, Alter_info *alter_info, TABLE_SHARE *share) { bool integer_fields= - create_info->db_type->flags & HTON_SUPPORTS_SYS_VERSIONING; + create_info->db_type->flags & HTON_NATIVE_SYS_VERSIONING; const char *table_name= share->table_name.str; if (!need_check() && !share->versioned) diff --git a/sql/handler.h b/sql/handler.h index 807ae234fef..6f65853256c 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1442,7 +1442,7 @@ handlerton *ha_default_tmp_handlerton(THD *thd); */ #define HTON_NO_BINLOG_ROW_OPT (1 << 9) #define HTON_SUPPORTS_EXTENDED_KEYS (1 <<10) //supports extended keys -#define HTON_SUPPORTS_SYS_VERSIONING (1 << 11) //Engine supports System Versioning +#define HTON_NATIVE_SYS_VERSIONING (1 << 11) //Engine supports System Versioning // MySQL compatibility. Unused. #define HTON_SUPPORTS_FOREIGN_KEYS (1 << 0) //Foreign key constraint supported. @@ -4368,8 +4368,8 @@ public: { return -1; /*unsupported */} virtual bool versioned() const - { DBUG_ASSERT(ht); return partition_ht()->flags & HTON_SUPPORTS_SYS_VERSIONING; } - virtual ha_rows part_recs_slow(void *_part_elem) + { DBUG_ASSERT(ht); return partition_ht()->flags & HTON_NATIVE_SYS_VERSIONING; } + virtual ha_rows part_records(void *_part_elem) { DBUG_ASSERT(0); return false; } virtual handler* part_handler(uint32 part_id) { DBUG_ASSERT(0); return NULL; } diff --git a/sql/item_vers.cc b/sql/item_vers.cc index 81cc3808651..eff4c15db6b 100644 --- a/sql/item_vers.cc +++ b/sql/item_vers.cc @@ -71,7 +71,7 @@ VTQ_common::init_hton() hton= plugin_hton(plugin_int_to_ref(innodb_plugin)); DBUG_ASSERT(hton); } - if (hton && !(hton->flags & HTON_SUPPORTS_SYS_VERSIONING)) + if (hton && !(hton->flags & HTON_NATIVE_SYS_VERSIONING)) { my_error(ER_VERS_ENGINE_UNSUPPORTED, MYF(0), Item::name ? Item::name : this->func_name()); hton= NULL; diff --git a/sql/partition_info.h b/sql/partition_info.h index ef20564837c..9dff7a41a4a 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -476,7 +476,7 @@ public: part= vers_hist_part(); } // TODO: cache thread-shared part_recs and increment on INSERT - return table->file->part_recs_slow(part) >= vers_info->limit; + return table->file->part_records(part) >= vers_info->limit; } Vers_field_stats& vers_stat_trx(stat_trx_field fld, uint32 part_element_id) { diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 5e3a3621185..d4b5b89ac30 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -3859,7 +3859,7 @@ innobase_init( innobase_hton->flush_logs = innobase_flush_logs; innobase_hton->show_status = innobase_show_status; innobase_hton->flags = - HTON_SUPPORTS_EXTENDED_KEYS | HTON_SUPPORTS_FOREIGN_KEYS | HTON_SUPPORTS_SYS_VERSIONING; + HTON_SUPPORTS_EXTENDED_KEYS | HTON_SUPPORTS_FOREIGN_KEYS | HTON_NATIVE_SYS_VERSIONING; innobase_hton->release_temporary_latches = innobase_release_temporary_latches; diff --git a/storage/innobase/handler/ha_innopart.cc b/storage/innobase/handler/ha_innopart.cc index 35c77d1d5ec..76f17f995a4 100644 --- a/storage/innobase/handler/ha_innopart.cc +++ b/storage/innobase/handler/ha_innopart.cc @@ -3045,7 +3045,7 @@ ha_innopart::records() } ha_rows -ha_innopart::part_recs_slow(void *_part_elem) +ha_innopart::part_records(void *_part_elem) { partition_element *part_elem= reinterpret_cast(_part_elem); DBUG_ASSERT(m_part_info); diff --git a/storage/innobase/handler/ha_innopart.h b/storage/innobase/handler/ha_innopart.h index ef66420acb1..090543196c4 100644 --- a/storage/innobase/handler/ha_innopart.h +++ b/storage/innobase/handler/ha_innopart.h @@ -1356,7 +1356,7 @@ public: } virtual ha_rows - part_recs_slow(void *_part_elem); + part_records(void *_part_elem); private: -- cgit v1.2.1 From 07ff0e1202fbc521c476080eb2cd9fed544dc959 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Thu, 22 Jun 2017 23:09:34 +0300 Subject: SQL: start_end_t members as LEX_CSTRING --- sql/handler.cc | 59 ++++++++---------------- sql/handler.h | 23 +++++----- sql/sql_table.cc | 8 ++-- sql/sql_yacc.yy | 18 +++----- sql/unireg.cc | 4 +- sql/vers_string.h | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ sql/vers_utils.h | 99 +---------------------------------------- sql/vtmd.cc | 2 +- 8 files changed, 176 insertions(+), 168 deletions(-) create mode 100644 sql/vers_string.h diff --git a/sql/handler.cc b/sql/handler.cc index 8ec9feab7c5..32d5c5fd2db 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6584,13 +6584,12 @@ int del_global_index_stat(THD *thd, TABLE* table, KEY* key_info) bool Vers_parse_info::is_trx_start(const char *name) const { DBUG_ASSERT(name); - return generated_as_row.start && - !strcmp(generated_as_row.start->c_ptr(), name); + return generated_as_row.start && generated_as_row.start == LString_i(name); } bool Vers_parse_info::is_trx_end(const char *name) const { DBUG_ASSERT(name); - return generated_as_row.end && !strcmp(generated_as_row.end->c_ptr(), name); + return generated_as_row.end && generated_as_row.end == LString_i(name); } bool Vers_parse_info::is_trx_start(const Create_field &f) const { @@ -6601,14 +6600,9 @@ bool Vers_parse_info::is_trx_end(const Create_field &f) const return f.flags & VERS_SYS_END_FLAG; } -static bool create_string(MEM_ROOT *mem_root, String **s, const char *value) -{ - *s= new (mem_root) String(value, system_charset_info); - return *s == NULL; -} static bool vers_create_sys_field(THD *thd, const char *field_name, - Alter_info *alter_info, String **s, + Alter_info *alter_info, int flags, bool integer_fields) { @@ -6635,9 +6629,6 @@ static bool vers_create_sys_field(THD *thd, const char *field_name, if (f->check(thd)) return true; - if (create_string(thd->mem_root, s, field_name)) - return true; - alter_info->create_list.push_back(f); return false; } @@ -6652,19 +6643,18 @@ bool Vers_parse_info::fix_implicit(THD *thd, Alter_info *alter_info, alter_info->flags|= Alter_info::ALTER_ADD_COLUMN; - static const char * sys_trx_start= "sys_trx_start"; - static const char * sys_trx_end= "sys_trx_end"; + static const LString sys_trx_start= "sys_trx_start"; + static const LString sys_trx_end= "sys_trx_end"; + + period_for_system_time= start_end_t(sys_trx_start, sys_trx_end); + generated_as_row= period_for_system_time; return vers_create_sys_field(thd, sys_trx_start, alter_info, - &generated_as_row.start, VERS_SYS_START_FLAG, + VERS_SYS_START_FLAG, integer_fields) || vers_create_sys_field(thd, sys_trx_end, alter_info, - &generated_as_row.end, VERS_SYS_END_FLAG, - integer_fields) || - create_string(thd->mem_root, &period_for_system_time.start, - sys_trx_start) || - create_string(thd->mem_root, &period_for_system_time.end, - sys_trx_end); + VERS_SYS_END_FLAG, + integer_fields); } bool Vers_parse_info::check_and_fix_implicit( @@ -6731,7 +6721,7 @@ bool Vers_parse_info::check_and_fix_implicit( return true; } orig_table= f->field->orig_table; - generated_as_row.start= new (thd->mem_root) String(f->field_name, system_charset_info); + generated_as_row.start= f->field_name; period_for_system_time.start= generated_as_row.start; } continue; @@ -6746,7 +6736,7 @@ bool Vers_parse_info::check_and_fix_implicit( goto err_different_tables; } orig_table= f->field->orig_table; - generated_as_row.end= new (thd->mem_root) String(f->field_name, system_charset_info); + generated_as_row.end= f->field_name; period_for_system_time.end= generated_as_row.end; } continue; @@ -6866,11 +6856,8 @@ bool Vers_parse_info::check_and_fix_alter(THD *thd, Alter_info *alter_info, const char *end= share->vers_end_field()->field_name; DBUG_ASSERT(start && end); - if (create_string(thd->mem_root, &generated_as_row.start, start) || - create_string(thd->mem_root, &generated_as_row.end, end) || - create_string(thd->mem_root, &period_for_system_time.start, start) || - create_string(thd->mem_root, &period_for_system_time.end, end)) - return true; + generated_as_row= start_end_t(start, end); + period_for_system_time= generated_as_row; if (alter_info->create_list.elements) { @@ -6935,14 +6922,8 @@ bool Vers_parse_info::fix_create_like(THD *thd, Alter_info *alter_info, return true; } - if (create_string(thd->mem_root, &generated_as_row.start, f_start->field_name) || - create_string(thd->mem_root, &period_for_system_time.start, f_start->field_name) || - create_string(thd->mem_root, &generated_as_row.end, f_end->field_name) || - create_string(thd->mem_root, &period_for_system_time.end, f_end->field_name)) - { - sql_print_error("Failed to allocate memory for Vers_parse_info::fix_create_like()"); - return true; - } + generated_as_row= start_end_t(f_start->field_name, f_end->field_name); + period_for_system_time= generated_as_row; create_info->options|= HA_VERSIONED_TABLE; return false; @@ -6972,16 +6953,14 @@ bool Vers_parse_info::check_with_conditions(const char *table_name) const return true; } - if (my_strcasecmp(system_charset_info, generated_as_row.start->c_ptr(), - period_for_system_time.start->c_ptr())) + if (generated_as_row.start != period_for_system_time.start) { my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, "'PERIOD FOR SYSTEM_TIME' and 'GENERATED AS ROW START' mismatch"); return true; } - if (my_strcasecmp(system_charset_info, generated_as_row.end->c_ptr(), - period_for_system_time.end->c_ptr())) + if (generated_as_row.end != period_for_system_time.end) { my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, "'PERIOD FOR SYSTEM_TIME' and 'GENERATED AS ROW END' mismatch"); diff --git a/sql/handler.h b/sql/handler.h index 6f65853256c..9c2b1bcf209 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -36,6 +36,7 @@ #include "sql_array.h" /* Dynamic_array<> */ #include "mdl.h" #include "vtq.h" +#include "vers_string.h" #include "sql_analyze_stmt.h" // for Exec_time_tracker @@ -1684,17 +1685,19 @@ struct Vers_parse_info struct start_end_t { - start_end_t() : - start(NULL), - end(NULL) {} - String *start; - String *end; + start_end_t() + {} + start_end_t(const char* _start, const char* _end) : + start(_start), + end(_end) {} + LString_i start; + LString_i end; }; start_end_t period_for_system_time; start_end_t generated_as_row; - void set_period_for_system_time(String *start, String *end) + void set_period_for_system_time(LString start, LString end) { period_for_system_time.start = start; period_for_system_time.end = end; @@ -1713,10 +1716,10 @@ private: has_unversioned_fields || declared_with_system_versioning || declared_without_system_versioning || - period_for_system_time.start || - period_for_system_time.end || - generated_as_row.start || - generated_as_row.end; + period_for_system_time.start.str || + period_for_system_time.end.str || + generated_as_row.start.str || + generated_as_row.end.str; } bool check_with_conditions(const char *table_name) const; bool check_generated_type(const char *table_name, Alter_info *alter_info, diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 7aeb1854e24..4c1ab495651 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4326,9 +4326,9 @@ vers_prepare_keys(THD *thd, { DBUG_ASSERT(create_info->versioned()); - const char *row_start_field= create_info->vers_info.generated_as_row.start->c_ptr(); + const char *row_start_field= create_info->vers_info.generated_as_row.start; DBUG_ASSERT(row_start_field); - const char *row_end_field= create_info->vers_info.generated_as_row.end->c_ptr(); + const char *row_end_field= create_info->vers_info.generated_as_row.end; DBUG_ASSERT(row_end_field); List_iterator key_it(alter_info->key_list); @@ -4354,10 +4354,8 @@ vers_prepare_keys(THD *thd, if (key_part) continue; // Key already contains Sys_start or Sys_end - const LEX_STRING &lex_sys_end= - create_info->vers_info.generated_as_row.end->lex_string(); Key_part_spec *key_part_sys_end_col= - new(thd->mem_root) Key_part_spec(lex_sys_end, 0); + new(thd->mem_root) Key_part_spec(create_info->vers_info.generated_as_row.end, 0); key->columns.push_back(key_part_sys_end_col); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index ec09803a46e..73860aadca5 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1622,6 +1622,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); opt_constraint constraint opt_ident sp_decl_ident sp_block_label + period_for_system_time_column_id %type TEXT_STRING @@ -1651,7 +1652,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type text_string hex_or_bin_String opt_gconcat_separator - period_for_system_time_column_id %type int_type real_type @@ -6167,7 +6167,7 @@ period_for_system_time: PERIOD_SYM FOR_SYSTEM_TIME_SYM '(' period_for_system_time_column_id ',' period_for_system_time_column_id ')' { Vers_parse_info &info= Lex->vers_get_info(); - if (!my_strcasecmp(system_charset_info, $4->c_ptr(), $6->c_ptr())) + if (!my_strcasecmp(system_charset_info, $4.str, $6.str)) { my_yyabort_error((ER_VERS_WRONG_PARAMS, MYF(0), Lex->create_last_non_select_table->table_name, @@ -6284,14 +6284,10 @@ field_def: { LEX *lex= Lex; Vers_parse_info &info= lex->vers_get_info(); - String *field_name= new (thd->mem_root) - String((const char*)lex->last_field->field_name, system_charset_info); - if (!field_name) - MYSQL_YYABORT; - + const char *field_name= lex->last_field->field_name; const char *table_name= lex->create_last_non_select_table->table_name; - String **p= NULL; + LString_i *p; const char* err; switch ($4) { @@ -6310,6 +6306,7 @@ field_def: MYSQL_YYABORT; break; } + DBUG_ASSERT(p); if (*p) { my_yyabort_error((ER_VERS_WRONG_PARAMS, MYF(0), table_name, err)); @@ -16237,10 +16234,7 @@ column_list: period_for_system_time_column_id: ident { - String *new_str= new (thd->mem_root) String((const char*) $1.str,$1.length,system_charset_info); - if (new_str == NULL) - MYSQL_YYABORT; - $$= new_str; + $$= $1; } ; diff --git a/sql/unireg.cc b/sql/unireg.cc index cffc98d2e35..7a5aadb1c22 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -101,8 +101,8 @@ vers_get_field(HA_CREATE_INFO *create_info, List &create_fields, b const char *row_field = row_start ? - create_info->vers_info.generated_as_row.start->c_ptr() : - create_info->vers_info.generated_as_row.end->c_ptr(); + create_info->vers_info.generated_as_row.start : + create_info->vers_info.generated_as_row.end; DBUG_ASSERT(row_field); for (unsigned field_no = 0; (sql_field = it++); ++field_no) diff --git a/sql/vers_string.h b/sql/vers_string.h new file mode 100644 index 00000000000..ddd691276db --- /dev/null +++ b/sql/vers_string.h @@ -0,0 +1,131 @@ +#ifndef VERS_STRING_INCLUDED +#define VERS_STRING_INCLUDED + +struct Compare_strncmp +{ + int operator()(const LEX_CSTRING& a, const LEX_CSTRING& b) const + { + return strncmp(a.str, b.str, a.length); + } + static CHARSET_INFO* charset() + { + return system_charset_info; + } +}; + +template +struct Compare_my_strcasecmp +{ + int operator()(const LEX_CSTRING& a, const LEX_CSTRING& b) const + { + DBUG_ASSERT(a.str[a.length] == 0 && b.str[b.length] == 0); + return my_strcasecmp(CS, a.str, b.str); + } + static CHARSET_INFO* charset() + { + return CS; + } +}; + +typedef Compare_my_strcasecmp Compare_fs; +typedef Compare_my_strcasecmp Compare_t; + +template +struct LEX_STRING_u : public Storage +{ + LEX_STRING_u() + { + Storage::str= NULL; + Storage::length= 0; + } + LEX_STRING_u(const char *_str, uint32 _len, CHARSET_INFO *) + { + Storage::str= _str; + Storage::length= _len; + } + uint32 length() const + { + return Storage::length; + } + const char *ptr() const + { + return Storage::str; + } + void set(const char *_str, uint32 _len, CHARSET_INFO *) + { + Storage::str= _str; + Storage::length= _len; + } + const LEX_CSTRING& lex_cstring() const + { + return *this; + } +}; + +template > +struct XString : public Storage +{ +public: + XString() {} + XString(const char *_str, size_t _len) : + Storage(_str, _len, Compare::charset()) + { + } + XString(LEX_STRING& src) : + Storage(src.str, src.length, Compare::charset()) + { + } + XString(const char *_str) : + Storage(_str, strlen(_str), Compare::charset()) + { + } + XString& operator= (const char *_str) + { + DBUG_ASSERT(_str); + Storage::set(_str, strlen(_str), Compare::charset()); + return *this; + } + bool operator== (const XString& b) const + { + return Storage::length() == b.length() && 0 == Compare()(this->lex_cstring(), b.lex_cstring()); + } + bool operator!= (const XString& b) const + { + return !(*this == b); + } + operator const char* () const + { + return Storage::ptr(); + } + operator LEX_CSTRING& () const + { + return this->lex_cstring(); + } + operator LEX_STRING () const + { + LEX_STRING res; + res.str= const_cast(this->ptr()); + res.length= this->length(); + return res; + } + operator bool () const + { + return Storage::ptr() != NULL; + } +}; + +typedef XString<> LString; +typedef XString LString_fs; +typedef XString > LString_i; + +typedef XString SString; +typedef XString SString_fs; +typedef XString SString_t; + + +#define XSTRING_WITH_LEN(X) (X).ptr(), (X).length() +#define DB_WITH_LEN(X) (X).db, (X).db_length +#define TABLE_NAME_WITH_LEN(X) (X).table_name, (X).table_name_length + + +#endif // VERS_STRING_INCLUDED diff --git a/sql/vers_utils.h b/sql/vers_utils.h index ee08fcbb2bc..948139bfa9b 100644 --- a/sql/vers_utils.h +++ b/sql/vers_utils.h @@ -3,6 +3,7 @@ #include "table.h" #include "sql_class.h" +#include "vers_string.h" class MDL_auto_lock { @@ -30,104 +31,6 @@ public: bool acquire_error() const { return error; } }; -struct Compare_strncmp -{ - int operator()(const LEX_STRING& a, const LEX_STRING& b) const - { - return strncmp(a.str, b.str, a.length); - } - static CHARSET_INFO* charset() - { - return system_charset_info; - } -}; - -template -struct Compare_my_strcasecmp -{ - int operator()(const LEX_STRING& a, const LEX_STRING& b) const - { - DBUG_ASSERT(a.str[a.length] == 0 && b.str[b.length] == 0); - return my_strcasecmp(CS, a.str, b.str); - } - static CHARSET_INFO* charset() - { - return CS; - } -}; - -typedef Compare_my_strcasecmp Compare_fs; -typedef Compare_my_strcasecmp Compare_t; - -struct LEX_STRING_u : public LEX_STRING -{ - LEX_STRING_u() - { - str= NULL; - LEX_STRING::length= 0; - } - LEX_STRING_u(const char *_str, uint32 _len, CHARSET_INFO *) - { - str= const_cast(_str); - LEX_STRING::length= _len; - } - uint32 length() const - { - return LEX_STRING::length; - } - const char *ptr() const - { - return LEX_STRING::str; - } - const LEX_STRING& lex_string() const - { - return *this; - } -}; - -template -struct XString : public Storage -{ -public: - XString() {} - XString(char *_str, size_t _len) : - Storage(_str, _len, Compare::charset()) - { - } - XString(LEX_STRING& src) : - Storage(src.str, src.length, Compare::charset()) - { - } - XString(char *_str) : - Storage(_str, strlen(_str), Compare::charset()) - { - } - bool operator== (const XString& b) const - { - return Storage::length() == b.length() && 0 == Compare()(this->lex_string(), b.lex_string()); - } - bool operator!= (const XString& b) const - { - return !(*this == b); - } - operator const char* () const - { - return Storage::ptr(); - } -}; - -typedef XString<> LString; -typedef XString LString_fs; - -typedef XString SString; -typedef XString SString_fs; -typedef XString SString_t; - - -#define XSTRING_WITH_LEN(X) (X).ptr(), (X).length() -#define DB_WITH_LEN(X) (X).db, (X).db_length -#define TABLE_NAME_WITH_LEN(X) (X).table_name, (X).table_name_length - class Local_da : public Diagnostics_area { diff --git a/sql/vtmd.cc b/sql/vtmd.cc index 65620bd2cb0..83a6fb512ef 100644 --- a/sql/vtmd.cc +++ b/sql/vtmd.cc @@ -416,7 +416,7 @@ VTMD_rename::try_rename(THD *thd, LString new_db, LString new_alias, const char return false; bool same_db= true; - if (LString_fs(DB_WITH_LEN(about)) != new_db) + if (LString_fs(DB_WITH_LEN(about)) != LString_fs(new_db)) { // Move archives before VTMD so if the operation is interrupted, it could be continued. if (move_archives(thd, new_db)) -- cgit v1.2.1 From b44425c6be217d34a6de2d6f9de85d256d68dd48 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Thu, 22 Jun 2017 23:36:50 +0300 Subject: Misc, SQL: checks cleanup in Item_field::set_field() --- sql/item.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sql/item.cc b/sql/item.cc index 80a38e4d1d2..d27ab95aaa4 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2763,9 +2763,8 @@ void Item_field::set_field(Field *field_par) field->force_null= false; if (field->flags & VERS_OPTIMIZED_UPDATE_FLAG && context && ((field->table->pos_in_table_list && - field->table->pos_in_table_list->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED) || - (context->select_lex && - context->select_lex->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED))) + field->table->pos_in_table_list->vers_conditions) || + (context->select_lex && context->select_lex->vers_conditions))) { field->force_null= true; push_warning_printf( -- cgit v1.2.1 From faab918ecd1ddb8640dda247ebec6010efc9ec69 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Fri, 23 Jun 2017 09:33:25 +0300 Subject: Style: comment about VTQ --- sql/vtq.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sql/vtq.h b/sql/vtq.h index 68c01990b04..dcea8734b57 100755 --- a/sql/vtq.h +++ b/sql/vtq.h @@ -1,5 +1,6 @@ #ifndef VTQ_INCLUDED #define VTQ_INCLUDED + /* Copyright (c) 2016, MariaDB Corporation. This program is free software; you can redistribute it and/or modify @@ -15,6 +16,15 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ + +/** + VTQ stands for 'versioning transaction query': InnoDB system table that holds + transaction IDs, their corresponding times and other transaction-related + data which is used for transaction order resolution. When versioned table + marks its records lifetime with transaction IDs, VTQ is used to get their + actual timestamps. */ + + enum vtq_field_t { VTQ_ALL = 0, -- cgit v1.2.1 From 46d572dde4f43a206f49574d5eca1d99b58b165a Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Tue, 27 Jun 2017 12:22:52 +0300 Subject: SQL: default engine fix in create from versioned [fixes #206] --- mysql-test/suite/versioning/r/create.result | 18 ++++++++++++++++++ mysql-test/suite/versioning/t/create.test | 29 +++++++++++++++++++++++++++++ sql/handler.cc | 20 +++++++++++++++++--- 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/versioning/r/create.result b/mysql-test/suite/versioning/r/create.result index 4e76063a52a..f3ea50192ce 100644 --- a/mysql-test/suite/versioning/r/create.result +++ b/mysql-test/suite/versioning/r/create.result @@ -61,6 +61,15 @@ drop table tmp; end if; end~~ drop table if exists t1; +create function if not exists non_default_engine() +returns varchar(255) +deterministic +begin +if default_engine() = 'innodb' then +return 'myisam'; +end if; +return 'innodb'; +end~~ create table t1 ( x1 int unsigned, Sys_start SYS_TRX_TYPE generated always as row start comment 'start', @@ -328,9 +337,18 @@ select st, en from t2 for system_time all where y = 2 into @st, @en; select y from t2 for system_time all where st = @st and en = @en; y 2 +create or replace table t1 (a int) with system versioning engine INNODB_OR_MYISAM; +create or replace table t2 as select a, sys_trx_start, sys_trx_end from t1 for system_time all; +create or replace table t2 engine INNODB_OR_MYISAM as select a, sys_trx_start, sys_trx_end from t1 for system_time all; +ERROR HY000: `sys_trx_start` must be of type `SYS_TRX_TYPE` for versioned table `t2` +create or replace table t1 (a int, id int) with system versioning engine INNODB_OR_MYISAM; +create or replace table t2 (b int, id int); +create or replace table t3 as +select t2.b, t1.a, t1.sys_trx_start, t1.sys_trx_end from t2 inner join t1 on t2.id=t1.id; drop table t1; drop table t2; drop table t3; +drop function non_default_engine; drop procedure verify_vtq; drop procedure innodb_verify_vtq; drop function default_engine; diff --git a/mysql-test/suite/versioning/t/create.test b/mysql-test/suite/versioning/t/create.test index a51e50f5deb..71b248c0003 100644 --- a/mysql-test/suite/versioning/t/create.test +++ b/mysql-test/suite/versioning/t/create.test @@ -4,7 +4,21 @@ drop table if exists t1; --enable_warnings +delimiter ~~; +create function if not exists non_default_engine() +returns varchar(255) +deterministic +begin + if default_engine() = 'innodb' then + return 'myisam'; + end if; + return 'innodb'; +end~~ +delimiter ;~~ + --let $sys_datatype= `select sys_datatype()` +--let $default_engine= `select default_engine()` +--let $non_default_engine= `select non_default_engine()` --replace_result "bigint unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE eval create table t1 ( @@ -257,8 +271,23 @@ select y from t2 for system_time all where st = @st and en = @en; select st, en from t2 for system_time all where y = 2 into @st, @en; select y from t2 for system_time all where st = @st and en = @en; +--replace_result innodb INNODB_OR_MYISAM myisam INNODB_OR_MYISAM +eval create or replace table t1 (a int) with system versioning engine $non_default_engine; +create or replace table t2 as select a, sys_trx_start, sys_trx_end from t1 for system_time all; +--replace_result innodb INNODB_OR_MYISAM myisam INNODB_OR_MYISAM "BIGINT(20) UNSIGNED" SYS_TRX_TYPE "TIMESTAMP(6)" SYS_TRX_TYPE +--error ER_VERS_FIELD_WRONG_TYPE +eval create or replace table t2 engine $default_engine as select a, sys_trx_start, sys_trx_end from t1 for system_time all; + +--replace_result innodb INNODB_OR_MYISAM myisam INNODB_OR_MYISAM +eval create or replace table t1 (a int, id int) with system versioning engine $non_default_engine; +create or replace table t2 (b int, id int); +create or replace table t3 as + select t2.b, t1.a, t1.sys_trx_start, t1.sys_trx_end from t2 inner join t1 on t2.id=t1.id; + drop table t1; drop table t2; drop table t3; +drop function non_default_engine; + -- source suite/versioning/common_finish.inc diff --git a/sql/handler.cc b/sql/handler.cc index 32d5c5fd2db..4f31c20c8e7 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6663,9 +6663,6 @@ bool Vers_parse_info::check_and_fix_implicit( HA_CREATE_INFO *create_info, const char* table_name) { - bool integer_fields= - create_info->db_type->flags & HTON_NATIVE_SYS_VERSIONING; - SELECT_LEX &slex= thd->lex->select_lex; int vers_tables= 0; bool from_select= slex.item_list.elements ? true : false; @@ -6677,6 +6674,21 @@ bool Vers_parse_info::check_and_fix_implicit( if (table->table && table->table->versioned()) vers_tables++; } + + // Possibly override default storage engine to match + // one used in source table. + if (!(create_info->used_fields & HA_CREATE_USED_ENGINE)) + { + List_iterator_fast it(alter_info->create_list); + while (Create_field *f= it++) + { + if (is_trx_start(*f) || is_trx_end(*f)) + { + create_info->db_type= f->field->orig_table->file->ht; + break; + } + } + } } // CREATE ... SELECT: if at least one table in SELECT is versioned, @@ -6750,6 +6762,8 @@ bool Vers_parse_info::check_and_fix_implicit( } } + bool integer_fields= create_info->db_type->flags & HTON_NATIVE_SYS_VERSIONING; + if (vers_tables > 0) { if (!generated_as_row.start && !generated_as_row.end) -- cgit v1.2.1 From 229c528110ecb38f379a6328b0eb62f6bbc74fad Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Tue, 27 Jun 2017 20:59:27 +0300 Subject: SQL: hide system fields instead of drop [closes #210] --- mysql-test/suite/versioning/r/alter.result | 27 +++++++++++++++++++++-- mysql-test/suite/versioning/t/alter.test | 27 +++++++++++++++++++++-- sql/handler.cc | 35 ++++++++++++++++++++++++++---- 3 files changed, 81 insertions(+), 8 deletions(-) diff --git a/mysql-test/suite/versioning/r/alter.result b/mysql-test/suite/versioning/r/alter.result index 3bb6f235056..4bc96a92b06 100644 --- a/mysql-test/suite/versioning/r/alter.result +++ b/mysql-test/suite/versioning/r/alter.result @@ -130,10 +130,33 @@ t CREATE TABLE `t` ( `c` int(11) DEFAULT NULL, PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +create or replace table t ( +a int, +sys_trx_start timestamp(6) generated always as row start, +sys_trx_end timestamp(6) generated always as row end, +period for system_time(sys_trx_start, sys_trx_end)) +with system versioning; +select * from t for system_time all; +a sys_trx_start sys_trx_end +alter table t drop column sys_trx_start; +alter table t drop column sys_trx_end; +select * from t for system_time all; +a alter table t drop column sys_trx_start; -ERROR HY000: Wrong parameters for `t`: Can not drop system versioning field +ERROR 42000: Can't DROP COLUMN `sys_trx_start`; check that it exists alter table t drop column sys_trx_end; -ERROR HY000: Wrong parameters for `t`: Can not drop system versioning field +ERROR 42000: Can't DROP COLUMN `sys_trx_end`; check that it exists +create or replace table t ( +a int, +sys_trx_start timestamp(6) generated always as row start, +sys_trx_end timestamp(6) generated always as row end, +period for system_time(sys_trx_start, sys_trx_end)) +with system versioning; +select * from t for system_time all; +a sys_trx_start sys_trx_end +alter table t drop column sys_trx_start, drop column sys_trx_end; +select * from t for system_time all; +a create or replace table t( a int ); diff --git a/mysql-test/suite/versioning/t/alter.test b/mysql-test/suite/versioning/t/alter.test index af297d2ba03..40d65f258a3 100644 --- a/mysql-test/suite/versioning/t/alter.test +++ b/mysql-test/suite/versioning/t/alter.test @@ -62,10 +62,33 @@ show create table t; alter table t drop column a; show create table t; ---error ER_VERS_WRONG_PARAMS +create or replace table t ( + a int, + sys_trx_start timestamp(6) generated always as row start, + sys_trx_end timestamp(6) generated always as row end, + period for system_time(sys_trx_start, sys_trx_end)) +with system versioning; + +select * from t for system_time all; alter table t drop column sys_trx_start; ---error ER_VERS_WRONG_PARAMS alter table t drop column sys_trx_end; +select * from t for system_time all; + +--error ER_CANT_DROP_FIELD_OR_KEY +alter table t drop column sys_trx_start; +--error ER_CANT_DROP_FIELD_OR_KEY +alter table t drop column sys_trx_end; + +create or replace table t ( + a int, + sys_trx_start timestamp(6) generated always as row start, + sys_trx_end timestamp(6) generated always as row end, + period for system_time(sys_trx_start, sys_trx_end)) +with system versioning; + +select * from t for system_time all; +alter table t drop column sys_trx_start, drop column sys_trx_end; +select * from t for system_time all; create or replace table t( a int diff --git a/sql/handler.cc b/sql/handler.cc index 4f31c20c8e7..9a4485412c2 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6630,6 +6630,7 @@ static bool vers_create_sys_field(THD *thd, const char *field_name, return true; alter_info->create_list.push_back(f); + alter_info->flags|= Alter_info::ALTER_ADD_COLUMN; return false; } @@ -6885,15 +6886,41 @@ bool Vers_parse_info::check_and_fix_alter(THD *thd, Alter_info *alter_info, if (alter_info->drop_list.elements) { + bool done_start= false; + bool done_end= false; List_iterator it(alter_info->drop_list); - while (Alter_drop* d= it++) + while (Alter_drop *d= it++) { - if (is_trx_start(d->name) || is_trx_end(d->name)) + const char *name= d->name; + Field *f= NULL; + if (!done_start && is_trx_start(name)) { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, - "Can not drop system versioning field"); + f= share->vers_start_field(); + done_start= true; + } + else if (!done_end && is_trx_end(name)) + { + f= share->vers_end_field(); + done_end= true; + } + else + continue; + if (f->flags & HIDDEN_FLAG) + { + my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0), d->type_name(), name); return true; } + + if (vers_create_sys_field(thd, name, alter_info, + f->flags & + (VERS_SYS_START_FLAG | VERS_SYS_END_FLAG), + integer_fields)) + { + return true; + } + + if (done_start && done_end) + break; } } -- cgit v1.2.1 From 177e477553bf0d2dd976971a1edf7b400f1aa265 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Thu, 29 Jun 2017 15:11:06 +0300 Subject: Tests: VTQ iso_level check fix --- mysql-test/suite/versioning/r/commit_id.result | 44 +++++++++++++++----------- mysql-test/suite/versioning/t/commit_id.test | 43 ++++++++++++++----------- 2 files changed, 50 insertions(+), 37 deletions(-) diff --git a/mysql-test/suite/versioning/r/commit_id.result b/mysql-test/suite/versioning/r/commit_id.result index c18f06c7abb..543840df1f8 100644 --- a/mysql-test/suite/versioning/r/commit_id.result +++ b/mysql-test/suite/versioning/r/commit_id.result @@ -64,26 +64,7 @@ create table t1( id int auto_increment primary key) with system versioning engine innodb; -set transaction isolation level read uncommitted; -insert into t1 values (); -select iso_level = 'RU' from information_schema.innodb_vtq limit 1; -iso_level = 'RU' -1 -set transaction isolation level read committed; -insert into t1 values (); -select iso_level = 'RC' from information_schema.innodb_vtq limit 1; -iso_level = 'RC' -1 -set transaction isolation level serializable; -insert into t1 values (); -select iso_level = 'S' from information_schema.innodb_vtq limit 1; -iso_level = 'S' -1 -set transaction isolation level repeatable read; insert into t1 values (); -select iso_level = 'RR' from information_schema.innodb_vtq limit 1; -iso_level = 'RR' -1 set @ts0= now(6); insert into t1 values (); select sys_trx_start from t1 where id = last_insert_id() into @tx0; @@ -135,6 +116,30 @@ vtq_trx_sees(0, @tx2) is null as F, vtq_trx_sees(-1, @tx2) as H; A B C D E F H 1 1 1 1 1 1 1 +set transaction isolation level read uncommitted; +insert into t1 values (); +select sys_trx_start from t1 where id = last_insert_id() into @tx3; +select iso_level = 'RU' from information_schema.innodb_vtq where trx_id = @tx3; +iso_level = 'RU' +1 +set transaction isolation level read committed; +insert into t1 values (); +select sys_trx_start from t1 where id = last_insert_id() into @tx4; +select iso_level = 'RC' from information_schema.innodb_vtq where trx_id = @tx4; +iso_level = 'RC' +1 +set transaction isolation level serializable; +insert into t1 values (); +select sys_trx_start from t1 where id = last_insert_id() into @tx5; +select iso_level = 'S' from information_schema.innodb_vtq where trx_id = @tx5; +iso_level = 'S' +1 +set transaction isolation level repeatable read; +insert into t1 values (); +select sys_trx_start from t1 where id = last_insert_id() into @tx6; +select iso_level = 'RR' from information_schema.innodb_vtq where trx_id = @tx6; +iso_level = 'RR' +1 drop table t1; call verify_vtq; No A B C D @@ -145,6 +150,7 @@ No A B C D 5 1 1 1 1 6 1 1 1 1 7 1 1 1 1 +8 1 1 1 1 drop procedure verify_vtq; drop procedure innodb_verify_vtq; drop function default_engine; diff --git a/mysql-test/suite/versioning/t/commit_id.test b/mysql-test/suite/versioning/t/commit_id.test index 7f7886f07a5..efecf55c143 100644 --- a/mysql-test/suite/versioning/t/commit_id.test +++ b/mysql-test/suite/versioning/t/commit_id.test @@ -6,26 +6,9 @@ with system versioning engine innodb; -# VTQ_ISO_LEVEL # - -set transaction isolation level read uncommitted; -insert into t1 values (); -select iso_level = 'RU' from information_schema.innodb_vtq limit 1; - -set transaction isolation level read committed; -insert into t1 values (); -select iso_level = 'RC' from information_schema.innodb_vtq limit 1; - -set transaction isolation level serializable; -insert into t1 values (); -select iso_level = 'S' from information_schema.innodb_vtq limit 1; +# VTQ_TRX_ID, VTQ_COMMIT_ID, VTQ_TRX_SEES # -set transaction isolation level repeatable read; insert into t1 values (); -select iso_level = 'RR' from information_schema.innodb_vtq limit 1; - - -# VTQ_TRX_ID, VTQ_COMMIT_ID, VTQ_TRX_SEES # set @ts0= now(6); insert into t1 values (); @@ -73,6 +56,30 @@ select vtq_trx_sees(0, @tx2) is null as F, vtq_trx_sees(-1, @tx2) as H; + +# VTQ_ISO_LEVEL # + +set transaction isolation level read uncommitted; +insert into t1 values (); +select sys_trx_start from t1 where id = last_insert_id() into @tx3; +select iso_level = 'RU' from information_schema.innodb_vtq where trx_id = @tx3; + +set transaction isolation level read committed; +insert into t1 values (); +select sys_trx_start from t1 where id = last_insert_id() into @tx4; +select iso_level = 'RC' from information_schema.innodb_vtq where trx_id = @tx4; + +set transaction isolation level serializable; +insert into t1 values (); +select sys_trx_start from t1 where id = last_insert_id() into @tx5; +select iso_level = 'S' from information_schema.innodb_vtq where trx_id = @tx5; + +set transaction isolation level repeatable read; +insert into t1 values (); +select sys_trx_start from t1 where id = last_insert_id() into @tx6; +select iso_level = 'RR' from information_schema.innodb_vtq where trx_id = @tx6; + + drop table t1; call verify_vtq; -- cgit v1.2.1 From 4b0f1284eeb633f091f2e93220661fc6888b1abc Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Thu, 29 Jun 2017 19:35:08 +0300 Subject: SQL: revisit error messages [closes #217] --- include/my_sys.h | 1 + mysql-test/suite/versioning/r/alter.result | 8 +- mysql-test/suite/versioning/r/create.result | 36 +++---- mysql-test/suite/versioning/r/partition.result | 28 ++++-- mysql-test/suite/versioning/r/select.result | 4 +- mysql-test/suite/versioning/r/vtmd_show.result | 6 +- mysql-test/suite/versioning/t/partition.test | 30 ++++-- mysql-test/suite/versioning/t/select.test | 4 +- mysql-test/suite/versioning/t/vtmd_show.test | 6 +- mysys/my_error.c | 36 +++++++ sql/handler.cc | 70 ++++++-------- sql/handler.h | 24 ++--- sql/partition_info.cc | 30 ++---- sql/share/errmsg-utf8.txt | 51 ++++++++-- sql/sql_partition.cc | 6 +- sql/sql_select.cc | 4 +- sql/sql_yacc.yy | 128 ++++++++++++++----------- 17 files changed, 284 insertions(+), 188 deletions(-) diff --git a/include/my_sys.h b/include/my_sys.h index 9cc069d1fd3..b1af4610ef0 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -726,6 +726,7 @@ extern int my_sync_dir(const char *dir_name, myf my_flags); extern int my_sync_dir_by_file(const char *file_name, myf my_flags); extern const char *my_get_err_msg(uint nr); extern void my_error(uint nr,myf MyFlags, ...); +extern void my_error_as(uint nr1, uint nr2, myf MyFlags, ...); extern void my_printf_error(uint my_err, const char *format, myf MyFlags, ...) ATTRIBUTE_FORMAT(printf, 2, 4); diff --git a/mysql-test/suite/versioning/r/alter.result b/mysql-test/suite/versioning/r/alter.result index 4bc96a92b06..71c7fb706af 100644 --- a/mysql-test/suite/versioning/r/alter.result +++ b/mysql-test/suite/versioning/r/alter.result @@ -9,7 +9,7 @@ t CREATE TABLE `t` ( alter table t without system versioning; ERROR HY000: Wrong parameters for `t`: table is not versioned alter table t with system versioning without system versioning; -ERROR HY000: Wrong parameters for `t`: Versioning specified more than once for the same table +ERROR HY000: Wrong parameters for `t`: multiple 'WITH/WITHOUT SYSTEM VERSIONING' alter table t with system versioning; show create table t; Table Create Table @@ -224,11 +224,11 @@ t CREATE TABLE `t` ( `b` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 alter table t modify a int with system versioning; -ERROR HY000: Wrong parameters for `t`: Can not change fields versioning mode in a non-versioned table +ERROR HY000: Wrong parameters for `t`: table is not versioned alter table t modify a int with system versioning with system versioning; -ERROR HY000: Wrong parameters for `t`: Versioning specified more than once for the same field +ERROR HY000: Wrong parameters for `t`: multiple 'WITH/WITHOUT SYSTEM VERSIONING' for `a` alter table t modify a int with system versioning without system versioning; -ERROR HY000: Wrong parameters for `t`: Versioning specified more than once for the same field +ERROR HY000: Wrong parameters for `t`: multiple 'WITH/WITHOUT SYSTEM VERSIONING' for `a` alter table t with system versioning; alter table t modify a int without system versioning; show create table t; diff --git a/mysql-test/suite/versioning/r/create.result b/mysql-test/suite/versioning/r/create.result index f3ea50192ce..2324adfaa73 100644 --- a/mysql-test/suite/versioning/r/create.result +++ b/mysql-test/suite/versioning/r/create.result @@ -103,14 +103,14 @@ Sys_start2 SYS_TRX_TYPE generated always as row start, Sys_end SYS_TRX_TYPE generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning; -ERROR HY000: Wrong parameters for `t1`: multiple 'GENERATED ALWAYS AS ROW START' +ERROR HY000: Wrong parameters for `t1`: multiple 'AS ROW START' (`Sys_start2`, `Sys_start`) create or replace table t1 ( x4 int unsigned, Sys_start SYS_TRX_TYPE generated always as row start, Sys_end2 SYS_TRX_TYPE generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning; -ERROR HY000: Wrong parameters for `t1`: 'PERIOD FOR SYSTEM_TIME' and 'GENERATED AS ROW END' mismatch +ERROR HY000: Wrong parameters for `t1`: mismatch 'PERIOD FOR SYSTEM_TIME' and 'AS ROW END' create or replace table t1 ( x5 int unsigned, Sys_start SYS_TRX_TYPE generated always as row start, @@ -118,12 +118,12 @@ Sys_end SYS_TRX_TYPE generated always as row end, Sys_end2 SYS_TRX_TYPE generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning; -ERROR HY000: Wrong parameters for `t1`: multiple 'GENERATED ALWAYS AS ROW END' +ERROR HY000: Wrong parameters for `t1`: multiple 'AS ROW END' (`Sys_end2`, `Sys_end`) create or replace table t1 ( x6 int unsigned, period for system_time (Sys_start, Sys_end) ) with system versioning; -ERROR HY000: Wrong parameters for `t1`: 'GENERATED AS ROW START' column missing +ERROR HY000: Wrong parameters for `t1`: missing 'AS ROW START' create or replace table t1 ( x7 int unsigned, Sys_start SYS_TRX_TYPE generated always as row start, @@ -131,28 +131,28 @@ Sys_end SYS_TRX_TYPE generated always as row end, Sys_end2 SYS_TRX_TYPE generated always as row end, period for system_time (Sys_start, Sys_end) ); -ERROR HY000: Wrong parameters for `t1`: multiple 'GENERATED ALWAYS AS ROW END' +ERROR HY000: Wrong parameters for `t1`: multiple 'AS ROW END' (`Sys_end2`, `Sys_end`) create or replace table t1 ( x8 int unsigned, Sys_start SYS_TRX_TYPE generated always as row start, Sys_end SYS_TRX_TYPE generated always as row end, period for system_time (sys_insert, sys_remove) ) with system versioning; -ERROR HY000: Wrong parameters for `t1`: 'PERIOD FOR SYSTEM_TIME' and 'GENERATED AS ROW START' mismatch +ERROR HY000: Wrong parameters for `t1`: mismatch 'PERIOD FOR SYSTEM_TIME' and 'AS ROW START' create or replace table t1 ( x9 int unsigned, Sys_start SYS_TRX_TYPE generated always as row start, Sys_end SYS_TRX_TYPE generated always as row end, period for system_time (Sys_start, Sys_end) ); -ERROR HY000: Wrong parameters for `t1`: 'WITH SYSTEM VERSIONING' missing +ERROR HY000: Wrong parameters for `t1`: missing 'WITH SYSTEM VERSIONING' create or replace table t1 ( x10 int unsigned, Sys_start SYS_TRX_TYPE generated always as row start, Sys_end SYS_TRX_TYPE generated always as row end, period for system_time (Sys_start, Sys_start) ); -ERROR HY000: Wrong parameters for `t1`: 'PERIOD FOR SYSTEM_TIME' columns must be different +ERROR HY000: Wrong parameters for `t1`: multiple `Sys_start` for 'PERIOD FOR SYSTEM_TIME' create or replace table t1 ( x11 int unsigned, Sys_start bigint unsigned generated always as row start, @@ -211,7 +211,7 @@ create or replace table t1 ( A3 int, B int without system versioning ); -ERROR HY000: Wrong parameters for `t1`: 'WITH SYSTEM VERSIONING' missing +ERROR HY000: Wrong parameters for `t1`: missing 'WITH SYSTEM VERSIONING' create or replace table t1 ( A4 int, B int without system versioning @@ -254,39 +254,39 @@ t1 CREATE TABLE `t1` ( create or replace table t1 ( A7 int without system versioning ); -ERROR HY000: Wrong parameters for `t1`: 'WITH SYSTEM VERSIONING' missing +ERROR HY000: Wrong parameters for `t1`: missing 'WITH SYSTEM VERSIONING' create or replace table t1 ( A8 int without system versioning ) with system versioning; -ERROR HY000: Wrong parameters for `t1`: no columns defined with system versioning! +ERROR HY000: Wrong parameters for `t1`: no columns defined 'WITH SYSTEM VERSIONING' create or replace table t1 ( A9 int without system versioning with system versioning ); -ERROR HY000: Wrong parameters for `t1`: Versioning specified more than once for the same field +ERROR HY000: Wrong parameters for `t1`: multiple 'WITH/WITHOUT SYSTEM VERSIONING' for `A9` create or replace table t1 ( A10 int with system versioning without system versioning ); -ERROR HY000: Wrong parameters for `t1`: Versioning specified more than once for the same field +ERROR HY000: Wrong parameters for `t1`: multiple 'WITH/WITHOUT SYSTEM VERSIONING' for `A10` create table t( a11 int ) without system versioning; -ERROR HY000: Wrong parameters for `t`: 'WITHOUT SYSTEM VERSIONING' is not allowed +ERROR HY000: Wrong parameters for `t`: not allowed 'WITHOUT SYSTEM VERSIONING' create or replace table t1 ( A12 int ) without system versioning with system versioning; -ERROR HY000: Wrong parameters for `t1`: Versioning specified more than once for the same table +ERROR HY000: Wrong parameters for `t1`: multiple 'WITH/WITHOUT SYSTEM VERSIONING' create or replace table t1 ( A13 int ) with system versioning without system versioning; -ERROR HY000: Wrong parameters for `t1`: Versioning specified more than once for the same table +ERROR HY000: Wrong parameters for `t1`: multiple 'WITH/WITHOUT SYSTEM VERSIONING' create or replace table t1 ( A14 int ) with system versioning with system versioning; -ERROR HY000: Wrong parameters for `t1`: Versioning specified more than once for the same table +ERROR HY000: Wrong parameters for `t1`: multiple 'WITH/WITHOUT SYSTEM VERSIONING' create or replace table t1 ( A15 int ) without system versioning without system versioning; -ERROR HY000: Wrong parameters for `t1`: Versioning specified more than once for the same table +ERROR HY000: Wrong parameters for `t1`: multiple 'WITH/WITHOUT SYSTEM VERSIONING' create or replace table t1 (a int) with system versioning; create temporary table tmp with system versioning select * from t1; create or replace table t1 (a int) with system versioning; diff --git a/mysql-test/suite/versioning/r/partition.result b/mysql-test/suite/versioning/r/partition.result index b76f01a340e..8daefaeff85 100644 --- a/mysql-test/suite/versioning/r/partition.result +++ b/mysql-test/suite/versioning/r/partition.result @@ -104,25 +104,25 @@ create or replace table t1 (x int) with system versioning partition by system_time ( partition p0 as of now); -ERROR HY000: Wrong parameters for `BY SYSTEM_TIME`: unexpected number of partitions (expected > 1) +ERROR HY000: Wrong partitions consistency for `t1`: must have at least one 'VERSIONING' and exactly one last 'AS OF NOW' create or replace table t1 (x int) with system versioning partition by system_time ( partition p0 as of now, partition p1 as of now); -ERROR HY000: Wrong parameters for `BY SYSTEM_TIME`: multiple `AS OF NOW` partitions +ERROR HY000: Wrong partitions consistency for `t1`: must have at least one 'VERSIONING' and exactly one last 'AS OF NOW' create or replace table t1 (x int) with system versioning partition by system_time ( partition p0 versioning, partition p1 versioning); -ERROR HY000: Wrong parameters for `BY SYSTEM_TIME`: no `AS OF NOW` partition defined +ERROR HY000: Wrong partitions consistency for `t1`: must have at least one 'VERSIONING' and exactly one last 'AS OF NOW' create or replace table t1 (x int) with system versioning partition by system_time ( partition pn as of now, partition p0 versioning); -ERROR HY000: Wrong parameters for `BY SYSTEM_TIME`: AS OF NOW partition is not last +ERROR HY000: Wrong partitions consistency for `t1`: must have at least one 'VERSIONING' and exactly one last 'AS OF NOW' create or replace table t1 (x int) with system versioning partition by system_time ( @@ -130,7 +130,7 @@ partition p0 versioning, partition pn as of now); alter table t1 add partition ( partition p1 as of now); -ERROR HY000: Wrong parameters for `BY SYSTEM_TIME`: AS OF NOW partition can not be added +ERROR HY000: Wrong partitions consistency for `t1`: must have at least one 'VERSIONING' and exactly one last 'AS OF NOW' alter table t1 add partition ( partition p1 versioning); Warnings: @@ -148,10 +148,10 @@ t1 CREATE TABLE `t1` ( PARTITION p1 VERSIONING ENGINE = ${INNODB_OR_MYISAM}, PARTITION pn AS OF NOW ENGINE = ${INNODB_OR_MYISAM}) alter table t1 drop partition pn; -ERROR HY000: Wrong parameters for `BY SYSTEM_TIME`: `AS OF NOW` partition can not be dropped +ERROR HY000: Wrong partitions consistency for `t1`: must have at least one 'VERSIONING' and exactly one last 'AS OF NOW' alter table t1 drop partition p1; alter table t1 drop partition p0; -ERROR HY000: Wrong parameters for `BY SYSTEM_TIME`: one `AS OF NOW` and at least one `VERSIONING` partition required +ERROR HY000: Wrong partitions consistency for `t1`: must have at least one 'VERSIONING' and exactly one last 'AS OF NOW' set @now= now(6); insert into t1 values (1); set @ts_start= sys_commit_ts('sys_trx_start'); @@ -226,6 +226,13 @@ select @ts2 = @ts3; 1 create or replace table t1 (x int) with system versioning +partition by system_time limit 0 ( +partition p0 versioning, +partition p1 versioning, +partition pn as of now); +ERROR HY000: Wrong parameters for partitioned `t1`: wrong value for 'LIMIT' +create or replace table t1 (x int) +with system versioning partition by system_time limit 1 ( partition p0 versioning, partition p1 versioning, @@ -268,6 +275,13 @@ x 3 create or replace table t1 (x int) with system versioning +partition by system_time interval 0 second ( +partition p0 versioning, +partition p1 versioning, +partition pn as of now); +ERROR HY000: Wrong parameters for partitioned `t1`: wrong value for 'INTERVAL' +create or replace table t1 (x int) +with system versioning partition by system_time interval 1 second ( partition p0 versioning, partition p1 versioning, diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index bc32db7114a..d6a471506ee 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -337,7 +337,7 @@ ERROR HY000: System Versioning required: `FOR SYSTEM_TIME` query create or replace table t1 (x int) with system versioning; insert into t1 values (1); select * from t1 for system_time all for update; -ERROR HY000: Wrong parameters for `FOR SYSTEM_TIME query`: write-locking of historic rows +ERROR HY000: Versioned SELECT write-locking of history rows create or replace table t1 (a int not null auto_increment primary key) with system versioning; select * from (t1 as t2 left join t1 as t3 using (a)) natural left join t1; a @@ -437,7 +437,7 @@ x y 2 1 3 1 select * from t1 for system_time all, t2 for system_time all query for system_time all; -ERROR HY000: Wrong versioned query: unused `QUERY FOR SYSTEM_TIME` clause! +ERROR HY000: Unused clause: 'QUERY FOR SYSTEM_TIME' drop view v1; drop table t1, t2; call innodb_verify_vtq(27); diff --git a/mysql-test/suite/versioning/r/vtmd_show.result b/mysql-test/suite/versioning/r/vtmd_show.result index 01d96f9a427..bcece5cba1f 100644 --- a/mysql-test/suite/versioning/r/vtmd_show.result +++ b/mysql-test/suite/versioning/r/vtmd_show.result @@ -55,11 +55,11 @@ ERROR 42S02: Table 'test.t_vtmd' doesn't exist set versioning_ddl_survival=on; create or replace table t (a int) with system versioning; show create table t for system_time between timestamp @tm1 and timestamp @tm1; -ERROR HY000: Wrong parameters for `FOR SYSTEM_TIME`: only AS OF allowed here +ERROR HY000: SYSTEM_TIME range selector is prohibited show create table t for system_time from timestamp @tm1 to timestamp @tm1; -ERROR HY000: Wrong parameters for `FOR SYSTEM_TIME`: only AS OF allowed here +ERROR HY000: SYSTEM_TIME range selector is prohibited show create table t for system_time before timestamp @tm1; -ERROR HY000: Wrong parameters for `FOR SYSTEM_TIME`: only AS OF allowed here +ERROR HY000: SYSTEM_TIME range selector is prohibited show create table t for system_time as of timestamp '01-01-1990'; ERROR HY000: VTMD error: failed to query VTMD table show create table t for system_time as of timestamp '01-01-2020'; diff --git a/mysql-test/suite/versioning/t/partition.test b/mysql-test/suite/versioning/t/partition.test index ca998757515..cbecde0be9b 100644 --- a/mysql-test/suite/versioning/t/partition.test +++ b/mysql-test/suite/versioning/t/partition.test @@ -35,27 +35,27 @@ partition by system_time ( partition p0 versioning, partition pn as of now); ---error ER_VERS_WRONG_PARAMS +--error ER_VERS_WRONG_PARTS create or replace table t1 (x int) with system versioning partition by system_time ( partition p0 as of now); ---error ER_VERS_WRONG_PARAMS +--error ER_VERS_WRONG_PARTS create or replace table t1 (x int) with system versioning partition by system_time ( partition p0 as of now, partition p1 as of now); ---error ER_VERS_WRONG_PARAMS +--error ER_VERS_WRONG_PARTS create or replace table t1 (x int) with system versioning partition by system_time ( partition p0 versioning, partition p1 versioning); ---error ER_VERS_WRONG_PARAMS +--error ER_VERS_WRONG_PARTS create or replace table t1 (x int) with system versioning partition by system_time ( @@ -69,7 +69,7 @@ partition by system_time ( partition pn as of now); # alter table ---error ER_VERS_WRONG_PARAMS +--error ER_VERS_WRONG_PARTS alter table t1 add partition ( partition p1 as of now); @@ -79,10 +79,10 @@ alter table t1 add partition ( --replace_result InnoDB ${INNODB_OR_MYISAM} MyISAM ${INNODB_OR_MYISAM} "bigint(20) unsigned" ${SYS_TRX_TYPE} timestamp(6) ${SYS_TRX_TYPE} show create table t1; ---error ER_VERS_WRONG_PARAMS +--error ER_VERS_WRONG_PARTS alter table t1 drop partition pn; alter table t1 drop partition p1; ---error ER_VERS_WRONG_PARAMS +--error ER_VERS_WRONG_PARTS alter table t1 drop partition p0; # insert, delete, update @@ -138,6 +138,14 @@ select @ts0 = @ts1; select @ts2 = @ts3; # rotation by LIMIT +--error ER_VERS_WRONG_PARAMS +create or replace table t1 (x int) +with system versioning +partition by system_time limit 0 ( + partition p0 versioning, + partition p1 versioning, + partition pn as of now); + create or replace table t1 (x int) with system versioning partition by system_time limit 1 ( @@ -162,6 +170,14 @@ delete from t1; select * from t1 partition (p1) for system_time all; # rotation by INTERVAL +--error ER_VERS_WRONG_PARAMS +create or replace table t1 (x int) +with system versioning +partition by system_time interval 0 second ( + partition p0 versioning, + partition p1 versioning, + partition pn as of now); + create or replace table t1 (x int) with system versioning partition by system_time interval 1 second ( diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index 37b6b8be89d..ca8b9ccf56a 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -127,7 +127,7 @@ select * from t1 for system_time all; create or replace table t1 (x int) with system versioning; insert into t1 values (1); ---error ER_VERS_WRONG_PARAMS +--error ER_VERS_HISTORY_LOCK select * from t1 for system_time all for update; create or replace table t1 (a int not null auto_increment primary key) with system versioning; @@ -197,7 +197,7 @@ delete from t1 where x = 3; insert into t2 values (1); select * from t1, t2 query for system_time all; ---error ER_VERS_WRONG_QUERY +--error ER_VERS_UNUSED_CLAUSE select * from t1 for system_time all, t2 for system_time all query for system_time all; drop view v1; diff --git a/mysql-test/suite/versioning/t/vtmd_show.test b/mysql-test/suite/versioning/t/vtmd_show.test index 7610db179ab..a4d946bbd55 100644 --- a/mysql-test/suite/versioning/t/vtmd_show.test +++ b/mysql-test/suite/versioning/t/vtmd_show.test @@ -71,11 +71,11 @@ show create table t for system_time as of now; set versioning_ddl_survival=on; create or replace table t (a int) with system versioning; ---error ER_VERS_WRONG_PARAMS +--error ER_VERS_RANGE_PROHIBITED show create table t for system_time between timestamp @tm1 and timestamp @tm1; ---error ER_VERS_WRONG_PARAMS +--error ER_VERS_RANGE_PROHIBITED show create table t for system_time from timestamp @tm1 to timestamp @tm1; ---error ER_VERS_WRONG_PARAMS +--error ER_VERS_RANGE_PROHIBITED show create table t for system_time before timestamp @tm1; --error ER_VERS_VTMD_ERROR show create table t for system_time as of timestamp '01-01-1990'; diff --git a/mysys/my_error.c b/mysys/my_error.c index f9614e07c6a..d57c186b2f3 100644 --- a/mysys/my_error.c +++ b/mysys/my_error.c @@ -327,3 +327,39 @@ void my_error_unregister_all(void) my_errmsgs_list= &my_errmsgs_globerrs; } + + +/** + Format one error and print out as another error code. + + @note + Stacks two error messages and prints as single error message. + Like my_error(), but error argument is another formatted error + + @param nr1 error number of printed message. nr1 must have exactly one %s + parameter which will be formatted message of error nr2. + @param nr2 error number of formatted message + @param MyFlags Flags + @param ... parameters for error nr2 +*/ + +void my_error_as(uint nr1, uint nr2, myf MyFlags, ...) +{ + const char *format; + va_list args; + char ebuff[ERRMSGSIZE]; + DBUG_ENTER("my_suberror"); + DBUG_PRINT("my", ("nr1: %d nr2: %d MyFlags: %lu errno: %d", nr1, nr2, MyFlags, errno)); + + if (!(format = my_get_err_msg(nr2))) + (void) my_snprintf(ebuff, sizeof(ebuff), "Unknown error %d", nr2); + else + { + va_start(args,MyFlags); + (void) my_vsnprintf_ex(&my_charset_utf8_general_ci, ebuff, + sizeof(ebuff), format, args); + va_end(args); + } + my_error(nr1, MyFlags, ebuff); + DBUG_VOID_RETURN; +} diff --git a/sql/handler.cc b/sql/handler.cc index 9a4485412c2..3589c3aee19 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6696,24 +6696,24 @@ bool Vers_parse_info::check_and_fix_implicit( // then created table will be versioned. if (thd->variables.vers_force || vers_tables > 0) { - declared_with_system_versioning= true; + with_system_versioning= true; create_info->options|= HA_VERSIONED_TABLE; } if (!need_check()) return false; - if (declared_without_system_versioning) + if (without_system_versioning) { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, - "'WITHOUT SYSTEM VERSIONING' is not allowed"); + my_error_as(ER_VERS_WRONG_PARAMS, ER_NOT_ALLOWED, MYF(0), table_name, + "WITHOUT SYSTEM VERSIONING"); return true; } - if (!declared_with_system_versioning && !has_versioned_fields) + if (!with_system_versioning && !versioned_fields) { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, - "'WITH SYSTEM VERSIONING' missing"); + my_error_as(ER_VERS_WRONG_PARAMS, ER_MISSING, MYF(0), table_name, + "WITH SYSTEM VERSIONING"); return true; } @@ -6729,8 +6729,7 @@ bool Vers_parse_info::check_and_fix_implicit( if (orig_table && orig_table != f->field->orig_table) { err_different_tables: - my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, - "system fields selected from different tables"); + my_error_as(ER_VERS_WRONG_PARAMS, ER_VERS_DIFFERENT_TABLES, MYF(0), table_name); return true; } orig_table= f->field->orig_table; @@ -6756,7 +6755,7 @@ bool Vers_parse_info::check_and_fix_implicit( } if ((f->versioning == Column_definition::VERSIONING_NOT_SET && - !declared_with_system_versioning) || + !with_system_versioning) || f->versioning == Column_definition::WITHOUT_VERSIONING) { f->flags|= VERS_OPTIMIZED_UPDATE_FLAG; @@ -6769,14 +6768,14 @@ bool Vers_parse_info::check_and_fix_implicit( { if (!generated_as_row.start && !generated_as_row.end) { - declared_with_system_versioning= false; + with_system_versioning= false; create_info->options&= ~HA_VERSIONED_TABLE; return false; } if (!generated_as_row.start || !generated_as_row.end) { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, - "both ROW START and ROW END system fields required in SELECT resultset"); + my_error_as(ER_VERS_WRONG_PARAMS, ER_MISSING, MYF(0), table_name, + generated_as_row.start ? "AS ROW END" : "AS ROW START"); return true; } } @@ -6807,8 +6806,8 @@ bool Vers_parse_info::check_and_fix_implicit( vers_cols == 0 && (plain_cols == 0 || !table_with_system_versioning)) { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, - "no columns defined with system versioning!"); + my_error_as(ER_VERS_WRONG_PARAMS, ER_VERS_NO_COLS_DEFINED, MYF(0), + table_name, "WITH SYSTEM VERSIONING"); return true; } @@ -6837,12 +6836,11 @@ bool Vers_parse_info::check_and_fix_alter(THD *thd, Alter_info *alter_info, if (!need_check() && !share->versioned) return false; - if (declared_without_system_versioning) + if (without_system_versioning) { if (!share->versioned) { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, - "table is not versioned"); + my_error_as(ER_VERS_WRONG_PARAMS, ER_VERS_NOT_VERSIONED, MYF(0), table_name); return true; } @@ -6854,10 +6852,9 @@ bool Vers_parse_info::check_and_fix_alter(THD *thd, Alter_info *alter_info, return false; } - if ((has_versioned_fields || has_unversioned_fields) && !share->versioned) + if ((versioned_fields || unversioned_fields) && !share->versioned) { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, - "Can not change fields versioning mode in a non-versioned table"); + my_error_as(ER_VERS_WRONG_PARAMS, ER_VERS_NOT_VERSIONED, MYF(0), table_name); return true; } @@ -6928,7 +6925,7 @@ bool Vers_parse_info::check_and_fix_alter(THD *thd, Alter_info *alter_info, } return fix_implicit(thd, alter_info, integer_fields) || - (declared_with_system_versioning && + (with_system_versioning && (check_with_conditions(table_name) || check_generated_type(table_name, alter_info, integer_fields))); } @@ -6958,8 +6955,8 @@ bool Vers_parse_info::fix_create_like(THD *thd, Alter_info *alter_info, if (!f_start || !f_end) { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), table->table_name, - "Missed one of system versioning fields from source"); + my_error_as(ER_VERS_WRONG_PARAMS, ER_MISSING, MYF(0), table->table_name, + f_start ? "AS ROW END" : "AS ROW START"); return true; } @@ -6973,38 +6970,31 @@ bool Vers_parse_info::fix_create_like(THD *thd, Alter_info *alter_info, bool Vers_parse_info::check_with_conditions(const char *table_name) const { - if (!generated_as_row.start) + if (!generated_as_row.start || !generated_as_row.end) { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, - "'GENERATED AS ROW START' column missing"); - return true; - } - - if (!generated_as_row.end) - { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, - "'GENERATED AS ROW END' column missing"); + my_error_as(ER_VERS_WRONG_PARAMS, ER_MISSING, MYF(0), table_name, + generated_as_row.start ? "AS ROW END" : "AS ROW START"); return true; } if (!period_for_system_time.start || !period_for_system_time.end) { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, - "'PERIOD FOR SYSTEM_TIME' missing"); + my_error_as(ER_VERS_WRONG_PARAMS, ER_MISSING, MYF(0), table_name, + "PERIOD FOR SYSTEM_TIME"); return true; } if (generated_as_row.start != period_for_system_time.start) { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, - "'PERIOD FOR SYSTEM_TIME' and 'GENERATED AS ROW START' mismatch"); + my_error_as(ER_VERS_WRONG_PARAMS, ER_MISMATCH, MYF(0), table_name, + "PERIOD FOR SYSTEM_TIME", "AS ROW START"); return true; } if (generated_as_row.end != period_for_system_time.end) { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), table_name, - "'PERIOD FOR SYSTEM_TIME' and 'GENERATED AS ROW END' mismatch"); + my_error_as(ER_VERS_WRONG_PARAMS, ER_MISMATCH, MYF(0), table_name, + "PERIOD FOR SYSTEM_TIME", "AS ROW END"); return true; } diff --git a/sql/handler.h b/sql/handler.h index 9c2b1bcf209..5462b33a3aa 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1677,10 +1677,10 @@ class Create_field; struct Vers_parse_info { Vers_parse_info() : - declared_with_system_versioning(false), - declared_without_system_versioning(false), - has_versioned_fields(false), - has_unversioned_fields(false) + with_system_versioning(false), + without_system_versioning(false), + versioned_fields(false), + unversioned_fields(false) {} struct start_end_t @@ -1712,10 +1712,10 @@ private: bool need_check() const { return - has_versioned_fields || - has_unversioned_fields || - declared_with_system_versioning || - declared_without_system_versioning || + versioned_fields || + unversioned_fields || + with_system_versioning || + without_system_versioning || period_for_system_time.start.str || period_for_system_time.end.str || generated_as_row.start.str || @@ -1735,22 +1735,22 @@ public: HA_CREATE_INFO *create_info, TABLE_LIST *table); /** User has added 'WITH SYSTEM VERSIONING' to table definition */ - bool declared_with_system_versioning : 1; + bool with_system_versioning : 1; /** Use has added 'WITHOUT SYSTEM VERSIONING' to ALTER TABLE */ - bool declared_without_system_versioning : 1; + bool without_system_versioning : 1; /** At least one field was specified 'WITH SYSTEM VERSIONING'. Useful for error handling. */ - bool has_versioned_fields : 1; + bool versioned_fields : 1; /** At least one field was specified 'WITHOUT SYSTEM VERSIONING'. Useful for error handling. */ - bool has_unversioned_fields : 1; + bool unversioned_fields : 1; }; /** diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 2b1bc41931d..dd4ec54673a 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -851,16 +851,8 @@ bool partition_info::vers_init_info(THD * thd) bool partition_info::vers_set_interval(const INTERVAL & i) { - if (i.neg) - { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), "BY SYSTEM_TIME", "negative INTERVAL"); - return true; - } - if (i.second_part) - { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), "BY SYSTEM_TIME", "second fractions in INTERVAL"); + if (i.neg || i.second_part) return true; - } DBUG_ASSERT(vers_info); @@ -874,20 +866,16 @@ bool partition_info::vers_set_interval(const INTERVAL & i) i.year * 365 * 30 * 24 * 60 * 60; if (vers_info->interval == 0) - { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), "BY SYSTEM_TIME", "zero INTERVAL"); return true; - } + return false; } bool partition_info::vers_set_limit(ulonglong limit) { if (limit < 1) - { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), "BY SYSTEM_TIME", "non-positive LIMIT"); return true; - } + DBUG_ASSERT(vers_info); vers_info->limit= limit; @@ -1978,15 +1966,11 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, if (part_type == VERSIONING_PARTITION) { - if (num_parts < 2) - { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), "BY SYSTEM_TIME", "unexpected number of partitions (expected > 1)"); - goto end; - } DBUG_ASSERT(vers_info); - if (!vers_info->now_part) + if (num_parts < 2 || !vers_info->now_part) { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), "BY SYSTEM_TIME", "no `AS OF NOW` partition defined"); + DBUG_ASSERT(info && info->alias); + my_error(ER_VERS_WRONG_PARTS, MYF(0), info->alias); goto end; } DBUG_ASSERT(vers_info->initialized(false)); @@ -2135,7 +2119,7 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, } if (now_parts > 1) { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), "BY SYSTEM_TIME", "multiple `AS OF NOW` partitions"); + my_error(ER_VERS_WRONG_PARTS, MYF(0), info->alias); goto end; } result= FALSE; diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 17bd8a983a7..bbe4e6cff0e 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7500,7 +7500,7 @@ ER_VERS_FIELD_WRONG_TYPE eng "%`s must be of type %`s for versioned table %`s" ER_VERS_WRONG_PARAMS - eng "Wrong parameters for %`s: %s" + eng "Wrong parameters %s" ER_VERS_ENGINE_UNSUPPORTED eng "Engine does not support System Versioning for %`s" @@ -7532,8 +7532,8 @@ WARN_VERS_PART_NON_HISTORICAL ER_VERS_NOT_ALLOWED eng "%`s is not allowed for versioned table" -ER_VERS_WRONG_QUERY_TYPE - eng "%`s works only with %`s query type" +ER_VERS_RANGE_PROHIBITED + eng "SYSTEM_TIME range selector is prohibited" ER_VERS_VIEW_PROHIBITED eng "Creating VIEW %`s is prohibited!" @@ -7541,14 +7541,53 @@ ER_VERS_VIEW_PROHIBITED ER_VERS_DERIVED_PROHIBITED eng "Derived table is prohibited!" -ER_VERS_WRONG_QUERY - eng "Wrong versioned query: %s" +ER_VERS_UNUSED_CLAUSE + eng "Unused clause: '%s'" WARN_VERS_ALIAS_TOO_LONG - eng "Auto generated alias for `%s.%s` is too long; using `%s`." + eng "Auto generated alias for `%s.%s` is too long; using `%s`" ER_VERS_VTMD_ERROR eng "VTMD error: %s" +ER_MULTIPLE_CLAUSE + eng "for %`s: multiple '%s'" + +ER_MULTIPLE_CLAUSE_FOR + eng "for %`s: multiple '%s' for %`s" + +ER_MULTIPLE_CLAUSE_2 + eng "for %`s: multiple '%s' (%`s, %`s)" + +ER_MULTIPLE_IDENTIFIER + eng "for %`s: multiple %`s for '%s'" + +ER_NOT_ALLOWED + eng "for %`s: not allowed '%s'" + +ER_VERS_DIFFERENT_TABLES + eng "for %`s: system fields selected from different tables" + +ER_VERS_NO_COLS_DEFINED + eng "for %`s: no columns defined '%s'" + +ER_VERS_NOT_VERSIONED + eng "for %`s: table is not versioned" + +ER_MISSING + eng "for %`s: missing '%s'" + +ER_MISMATCH + eng "for %`s: mismatch '%s' and '%s'" + +ER_PART_WRONG_VALUE + eng "for partitioned %`s: wrong value for '%s'" + +ER_VERS_WRONG_PARTS + eng "Wrong partitions consistency for %`s: must have at least one 'VERSIONING' and exactly one last 'AS OF NOW'" + +ER_VERS_HISTORY_LOCK + eng "Versioned SELECT write-locking of history rows" + ER_WRONG_TABLESPACE_NAME 42000 eng "Incorrect tablespace name `%-.192s`" diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index caca441e5e4..7278b56a017 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5368,7 +5368,8 @@ that are reorganised. { if (num_parts_dropped >= tab_part_info->num_parts - 1) { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), "BY SYSTEM_TIME", "one `AS OF NOW` and at least one `VERSIONING` partition required"); + DBUG_ASSERT(table && table->s && table->s->table_name.str); + my_error(ER_VERS_WRONG_PARTS, MYF(0), table->s->table_name.str); goto err; } } @@ -5394,7 +5395,8 @@ that are reorganised. { if (part_elem->type == partition_element::AS_OF_NOW) { - my_error(ER_VERS_WRONG_PARAMS, MYF(0), "BY SYSTEM_TIME", "`AS OF NOW` partition can not be dropped"); + DBUG_ASSERT(table && table->s && table->s->table_name.str); + my_error(ER_VERS_WRONG_PARTS, MYF(0), table->s->table_name.str); goto err; } /* diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 2355552ab77..fef673b8c33 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -824,7 +824,7 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, case TL_WRITE_LOW_PRIORITY: case TL_WRITE: case TL_WRITE_ONLY: - my_error(ER_VERS_WRONG_PARAMS, MYF(0), "FOR SYSTEM_TIME query", "write-locking of historic rows"); + my_error(ER_VERS_HISTORY_LOCK, MYF(0)); DBUG_RETURN(-1); default: break; @@ -1004,7 +1004,7 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, if (!slex->vers_conditions.used && slex->vers_conditions) { - my_error(ER_VERS_WRONG_QUERY, MYF(0), "unused `QUERY FOR SYSTEM_TIME` clause!"); + my_error(ER_VERS_UNUSED_CLAUSE, MYF(0), "QUERY FOR SYSTEM_TIME"); DBUG_RETURN(-1); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 73860aadca5..8b3014f301a 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -67,6 +67,7 @@ #include "lex_token.h" #include "sql_lex.h" #include "sql_sequence.h" +#include "vers_utils.h" /* this is to get the bison compilation windows warnings out */ #ifdef _MSC_VER @@ -851,6 +852,7 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr) enum trigger_order_type trigger_action_order_type; DDL_options_st object_ddl_options; enum vers_range_unit_t vers_range_unit; + enum Column_definition::enum_column_versioning vers_column_versioning; } %{ @@ -1973,7 +1975,7 @@ END_OF_INPUT %type trans_or_timestamp %type opt_for_system_time_clause - +%type with_or_without_system %% @@ -5206,8 +5208,11 @@ opt_part_values: } else { + DBUG_ASSERT(Lex->create_last_non_select_table); + DBUG_ASSERT(Lex->create_last_non_select_table->table_name); // FIXME: other ALTER commands? - my_yyabort_error((ER_VERS_WRONG_PARAMS, MYF(0), "BY SYSTEM_TIME", "AS OF NOW partition can not be added")); + my_yyabort_error((ER_VERS_WRONG_PARTS, MYF(0), + Lex->create_last_non_select_table->table_name)); } elem->type= partition_element::AS_OF_NOW; DBUG_ASSERT(part_info->vers_info); @@ -5235,7 +5240,11 @@ opt_part_values: } DBUG_ASSERT(part_info->vers_info); if (part_info->vers_info->now_part) - my_yyabort_error((ER_VERS_WRONG_PARAMS, MYF(0), "BY SYSTEM_TIME", "AS OF NOW partition is not last")); + { + DBUG_ASSERT(Lex->create_last_non_select_table); + DBUG_ASSERT(Lex->create_last_non_select_table->table_name); + my_yyabort_error((ER_VERS_WRONG_PARTS, MYF(0), Lex->create_last_non_select_table->table_name)); + } elem->type= partition_element::VERSIONING; if (part_info->init_column_part(thd)) { @@ -5551,10 +5560,13 @@ opt_versioning_interval: partition_info *part_info= Lex->part_info; DBUG_ASSERT(part_info->part_type == VERSIONING_PARTITION); INTERVAL interval; - if (get_interval_value($2, $3, &interval)) - my_yyabort_error((ER_VERS_WRONG_PARAMS, MYF(0), "BY SYSTEM_TIME", "wrong INTERVAL value")); - if (part_info->vers_set_interval(interval)) + if (get_interval_value($2, $3, &interval) || + part_info->vers_set_interval(interval)) + { + my_error_as(ER_VERS_WRONG_PARAMS, ER_PART_WRONG_VALUE, MYF(0), + Lex->create_last_non_select_table->table_name, "INTERVAL"); MYSQL_YYABORT; + } } ; @@ -5565,7 +5577,11 @@ opt_versioning_limit: partition_info *part_info= Lex->part_info; DBUG_ASSERT(part_info->part_type == VERSIONING_PARTITION); if (part_info->vers_set_limit($2)) + { + my_error_as(ER_VERS_WRONG_PARAMS, ER_PART_WRONG_VALUE, MYF(0), + Lex->create_last_non_select_table->table_name, "LIMIT"); MYSQL_YYABORT; + } } ; @@ -5936,32 +5952,28 @@ create_table_option: Lex->create_info.used_fields|= HA_CREATE_USED_SEQUENCE; Lex->create_info.sequence= $3; } - | WITH_SYSTEM_SYM VERSIONING_SYM + | WITH_SYSTEM_SYM table_versioning { - const char *table_name= - Lex->create_last_non_select_table->table_name; - Vers_parse_info &info= Lex->vers_get_info(); - if (info.declared_with_system_versioning || - info.declared_without_system_versioning) - my_yyabort_error( - (ER_VERS_WRONG_PARAMS, MYF(0), table_name, - "Versioning specified more than once for the same table")); - - info.declared_with_system_versioning= true; + Lex->vers_get_info().with_system_versioning= true; Lex->create_info.options|= HA_VERSIONED_TABLE; } - | WITHOUT SYSTEM VERSIONING_SYM + | WITHOUT SYSTEM table_versioning { - const char *table_name= - Lex->create_last_non_select_table->table_name; - Vers_parse_info &info= Lex->vers_get_info(); - if (info.declared_with_system_versioning || - info.declared_without_system_versioning) - my_yyabort_error( - (ER_VERS_WRONG_PARAMS, MYF(0), table_name, - "Versioning specified more than once for the same table")); + Lex->vers_get_info().without_system_versioning= true; + } + ; - info.declared_without_system_versioning= true; +table_versioning: + VERSIONING_SYM + { + Vers_parse_info &info= Lex->vers_get_info(); + if (info.with_system_versioning || info.without_system_versioning) + { + my_error_as(ER_VERS_WRONG_PARAMS, ER_MULTIPLE_CLAUSE, MYF(0), + Lex->create_last_non_select_table->table_name, + "WITH/WITHOUT SYSTEM VERSIONING"); + MYSQL_YYABORT; + } } ; @@ -6169,9 +6181,10 @@ period_for_system_time: Vers_parse_info &info= Lex->vers_get_info(); if (!my_strcasecmp(system_charset_info, $4.str, $6.str)) { - my_yyabort_error((ER_VERS_WRONG_PARAMS, MYF(0), - Lex->create_last_non_select_table->table_name, - "'PERIOD FOR SYSTEM_TIME' columns must be different")); + my_error_as(ER_VERS_WRONG_PARAMS, ER_MULTIPLE_IDENTIFIER, MYF(0), + Lex->create_last_non_select_table->table_name, $4.str, + "PERIOD FOR SYSTEM_TIME"); + MYSQL_YYABORT; } info.set_period_for_system_time($4, $6); } @@ -6288,17 +6301,17 @@ field_def: const char *table_name= lex->create_last_non_select_table->table_name; LString_i *p; - const char* err; + const char* clause; switch ($4) { case 1: p= &info.generated_as_row.start; - err= "multiple 'GENERATED ALWAYS AS ROW START'"; + clause= "AS ROW START"; lex->last_field->flags|= VERS_SYS_START_FLAG; break; case 0: p= &info.generated_as_row.end; - err= "multiple 'GENERATED ALWAYS AS ROW END'"; + clause= "AS ROW END"; lex->last_field->flags|= VERS_SYS_END_FLAG; break; default: @@ -6309,7 +6322,9 @@ field_def: DBUG_ASSERT(p); if (*p) { - my_yyabort_error((ER_VERS_WRONG_PARAMS, MYF(0), table_name, err)); + my_error_as(ER_VERS_WRONG_PARAMS, ER_MULTIPLE_CLAUSE_2, MYF(0), + table_name, clause, field_name, p->ptr()); + MYSQL_YYABORT; } *p= field_name; if (lex->last_field->implicit_not_null) @@ -6805,31 +6820,30 @@ serial_attribute: new (thd->mem_root) engine_option_value($1, &Lex->last_field->option_list, &Lex->option_list_last); } - | WITH_SYSTEM_SYM VERSIONING_SYM + | with_or_without_system VERSIONING_SYM { - if (Lex->last_field->versioning != - Column_definition::VERSIONING_NOT_SET) - my_yyabort_error( - (ER_VERS_WRONG_PARAMS, MYF(0), + if (Lex->last_field->versioning != Column_definition::VERSIONING_NOT_SET) + { + my_error_as(ER_VERS_WRONG_PARAMS, ER_MULTIPLE_CLAUSE_FOR, MYF(0), Lex->create_last_non_select_table->table_name, - "Versioning specified more than once for the same field")); - - Lex->last_field->versioning = Column_definition::WITH_VERSIONING; - Lex->create_info.vers_info.has_versioned_fields= true; + "WITH/WITHOUT SYSTEM VERSIONING", Lex->last_field->field_name); + MYSQL_YYABORT; + } + Lex->last_field->versioning= $1; Lex->create_info.options|= HA_VERSIONED_TABLE; } - | WITHOUT SYSTEM VERSIONING_SYM - { - if (Lex->last_field->versioning != - Column_definition::VERSIONING_NOT_SET) - my_yyabort_error( - (ER_VERS_WRONG_PARAMS, MYF(0), - Lex->create_last_non_select_table->table_name, - "Versioning specified more than once for the same field")); + ; - Lex->last_field->versioning = Column_definition::WITHOUT_VERSIONING; - Lex->create_info.vers_info.has_unversioned_fields= true; - Lex->create_info.options|= HA_VERSIONED_TABLE; +with_or_without_system: + WITH_SYSTEM_SYM + { + Lex->create_info.vers_info.versioned_fields= true; + $$= Column_definition::WITH_VERSIONING; + } + | WITHOUT SYSTEM + { + Lex->create_info.vers_info.unversioned_fields= true; + $$= Column_definition::WITHOUT_VERSIONING; } ; @@ -13336,9 +13350,9 @@ show_param: lex->create_info.storage_media= HA_SM_DEFAULT; if (lex->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED && - lex->vers_conditions.type != FOR_SYSTEM_TIME_AS_OF) { - my_yyabort_error((ER_VERS_WRONG_PARAMS, MYF(0), "FOR SYSTEM_TIME", - "only AS OF allowed here")); + lex->vers_conditions.type != FOR_SYSTEM_TIME_AS_OF) + { + my_yyabort_error((ER_VERS_RANGE_PROHIBITED, MYF(0))); } if ($4) Lex->last_table()->vers_conditions= Lex->vers_conditions; -- cgit v1.2.1 From 5570ab378935319400acbb69048fecf80fb7c57d Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Mon, 3 Jul 2017 12:15:55 +0300 Subject: SQL: history records became alive on copy [fixes #212] --- mysql-test/suite/versioning/r/alter.result | 2 -- sql/sql_table.cc | 12 +++++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/versioning/r/alter.result b/mysql-test/suite/versioning/r/alter.result index 71c7fb706af..924560c3a6e 100644 --- a/mysql-test/suite/versioning/r/alter.result +++ b/mysql-test/suite/versioning/r/alter.result @@ -366,7 +366,6 @@ t CREATE TABLE `t` ( select * from t; a b 2 NULL -1 NULL alter table t drop column b, algorithm=copy; show create table t; Table Create Table @@ -393,7 +392,6 @@ t CREATE TABLE `t` ( select * from t; a b 2 NULL -1 NULL alter table t drop column b, algorithm=inplace; show create table t; Table Create Table diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 4c1ab495651..9728b2d77e8 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -10052,7 +10052,17 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, error= 1; break; } - error=to->file->ha_write_row(to->record[0]); + if (keep_versioned && to->versioned_by_engine() && + !thd->variables.vers_ddl_survival) + { + to->s->versioned= false; + } + error= to->file->ha_write_row(to->record[0]); + if (keep_versioned && to->versioned_by_engine() && + !thd->variables.vers_ddl_survival) + { + to->s->versioned= true; + } to->auto_increment_field_not_null= FALSE; if (error) { -- cgit v1.2.1 From 72de7721b9ebc80ab8cb8019d2ca955f666368df Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 3 Jul 2017 17:38:59 +0300 Subject: SQL: No implicit versioning when created from SELECT [closes #219] --- mysql-test/suite/versioning/r/create.result | 69 +++++++++++++++++++--------- mysql-test/suite/versioning/r/sysvars.result | 4 +- mysql-test/suite/versioning/r/vtmd.result | 2 +- mysql-test/suite/versioning/t/create.test | 58 ++++++++++++++++------- mysql-test/suite/versioning/t/sysvars.test | 2 +- mysql-test/suite/versioning/t/vtmd.test | 2 +- sql/handler.cc | 49 +++++++------------- sql/sql_base.cc | 27 +++++++---- 8 files changed, 130 insertions(+), 83 deletions(-) diff --git a/mysql-test/suite/versioning/r/create.result b/mysql-test/suite/versioning/r/create.result index 2324adfaa73..e4341223ef5 100644 --- a/mysql-test/suite/versioning/r/create.result +++ b/mysql-test/suite/versioning/r/create.result @@ -301,21 +301,39 @@ tt1 CREATE TABLE `tt1` ( ) ENGINE=INNODB_OR_MYISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING drop table tt1; create or replace table t1 (x int) with system versioning; -create or replace table t2 (y int); -create or replace table t3 select * from t1 for system_time all, t2; -show create table t3; -Table Create Table -t3 CREATE TABLE `t3` ( - `x` int(11) DEFAULT NULL, - `y` int(11) DEFAULT NULL -) ENGINE=INNODB_OR_MYISAM DEFAULT CHARSET=latin1 -create or replace table t2 ( +create or replace table t0( y int, st SYS_TRX_TYPE generated always as row start, en SYS_TRX_TYPE generated always as row end, period for system_time (st, en) ) with system versioning; -create or replace table t3 select * from t2; +create or replace table t2 as select * from t1; +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `x` int(11) DEFAULT NULL +) ENGINE=INNODB_OR_MYISAM DEFAULT CHARSET=latin1 +create or replace table t3 as select * from t0; +show create table t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `y` int(11) DEFAULT NULL +) ENGINE=INNODB_OR_MYISAM DEFAULT CHARSET=latin1 +insert into t1 values (1); +insert into t0 values (2); +create or replace table t2 with system versioning as select * from t1; +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `x` int(11) DEFAULT NULL, + `sys_trx_start` SYS_TRX_TYPE GENERATED ALWAYS AS ROW START, + `sys_trx_end` SYS_TRX_TYPE GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=INNODB_OR_MYISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +select * from t2; +x +1 +create or replace table t3 with system versioning as select * from t0; show create table t3; Table Create Table t3 CREATE TABLE `t3` ( @@ -324,7 +342,23 @@ t3 CREATE TABLE `t3` ( `en` SYS_TRX_TYPE GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (`st`, `en`) ) ENGINE=INNODB_OR_MYISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING -create or replace table t3 select x, y, t1.sys_trx_start, t2.en from t1, t2; +select * from t3 where y > 2; +y st en +delete from t0; +create or replace table t1 (x int) with system versioning; +create or replace table t2 (y int); +create or replace table t3 with system versioning select * from t1 for system_time all, t2; +show create table t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `x` int(11) DEFAULT NULL, + `sys_trx_start` SYS_TRX_TYPE GENERATED ALWAYS AS ROW START, + `sys_trx_end` SYS_TRX_TYPE GENERATED ALWAYS AS ROW END, + `y` int(11) DEFAULT NULL, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=INNODB_OR_MYISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +create or replace table t2 with system versioning as select * from t0; +create or replace table t3 with system versioning select x, y, t1.sys_trx_start, t2.en from t1, t2; ERROR HY000: Wrong parameters for `t3`: system fields selected from different tables insert into t2 values (1), (2); delete from t2 where y = 2; @@ -339,18 +373,11 @@ y 2 create or replace table t1 (a int) with system versioning engine INNODB_OR_MYISAM; create or replace table t2 as select a, sys_trx_start, sys_trx_end from t1 for system_time all; -create or replace table t2 engine INNODB_OR_MYISAM as select a, sys_trx_start, sys_trx_end from t1 for system_time all; +create or replace table t2 with system versioning engine INNODB_OR_MYISAM as select a, sys_trx_start, sys_trx_end from t1 for system_time all; ERROR HY000: `sys_trx_start` must be of type `SYS_TRX_TYPE` for versioned table `t2` create or replace table t1 (a int, id int) with system versioning engine INNODB_OR_MYISAM; create or replace table t2 (b int, id int); create or replace table t3 as select t2.b, t1.a, t1.sys_trx_start, t1.sys_trx_end from t2 inner join t1 on t2.id=t1.id; -drop table t1; -drop table t2; -drop table t3; -drop function non_default_engine; -drop procedure verify_vtq; -drop procedure innodb_verify_vtq; -drop function default_engine; -drop function sys_commit_ts; -drop function sys_datatype; +drop database test; +create database test; diff --git a/mysql-test/suite/versioning/r/sysvars.result b/mysql-test/suite/versioning/r/sysvars.result index 172a10c78d7..56122432e6e 100644 --- a/mysql-test/suite/versioning/r/sysvars.result +++ b/mysql-test/suite/versioning/r/sysvars.result @@ -139,12 +139,12 @@ Table Create Table t CREATE TABLE `t` ( `x` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 -insert into t values (1); +insert into t values (2); delete from t; select * from t; x select * from t for system_time all; x -1 +2 drop table t; set versioning_hide= IMPLICIT; diff --git a/mysql-test/suite/versioning/r/vtmd.result b/mysql-test/suite/versioning/r/vtmd.result index f2e7956bfa8..808f6e7d92d 100644 --- a/mysql-test/suite/versioning/r/vtmd.result +++ b/mysql-test/suite/versioning/r/vtmd.result @@ -28,7 +28,7 @@ create or replace procedure check_vtmd (in vtmd_name varchar(64)) begin set @tmp= concat(' create or replace temporary table - tmp_vtmd as + tmp_vtmd with system versioning as select * from ', vtmd_name, ' as vtmd for system_time all'); prepare stmt from @tmp; execute stmt; drop prepare stmt; diff --git a/mysql-test/suite/versioning/t/create.test b/mysql-test/suite/versioning/t/create.test index 71b248c0003..032c75b64ef 100644 --- a/mysql-test/suite/versioning/t/create.test +++ b/mysql-test/suite/versioning/t/create.test @@ -243,24 +243,55 @@ drop table tt1; # CREATE TABLE ... SELECT create or replace table t1 (x int) with system versioning; -create or replace table t2 (y int); -create or replace table t3 select * from t1 for system_time all, t2; ---replace_result InnoDB INNODB_OR_MYISAM MyISAM INNODB_OR_MYISAM "bigint(20) unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE -show create table t3; - --replace_result "bigint unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE -eval create or replace table t2 ( +eval create or replace table t0( y int, st $sys_datatype generated always as row start, en $sys_datatype generated always as row end, period for system_time (st, en) ) with system versioning; -create or replace table t3 select * from t2; + +## For non-versioned table: +### 1. system fields are not inherited (hidden and not hidden) +create or replace table t2 as select * from t1; +--replace_result InnoDB INNODB_OR_MYISAM MyISAM INNODB_OR_MYISAM +show create table t2; + +create or replace table t3 as select * from t0; +--replace_result InnoDB INNODB_OR_MYISAM MyISAM INNODB_OR_MYISAM +show create table t3; + +### 2. hidden fields are inherited as hidden +### TODO: non-system hidden fields + +## For versioned table system fields are inherited as is. +insert into t1 values (1); +insert into t0 values (2); + +create or replace table t2 with system versioning as select * from t1; +--replace_result InnoDB INNODB_OR_MYISAM MyISAM INNODB_OR_MYISAM "bigint(20) unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE +show create table t2; +# implicit system fields are hidden +select * from t2; + +create or replace table t3 with system versioning as select * from t0; +--replace_result InnoDB INNODB_OR_MYISAM MyISAM INNODB_OR_MYISAM "bigint(20) unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE +show create table t3; +# explicit system fields are not hidden +select * from t3 where y > 2; + +delete from t0; + +## Combinations of versioned + non-versioned +create or replace table t1 (x int) with system versioning; +create or replace table t2 (y int); +create or replace table t3 with system versioning select * from t1 for system_time all, t2; --replace_result InnoDB INNODB_OR_MYISAM MyISAM INNODB_OR_MYISAM "bigint(20) unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE show create table t3; +create or replace table t2 with system versioning as select * from t0; --error ER_VERS_WRONG_PARAMS -create or replace table t3 select x, y, t1.sys_trx_start, t2.en from t1, t2; +create or replace table t3 with system versioning select x, y, t1.sys_trx_start, t2.en from t1, t2; insert into t2 values (1), (2); delete from t2 where y = 2; @@ -276,7 +307,7 @@ eval create or replace table t1 (a int) with system versioning engine $non_defau create or replace table t2 as select a, sys_trx_start, sys_trx_end from t1 for system_time all; --replace_result innodb INNODB_OR_MYISAM myisam INNODB_OR_MYISAM "BIGINT(20) UNSIGNED" SYS_TRX_TYPE "TIMESTAMP(6)" SYS_TRX_TYPE --error ER_VERS_FIELD_WRONG_TYPE -eval create or replace table t2 engine $default_engine as select a, sys_trx_start, sys_trx_end from t1 for system_time all; +eval create or replace table t2 with system versioning engine $default_engine as select a, sys_trx_start, sys_trx_end from t1 for system_time all; --replace_result innodb INNODB_OR_MYISAM myisam INNODB_OR_MYISAM eval create or replace table t1 (a int, id int) with system versioning engine $non_default_engine; @@ -284,10 +315,5 @@ create or replace table t2 (b int, id int); create or replace table t3 as select t2.b, t1.a, t1.sys_trx_start, t1.sys_trx_end from t2 inner join t1 on t2.id=t1.id; -drop table t1; -drop table t2; -drop table t3; - -drop function non_default_engine; - --- source suite/versioning/common_finish.inc +drop database test; +create database test; diff --git a/mysql-test/suite/versioning/t/sysvars.test b/mysql-test/suite/versioning/t/sysvars.test index 49ee14326f1..4516833d58d 100644 --- a/mysql-test/suite/versioning/t/sysvars.test +++ b/mysql-test/suite/versioning/t/sysvars.test @@ -101,7 +101,7 @@ create or replace table t ( with system versioning; show create table t; -insert into t values (1); +insert into t values (2); delete from t; select * from t; diff --git a/mysql-test/suite/versioning/t/vtmd.test b/mysql-test/suite/versioning/t/vtmd.test index 299d31ee036..01b68275737 100644 --- a/mysql-test/suite/versioning/t/vtmd.test +++ b/mysql-test/suite/versioning/t/vtmd.test @@ -36,7 +36,7 @@ create or replace procedure check_vtmd (in vtmd_name varchar(64)) begin set @tmp= concat(' create or replace temporary table - tmp_vtmd as + tmp_vtmd with system versioning as select * from ', vtmd_name, ' as vtmd for system_time all'); prepare stmt from @tmp; execute stmt; drop prepare stmt; diff --git a/sql/handler.cc b/sql/handler.cc index 3589c3aee19..0bf4f766dac 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6675,31 +6675,31 @@ bool Vers_parse_info::check_and_fix_implicit( if (table->table && table->table->versioned()) vers_tables++; } - - // Possibly override default storage engine to match - // one used in source table. - if (!(create_info->used_fields & HA_CREATE_USED_ENGINE)) - { - List_iterator_fast it(alter_info->create_list); - while (Create_field *f= it++) - { - if (is_trx_start(*f) || is_trx_end(*f)) - { - create_info->db_type= f->field->orig_table->file->ht; - break; - } - } - } } // CREATE ... SELECT: if at least one table in SELECT is versioned, // then created table will be versioned. - if (thd->variables.vers_force || vers_tables > 0) + if (thd->variables.vers_force) { with_system_versioning= true; create_info->options|= HA_VERSIONED_TABLE; } + // Possibly override default storage engine to match one used in source table. + if (from_select && with_system_versioning && + !(create_info->used_fields & HA_CREATE_USED_ENGINE)) + { + List_iterator_fast it(alter_info->create_list); + while (Create_field *f= it++) + { + if (is_trx_start(*f) || is_trx_end(*f)) + { + create_info->db_type= f->field->orig_table->file->ht; + break; + } + } + } + if (!need_check()) return false; @@ -6764,22 +6764,7 @@ bool Vers_parse_info::check_and_fix_implicit( bool integer_fields= create_info->db_type->flags & HTON_NATIVE_SYS_VERSIONING; - if (vers_tables > 0) - { - if (!generated_as_row.start && !generated_as_row.end) - { - with_system_versioning= false; - create_info->options&= ~HA_VERSIONED_TABLE; - return false; - } - if (!generated_as_row.start || !generated_as_row.end) - { - my_error_as(ER_VERS_WRONG_PARAMS, ER_MISSING, MYF(0), table_name, - generated_as_row.start ? "AS ROW END" : "AS ROW START"); - return true; - } - } - else if (fix_implicit(thd, alter_info, integer_fields)) + if (fix_implicit(thd, alter_info, integer_fields)) return true; int plain_cols= 0; // column doesn't have WITH or WITHOUT SYSTEM VERSIONING diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 8cdc835c0df..238fa3a0fa4 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7596,16 +7596,25 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, tl->vers_conditions.type == FOR_SYSTEM_TIME_UNSPECIFIED ? slex->vers_conditions.type : tl->vers_conditions.type; - if ((sys_field && (thd->lex->sql_command == SQLCOM_CREATE_VIEW || - slex->nest_level > 0 || - (vers_hide == VERS_HIDE_FULL && thd->lex->sql_command != SQLCOM_CREATE_TABLE))) || - ((fl & HIDDEN_FLAG) && ( - !sys_field || - vers_hide == VERS_HIDE_IMPLICIT || - (vers_hide == VERS_HIDE_AUTO && ( - vers_type == FOR_SYSTEM_TIME_UNSPECIFIED || - vers_type == FOR_SYSTEM_TIME_AS_OF))))) + enum_sql_command sql_command= thd->lex->sql_command; + unsigned int create_options= thd->lex->create_info.options; + + if ( + sql_command == SQLCOM_CREATE_TABLE ? + sys_field && !(create_options & HA_VERSIONED_TABLE) : ( + sys_field ? + (sql_command == SQLCOM_CREATE_VIEW || + slex->nest_level > 0 || + vers_hide == VERS_HIDE_FULL || + ((fl & HIDDEN_FLAG) && ( + vers_hide == VERS_HIDE_IMPLICIT || + (vers_hide == VERS_HIDE_AUTO && ( + vers_type == FOR_SYSTEM_TIME_UNSPECIFIED || + vers_type == FOR_SYSTEM_TIME_AS_OF))))) : + (fl & HIDDEN_FLAG))) + { continue; + } } else if (item->type() == Item::REF_ITEM) { -- cgit v1.2.1 From bdcce58fad395282d072b6b52428ab73531b507a Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 4 Jul 2017 12:05:40 +0300 Subject: IB: long names in information_schema --- mysql-test/suite/versioning/common.inc | 14 +++--- mysql-test/suite/versioning/r/alter.result | 14 +++--- .../suite/versioning/r/auto_increment.result | 14 +++--- mysql-test/suite/versioning/r/commit_id.result | 42 ++++++++-------- mysql-test/suite/versioning/r/create.result | 14 +++--- mysql-test/suite/versioning/r/ddl.result | 14 +++--- mysql-test/suite/versioning/r/delete.result | 14 +++--- mysql-test/suite/versioning/r/insert.result | 14 +++--- mysql-test/suite/versioning/r/partition.result | 14 +++--- mysql-test/suite/versioning/r/select.result | 14 +++--- mysql-test/suite/versioning/r/update.result | 14 +++--- mysql-test/suite/versioning/t/commit_id.test | 14 +++--- storage/innobase/handler/i_s.cc | 58 +++++++++++++++------- 13 files changed, 137 insertions(+), 117 deletions(-) diff --git a/mysql-test/suite/versioning/common.inc b/mysql-test/suite/versioning/common.inc index d9f83f5fea9..288c188c43d 100644 --- a/mysql-test/suite/versioning/common.inc +++ b/mysql-test/suite/versioning/common.inc @@ -1,5 +1,5 @@ set @@session.time_zone='+00:00'; -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; delimiter ~~; create procedure if not exists verify_vtq() @@ -7,13 +7,13 @@ begin set @i= 0; select @i:= @i + 1 as No, - trx_id > 0 as A, - commit_id > trx_id as B, - begin_ts > '1-1-1 0:0:0' as C, - commit_ts >= begin_ts as D + transaction_id > 0 as A, + commit_id > transaction_id as B, + begin_timestamp > '1-1-1 0:0:0' as C, + commit_timestamp >= begin_timestamp as D from information_schema.innodb_vtq - where trx_id > @start_trx_id; - select ifnull(max(trx_id), 0) + where transaction_id > @start_trx_id; + select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; end~~ diff --git a/mysql-test/suite/versioning/r/alter.result b/mysql-test/suite/versioning/r/alter.result index 924560c3a6e..5dff4e706cb 100644 --- a/mysql-test/suite/versioning/r/alter.result +++ b/mysql-test/suite/versioning/r/alter.result @@ -251,19 +251,19 @@ t CREATE TABLE `t` ( PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING set @@session.time_zone='+00:00'; -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; create procedure if not exists verify_vtq() begin set @i= 0; select @i:= @i + 1 as No, -trx_id > 0 as A, -commit_id > trx_id as B, -begin_ts > '1-1-1 0:0:0' as C, -commit_ts >= begin_ts as D +transaction_id > 0 as A, +commit_id > transaction_id as B, +begin_timestamp > '1-1-1 0:0:0' as C, +commit_timestamp >= begin_timestamp as D from information_schema.innodb_vtq -where trx_id > @start_trx_id; -select ifnull(max(trx_id), 0) +where transaction_id > @start_trx_id; +select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; end~~ diff --git a/mysql-test/suite/versioning/r/auto_increment.result b/mysql-test/suite/versioning/r/auto_increment.result index e9e487c40a3..31604a62740 100644 --- a/mysql-test/suite/versioning/r/auto_increment.result +++ b/mysql-test/suite/versioning/r/auto_increment.result @@ -1,17 +1,17 @@ set @@session.time_zone='+00:00'; -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; create procedure if not exists verify_vtq() begin set @i= 0; select @i:= @i + 1 as No, -trx_id > 0 as A, -commit_id > trx_id as B, -begin_ts > '1-1-1 0:0:0' as C, -commit_ts >= begin_ts as D +transaction_id > 0 as A, +commit_id > transaction_id as B, +begin_timestamp > '1-1-1 0:0:0' as C, +commit_timestamp >= begin_timestamp as D from information_schema.innodb_vtq -where trx_id > @start_trx_id; -select ifnull(max(trx_id), 0) +where transaction_id > @start_trx_id; +select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; end~~ diff --git a/mysql-test/suite/versioning/r/commit_id.result b/mysql-test/suite/versioning/r/commit_id.result index 543840df1f8..a9de17cb74c 100644 --- a/mysql-test/suite/versioning/r/commit_id.result +++ b/mysql-test/suite/versioning/r/commit_id.result @@ -1,17 +1,17 @@ set @@session.time_zone='+00:00'; -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; create procedure if not exists verify_vtq() begin set @i= 0; select @i:= @i + 1 as No, -trx_id > 0 as A, -commit_id > trx_id as B, -begin_ts > '1-1-1 0:0:0' as C, -commit_ts >= begin_ts as D +transaction_id > 0 as A, +commit_id > transaction_id as B, +begin_timestamp > '1-1-1 0:0:0' as C, +commit_timestamp >= begin_timestamp as D from information_schema.innodb_vtq -where trx_id > @start_trx_id; -select ifnull(max(trx_id), 0) +where transaction_id > @start_trx_id; +select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; end~~ @@ -68,20 +68,20 @@ insert into t1 values (); set @ts0= now(6); insert into t1 values (); select sys_trx_start from t1 where id = last_insert_id() into @tx0; -select trx_id = @tx0 from information_schema.innodb_vtq limit 1; -trx_id = @tx0 +select transaction_id = @tx0 from information_schema.innodb_vtq limit 1; +transaction_id = @tx0 1 set @ts1= now(6); insert into t1 values (); select sys_trx_start from t1 where id = last_insert_id() into @tx1; -select trx_id = @tx1 from information_schema.innodb_vtq limit 1; -trx_id = @tx1 +select transaction_id = @tx1 from information_schema.innodb_vtq limit 1; +transaction_id = @tx1 1 set @ts2= now(6); insert into t1 values (); select sys_trx_start from t1 where id = last_insert_id() into @tx2; -select trx_id = @tx2 from information_schema.innodb_vtq limit 1; -trx_id = @tx2 +select transaction_id = @tx2 from information_schema.innodb_vtq limit 1; +transaction_id = @tx2 1 set @ts3= now(6); select @@ -119,26 +119,26 @@ A B C D E F H set transaction isolation level read uncommitted; insert into t1 values (); select sys_trx_start from t1 where id = last_insert_id() into @tx3; -select iso_level = 'RU' from information_schema.innodb_vtq where trx_id = @tx3; -iso_level = 'RU' +select isolation_level = 'READ-UNCOMMITTED' from information_schema.innodb_vtq where transaction_id = @tx3; +isolation_level = 'READ-UNCOMMITTED' 1 set transaction isolation level read committed; insert into t1 values (); select sys_trx_start from t1 where id = last_insert_id() into @tx4; -select iso_level = 'RC' from information_schema.innodb_vtq where trx_id = @tx4; -iso_level = 'RC' +select isolation_level = 'READ-COMMITTED' from information_schema.innodb_vtq where transaction_id = @tx4; +isolation_level = 'READ-COMMITTED' 1 set transaction isolation level serializable; insert into t1 values (); select sys_trx_start from t1 where id = last_insert_id() into @tx5; -select iso_level = 'S' from information_schema.innodb_vtq where trx_id = @tx5; -iso_level = 'S' +select isolation_level = 'SERIALIZABLE' from information_schema.innodb_vtq where transaction_id = @tx5; +isolation_level = 'SERIALIZABLE' 1 set transaction isolation level repeatable read; insert into t1 values (); select sys_trx_start from t1 where id = last_insert_id() into @tx6; -select iso_level = 'RR' from information_schema.innodb_vtq where trx_id = @tx6; -iso_level = 'RR' +select isolation_level = 'REPEATABLE-READ' from information_schema.innodb_vtq where transaction_id = @tx6; +isolation_level = 'REPEATABLE-READ' 1 drop table t1; call verify_vtq; diff --git a/mysql-test/suite/versioning/r/create.result b/mysql-test/suite/versioning/r/create.result index e4341223ef5..97e2a336513 100644 --- a/mysql-test/suite/versioning/r/create.result +++ b/mysql-test/suite/versioning/r/create.result @@ -1,17 +1,17 @@ set @@session.time_zone='+00:00'; -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; create procedure if not exists verify_vtq() begin set @i= 0; select @i:= @i + 1 as No, -trx_id > 0 as A, -commit_id > trx_id as B, -begin_ts > '1-1-1 0:0:0' as C, -commit_ts >= begin_ts as D +transaction_id > 0 as A, +commit_id > transaction_id as B, +begin_timestamp > '1-1-1 0:0:0' as C, +commit_timestamp >= begin_timestamp as D from information_schema.innodb_vtq -where trx_id > @start_trx_id; -select ifnull(max(trx_id), 0) +where transaction_id > @start_trx_id; +select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; end~~ diff --git a/mysql-test/suite/versioning/r/ddl.result b/mysql-test/suite/versioning/r/ddl.result index 36998f7bc98..23e8c6d6dc5 100644 --- a/mysql-test/suite/versioning/r/ddl.result +++ b/mysql-test/suite/versioning/r/ddl.result @@ -1,17 +1,17 @@ set @@session.time_zone='+00:00'; -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; create procedure if not exists verify_vtq() begin set @i= 0; select @i:= @i + 1 as No, -trx_id > 0 as A, -commit_id > trx_id as B, -begin_ts > '1-1-1 0:0:0' as C, -commit_ts >= begin_ts as D +transaction_id > 0 as A, +commit_id > transaction_id as B, +begin_timestamp > '1-1-1 0:0:0' as C, +commit_timestamp >= begin_timestamp as D from information_schema.innodb_vtq -where trx_id > @start_trx_id; -select ifnull(max(trx_id), 0) +where transaction_id > @start_trx_id; +select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; end~~ diff --git a/mysql-test/suite/versioning/r/delete.result b/mysql-test/suite/versioning/r/delete.result index 2c5e4138c00..354543bf0ab 100644 --- a/mysql-test/suite/versioning/r/delete.result +++ b/mysql-test/suite/versioning/r/delete.result @@ -1,17 +1,17 @@ set @@session.time_zone='+00:00'; -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; create procedure if not exists verify_vtq() begin set @i= 0; select @i:= @i + 1 as No, -trx_id > 0 as A, -commit_id > trx_id as B, -begin_ts > '1-1-1 0:0:0' as C, -commit_ts >= begin_ts as D +transaction_id > 0 as A, +commit_id > transaction_id as B, +begin_timestamp > '1-1-1 0:0:0' as C, +commit_timestamp >= begin_timestamp as D from information_schema.innodb_vtq -where trx_id > @start_trx_id; -select ifnull(max(trx_id), 0) +where transaction_id > @start_trx_id; +select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; end~~ diff --git a/mysql-test/suite/versioning/r/insert.result b/mysql-test/suite/versioning/r/insert.result index 0332018ff9b..e6cf8954f26 100644 --- a/mysql-test/suite/versioning/r/insert.result +++ b/mysql-test/suite/versioning/r/insert.result @@ -1,17 +1,17 @@ set @@session.time_zone='+00:00'; -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; create procedure if not exists verify_vtq() begin set @i= 0; select @i:= @i + 1 as No, -trx_id > 0 as A, -commit_id > trx_id as B, -begin_ts > '1-1-1 0:0:0' as C, -commit_ts >= begin_ts as D +transaction_id > 0 as A, +commit_id > transaction_id as B, +begin_timestamp > '1-1-1 0:0:0' as C, +commit_timestamp >= begin_timestamp as D from information_schema.innodb_vtq -where trx_id > @start_trx_id; -select ifnull(max(trx_id), 0) +where transaction_id > @start_trx_id; +select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; end~~ diff --git a/mysql-test/suite/versioning/r/partition.result b/mysql-test/suite/versioning/r/partition.result index 8daefaeff85..a2aab637f31 100644 --- a/mysql-test/suite/versioning/r/partition.result +++ b/mysql-test/suite/versioning/r/partition.result @@ -1,17 +1,17 @@ set @@session.time_zone='+00:00'; -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; create procedure if not exists verify_vtq() begin set @i= 0; select @i:= @i + 1 as No, -trx_id > 0 as A, -commit_id > trx_id as B, -begin_ts > '1-1-1 0:0:0' as C, -commit_ts >= begin_ts as D +transaction_id > 0 as A, +commit_id > transaction_id as B, +begin_timestamp > '1-1-1 0:0:0' as C, +commit_timestamp >= begin_timestamp as D from information_schema.innodb_vtq -where trx_id > @start_trx_id; -select ifnull(max(trx_id), 0) +where transaction_id > @start_trx_id; +select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; end~~ diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index d6a471506ee..39a5880250a 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -1,17 +1,17 @@ set @@session.time_zone='+00:00'; -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; create procedure if not exists verify_vtq() begin set @i= 0; select @i:= @i + 1 as No, -trx_id > 0 as A, -commit_id > trx_id as B, -begin_ts > '1-1-1 0:0:0' as C, -commit_ts >= begin_ts as D +transaction_id > 0 as A, +commit_id > transaction_id as B, +begin_timestamp > '1-1-1 0:0:0' as C, +commit_timestamp >= begin_timestamp as D from information_schema.innodb_vtq -where trx_id > @start_trx_id; -select ifnull(max(trx_id), 0) +where transaction_id > @start_trx_id; +select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; end~~ diff --git a/mysql-test/suite/versioning/r/update.result b/mysql-test/suite/versioning/r/update.result index 3c62fa0a14b..48b3eec3c3d 100644 --- a/mysql-test/suite/versioning/r/update.result +++ b/mysql-test/suite/versioning/r/update.result @@ -1,17 +1,17 @@ set @@session.time_zone='+00:00'; -select ifnull(max(trx_id), 0) into @start_trx_id from information_schema.innodb_vtq; +select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; create procedure if not exists verify_vtq() begin set @i= 0; select @i:= @i + 1 as No, -trx_id > 0 as A, -commit_id > trx_id as B, -begin_ts > '1-1-1 0:0:0' as C, -commit_ts >= begin_ts as D +transaction_id > 0 as A, +commit_id > transaction_id as B, +begin_timestamp > '1-1-1 0:0:0' as C, +commit_timestamp >= begin_timestamp as D from information_schema.innodb_vtq -where trx_id > @start_trx_id; -select ifnull(max(trx_id), 0) +where transaction_id > @start_trx_id; +select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; end~~ diff --git a/mysql-test/suite/versioning/t/commit_id.test b/mysql-test/suite/versioning/t/commit_id.test index efecf55c143..fa44958470c 100644 --- a/mysql-test/suite/versioning/t/commit_id.test +++ b/mysql-test/suite/versioning/t/commit_id.test @@ -13,17 +13,17 @@ insert into t1 values (); set @ts0= now(6); insert into t1 values (); select sys_trx_start from t1 where id = last_insert_id() into @tx0; -select trx_id = @tx0 from information_schema.innodb_vtq limit 1; +select transaction_id = @tx0 from information_schema.innodb_vtq limit 1; set @ts1= now(6); insert into t1 values (); select sys_trx_start from t1 where id = last_insert_id() into @tx1; -select trx_id = @tx1 from information_schema.innodb_vtq limit 1; +select transaction_id = @tx1 from information_schema.innodb_vtq limit 1; set @ts2= now(6); insert into t1 values (); select sys_trx_start from t1 where id = last_insert_id() into @tx2; -select trx_id = @tx2 from information_schema.innodb_vtq limit 1; +select transaction_id = @tx2 from information_schema.innodb_vtq limit 1; set @ts3= now(6); @@ -62,22 +62,22 @@ select set transaction isolation level read uncommitted; insert into t1 values (); select sys_trx_start from t1 where id = last_insert_id() into @tx3; -select iso_level = 'RU' from information_schema.innodb_vtq where trx_id = @tx3; +select isolation_level = 'READ-UNCOMMITTED' from information_schema.innodb_vtq where transaction_id = @tx3; set transaction isolation level read committed; insert into t1 values (); select sys_trx_start from t1 where id = last_insert_id() into @tx4; -select iso_level = 'RC' from information_schema.innodb_vtq where trx_id = @tx4; +select isolation_level = 'READ-COMMITTED' from information_schema.innodb_vtq where transaction_id = @tx4; set transaction isolation level serializable; insert into t1 values (); select sys_trx_start from t1 where id = last_insert_id() into @tx5; -select iso_level = 'S' from information_schema.innodb_vtq where trx_id = @tx5; +select isolation_level = 'SERIALIZABLE' from information_schema.innodb_vtq where transaction_id = @tx5; set transaction isolation level repeatable read; insert into t1 values (); select sys_trx_start from t1 where id = last_insert_id() into @tx6; -select iso_level = 'RR' from information_schema.innodb_vtq where trx_id = @tx6; +select isolation_level = 'REPEATABLE-READ' from information_schema.innodb_vtq where transaction_id = @tx6; drop table t1; diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index 436cea7fe4b..b7f24d34de5 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -9661,7 +9661,7 @@ UNIV_INTERN struct st_maria_plugin i_s_innodb_sys_semaphore_waits = static ST_FIELD_INFO innodb_vtq_fields_info[] = { #define SYS_VTQ_TRX_ID 0 - { STRUCT_FLD(field_name, "trx_id"), + { STRUCT_FLD(field_name, "transaction_id"), STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), STRUCT_FLD(value, 0), @@ -9679,7 +9679,7 @@ static ST_FIELD_INFO innodb_vtq_fields_info[] = STRUCT_FLD(open_method, SKIP_OPEN_TABLE) }, #define SYS_VTQ_BEGIN_TS 2 - { STRUCT_FLD(field_name, "begin_ts"), + { STRUCT_FLD(field_name, "begin_timestamp"), STRUCT_FLD(field_length, 6), STRUCT_FLD(field_type, MYSQL_TYPE_TIMESTAMP), STRUCT_FLD(value, 0), @@ -9688,7 +9688,7 @@ static ST_FIELD_INFO innodb_vtq_fields_info[] = STRUCT_FLD(open_method, SKIP_OPEN_TABLE) }, #define SYS_VTQ_COMMIT_TS 3 - { STRUCT_FLD(field_name, "commit_ts"), + { STRUCT_FLD(field_name, "commit_timestamp"), STRUCT_FLD(field_length, 6), STRUCT_FLD(field_type, MYSQL_TYPE_TIMESTAMP), STRUCT_FLD(value, 0), @@ -9697,8 +9697,8 @@ static ST_FIELD_INFO innodb_vtq_fields_info[] = STRUCT_FLD(open_method, SKIP_OPEN_TABLE) }, #define SYS_VTQ_ISO_LEVEL 4 - { STRUCT_FLD(field_name, "iso_level"), - STRUCT_FLD(field_length, 2), + { STRUCT_FLD(field_name, "isolation_level"), + STRUCT_FLD(field_length, 16), STRUCT_FLD(field_type, MYSQL_TYPE_STRING), STRUCT_FLD(value, 0), STRUCT_FLD(field_flags, 0), @@ -9708,6 +9708,39 @@ static ST_FIELD_INFO innodb_vtq_fields_info[] = END_OF_ST_FIELD_INFO }; +/******************************************************************//** +Maps a InnoDB trx isolation level code to the MySQL isolation level name +@return MySQL isolation level name */ +static inline +const char* +i_s_isolation_name( +/*=========================*/ + ulint iso) /*!< in: InnoDB isolation level code */ +{ + enum_tx_isolation mysql_iso; + + switch (iso) { + case TRX_ISO_REPEATABLE_READ: + mysql_iso = ISO_REPEATABLE_READ; + break; + case TRX_ISO_READ_COMMITTED: + mysql_iso = ISO_READ_COMMITTED; + break; + case TRX_ISO_SERIALIZABLE: + mysql_iso = ISO_SERIALIZABLE; + break; + case TRX_ISO_READ_UNCOMMITTED: + mysql_iso = ISO_READ_UNCOMMITTED; + break; + default: + ut_error; + return NULL; + } + + return tx_isolation_names[mysql_iso]; +} + + /**********************************************************************//** Function to fill INFORMATION_SCHEMA.INNODB_SYS_VTQ with information collected by scanning SYS_VTQ table. @@ -9726,20 +9759,7 @@ i_s_dict_fill_vtq( DBUG_ENTER("i_s_dict_fill_vtq"); fields = table_to_fill->field; - switch (vtq.iso_level) { - case TRX_ISO_REPEATABLE_READ: - iso_level = "RR"; - break; - case TRX_ISO_READ_COMMITTED: - iso_level = "RC"; - break; - case TRX_ISO_SERIALIZABLE: - iso_level = "S"; - break; - case TRX_ISO_READ_UNCOMMITTED: - iso_level = "RU"; - break; - } + iso_level = i_s_isolation_name(vtq.iso_level); OK(field_store_ullong(fields[SYS_VTQ_TRX_ID], vtq.trx_id)); OK(field_store_ullong(fields[SYS_VTQ_COMMIT_ID], vtq.commit_id)); -- cgit v1.2.1 From 1903b407da2fc74fb3dc90351b1a92edaeff8874 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Tue, 4 Jul 2017 17:45:14 +0300 Subject: SQL: ignore columns WITHOUT VERSIONING [fixes #220] --- mysql-test/suite/versioning/r/create.result | 2 -- mysql-test/suite/versioning/t/create.test | 2 -- sql/handler.cc | 54 ++++++++++++++++------------- sql/handler.h | 16 ++++----- sql/sql_table.cc | 6 ++-- sql/sql_yacc.yy | 4 +-- sql/unireg.cc | 6 ++-- 7 files changed, 45 insertions(+), 45 deletions(-) diff --git a/mysql-test/suite/versioning/r/create.result b/mysql-test/suite/versioning/r/create.result index 97e2a336513..32b8d1c97a7 100644 --- a/mysql-test/suite/versioning/r/create.result +++ b/mysql-test/suite/versioning/r/create.result @@ -211,7 +211,6 @@ create or replace table t1 ( A3 int, B int without system versioning ); -ERROR HY000: Wrong parameters for `t1`: missing 'WITH SYSTEM VERSIONING' create or replace table t1 ( A4 int, B int without system versioning @@ -254,7 +253,6 @@ t1 CREATE TABLE `t1` ( create or replace table t1 ( A7 int without system versioning ); -ERROR HY000: Wrong parameters for `t1`: missing 'WITH SYSTEM VERSIONING' create or replace table t1 ( A8 int without system versioning ) with system versioning; diff --git a/mysql-test/suite/versioning/t/create.test b/mysql-test/suite/versioning/t/create.test index 032c75b64ef..9c92cc30e2c 100644 --- a/mysql-test/suite/versioning/t/create.test +++ b/mysql-test/suite/versioning/t/create.test @@ -157,7 +157,6 @@ create or replace table t1 ( --replace_result InnoDB INNODB_OR_MYISAM MyISAM INNODB_OR_MYISAM "bigint(20) unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE show create table t1; ---error ER_VERS_WRONG_PARAMS create or replace table t1 ( A3 int, B int without system versioning @@ -184,7 +183,6 @@ create or replace table t1 ( --replace_result InnoDB INNODB_OR_MYISAM MyISAM INNODB_OR_MYISAM "bigint(20) unsigned" SYS_TRX_TYPE timestamp(6) SYS_TRX_TYPE show create table t1; ---error ER_VERS_WRONG_PARAMS create or replace table t1 ( A7 int without system versioning ); diff --git a/sql/handler.cc b/sql/handler.cc index 0bf4f766dac..ae685482219 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6584,12 +6584,12 @@ int del_global_index_stat(THD *thd, TABLE* table, KEY* key_info) bool Vers_parse_info::is_trx_start(const char *name) const { DBUG_ASSERT(name); - return generated_as_row.start && generated_as_row.start == LString_i(name); + return as_row.start && as_row.start == LString_i(name); } bool Vers_parse_info::is_trx_end(const char *name) const { DBUG_ASSERT(name); - return generated_as_row.end && generated_as_row.end == LString_i(name); + return as_row.end && as_row.end == LString_i(name); } bool Vers_parse_info::is_trx_start(const Create_field &f) const { @@ -6638,8 +6638,7 @@ bool Vers_parse_info::fix_implicit(THD *thd, Alter_info *alter_info, bool integer_fields) { // If user specified some of these he must specify the others too. Do nothing. - if (generated_as_row.start || generated_as_row.end || - period_for_system_time.start || period_for_system_time.end) + if (as_row.start || as_row.end || system_time.start || system_time.end) return false; alter_info->flags|= Alter_info::ALTER_ADD_COLUMN; @@ -6647,8 +6646,8 @@ bool Vers_parse_info::fix_implicit(THD *thd, Alter_info *alter_info, static const LString sys_trx_start= "sys_trx_start"; static const LString sys_trx_end= "sys_trx_end"; - period_for_system_time= start_end_t(sys_trx_start, sys_trx_end); - generated_as_row= period_for_system_time; + system_time= start_end_t(sys_trx_start, sys_trx_end); + as_row= system_time; return vers_create_sys_field(thd, sys_trx_start, alter_info, VERS_SYS_START_FLAG, @@ -6703,6 +6702,13 @@ bool Vers_parse_info::check_and_fix_implicit( if (!need_check()) return false; + if (!versioned_fields && unversioned_fields && !with_system_versioning) + { + // All is correct but this table is not versioned. + create_info->options&= ~HA_VERSIONED_TABLE; + return false; + } + if (without_system_versioning) { my_error_as(ER_VERS_WRONG_PARAMS, ER_NOT_ALLOWED, MYF(0), table_name, @@ -6710,7 +6716,8 @@ bool Vers_parse_info::check_and_fix_implicit( return true; } - if (!with_system_versioning && !versioned_fields) + if ((system_time.start || system_time.end || as_row.start || as_row.end) && + !with_system_versioning) { my_error_as(ER_VERS_WRONG_PARAMS, ER_MISSING, MYF(0), table_name, "WITH SYSTEM VERSIONING"); @@ -6723,7 +6730,7 @@ bool Vers_parse_info::check_and_fix_implicit( { if (is_trx_start(*f)) { - if (!generated_as_row.start) // not inited in CREATE ... SELECT + if (!as_row.start) // not inited in CREATE ... SELECT { DBUG_ASSERT(vers_tables > 0); if (orig_table && orig_table != f->field->orig_table) @@ -6733,14 +6740,14 @@ bool Vers_parse_info::check_and_fix_implicit( return true; } orig_table= f->field->orig_table; - generated_as_row.start= f->field_name; - period_for_system_time.start= generated_as_row.start; + as_row.start= f->field_name; + system_time.start= as_row.start; } continue; } if (is_trx_end(*f)) { - if (!generated_as_row.end) + if (!as_row.end) { DBUG_ASSERT(vers_tables > 0); if (orig_table && orig_table != f->field->orig_table) @@ -6748,8 +6755,8 @@ bool Vers_parse_info::check_and_fix_implicit( goto err_different_tables; } orig_table= f->field->orig_table; - generated_as_row.end= f->field_name; - period_for_system_time.end= generated_as_row.end; + as_row.end= f->field_name; + system_time.end= as_row.end; } continue; } @@ -6782,8 +6789,7 @@ bool Vers_parse_info::check_and_fix_implicit( } bool table_with_system_versioning= - generated_as_row.start || generated_as_row.end || - period_for_system_time.start || period_for_system_time.end; + as_row.start || as_row.end || system_time.start || system_time.end; if (!thd->lex->tmp_table() && // CREATE from SELECT (Create_fields are not yet added) @@ -6853,8 +6859,8 @@ bool Vers_parse_info::check_and_fix_alter(THD *thd, Alter_info *alter_info, const char *end= share->vers_end_field()->field_name; DBUG_ASSERT(start && end); - generated_as_row= start_end_t(start, end); - period_for_system_time= generated_as_row; + as_row= start_end_t(start, end); + system_time= as_row; if (alter_info->create_list.elements) { @@ -6945,8 +6951,8 @@ bool Vers_parse_info::fix_create_like(THD *thd, Alter_info *alter_info, return true; } - generated_as_row= start_end_t(f_start->field_name, f_end->field_name); - period_for_system_time= generated_as_row; + as_row= start_end_t(f_start->field_name, f_end->field_name); + system_time= as_row; create_info->options|= HA_VERSIONED_TABLE; return false; @@ -6955,28 +6961,28 @@ bool Vers_parse_info::fix_create_like(THD *thd, Alter_info *alter_info, bool Vers_parse_info::check_with_conditions(const char *table_name) const { - if (!generated_as_row.start || !generated_as_row.end) + if (!as_row.start || !as_row.end) { my_error_as(ER_VERS_WRONG_PARAMS, ER_MISSING, MYF(0), table_name, - generated_as_row.start ? "AS ROW END" : "AS ROW START"); + as_row.start ? "AS ROW END" : "AS ROW START"); return true; } - if (!period_for_system_time.start || !period_for_system_time.end) + if (!system_time.start || !system_time.end) { my_error_as(ER_VERS_WRONG_PARAMS, ER_MISSING, MYF(0), table_name, "PERIOD FOR SYSTEM_TIME"); return true; } - if (generated_as_row.start != period_for_system_time.start) + if (as_row.start != system_time.start) { my_error_as(ER_VERS_WRONG_PARAMS, ER_MISMATCH, MYF(0), table_name, "PERIOD FOR SYSTEM_TIME", "AS ROW START"); return true; } - if (generated_as_row.end != period_for_system_time.end) + if (as_row.end != system_time.end) { my_error_as(ER_VERS_WRONG_PARAMS, ER_MISMATCH, MYF(0), table_name, "PERIOD FOR SYSTEM_TIME", "AS ROW END"); diff --git a/sql/handler.h b/sql/handler.h index 5462b33a3aa..24d1a73ec92 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1694,13 +1694,13 @@ struct Vers_parse_info LString_i end; }; - start_end_t period_for_system_time; - start_end_t generated_as_row; + start_end_t system_time; + start_end_t as_row; void set_period_for_system_time(LString start, LString end) { - period_for_system_time.start = start; - period_for_system_time.end = end; + system_time.start = start; + system_time.end = end; } private: @@ -1716,10 +1716,10 @@ private: unversioned_fields || with_system_versioning || without_system_versioning || - period_for_system_time.start.str || - period_for_system_time.end.str || - generated_as_row.start.str || - generated_as_row.end.str; + system_time.start || + system_time.end || + as_row.start || + as_row.end; } bool check_with_conditions(const char *table_name) const; bool check_generated_type(const char *table_name, Alter_info *alter_info, diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 9728b2d77e8..cb4bb052a65 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4326,9 +4326,9 @@ vers_prepare_keys(THD *thd, { DBUG_ASSERT(create_info->versioned()); - const char *row_start_field= create_info->vers_info.generated_as_row.start; + const char *row_start_field= create_info->vers_info.as_row.start; DBUG_ASSERT(row_start_field); - const char *row_end_field= create_info->vers_info.generated_as_row.end; + const char *row_end_field= create_info->vers_info.as_row.end; DBUG_ASSERT(row_end_field); List_iterator key_it(alter_info->key_list); @@ -4355,7 +4355,7 @@ vers_prepare_keys(THD *thd, continue; // Key already contains Sys_start or Sys_end Key_part_spec *key_part_sys_end_col= - new(thd->mem_root) Key_part_spec(create_info->vers_info.generated_as_row.end, 0); + new (thd->mem_root) Key_part_spec(create_info->vers_info.as_row.end, 0); key->columns.push_back(key_part_sys_end_col); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 8b3014f301a..b0365d2b97f 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -6305,12 +6305,12 @@ field_def: switch ($4) { case 1: - p= &info.generated_as_row.start; + p= &info.as_row.start; clause= "AS ROW START"; lex->last_field->flags|= VERS_SYS_START_FLAG; break; case 0: - p= &info.generated_as_row.end; + p= &info.as_row.end; clause= "AS ROW END"; lex->last_field->flags|= VERS_SYS_END_FLAG; break; diff --git a/sql/unireg.cc b/sql/unireg.cc index 7a5aadb1c22..b647a284b14 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -99,10 +99,8 @@ vers_get_field(HA_CREATE_INFO *create_info, List &create_fields, b List_iterator it(create_fields); Create_field *sql_field = NULL; - const char *row_field = - row_start ? - create_info->vers_info.generated_as_row.start : - create_info->vers_info.generated_as_row.end; + const char *row_field= row_start ? create_info->vers_info.as_row.start + : create_info->vers_info.as_row.end; DBUG_ASSERT(row_field); for (unsigned field_no = 0; (sql_field = it++); ++field_no) -- cgit v1.2.1 From 42a0289de9789979fedd51240be52347c5330995 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Thu, 6 Jul 2017 15:22:10 +0300 Subject: Tests: optimized fields --- mysql-test/suite/versioning/r/optimized_fields.result | 6 ++++++ mysql-test/suite/versioning/t/optimized_fields.test | 1 + 2 files changed, 7 insertions(+) diff --git a/mysql-test/suite/versioning/r/optimized_fields.result b/mysql-test/suite/versioning/r/optimized_fields.result index 20fab121a69..4878f21b1f5 100644 --- a/mysql-test/suite/versioning/r/optimized_fields.result +++ b/mysql-test/suite/versioning/r/optimized_fields.result @@ -58,6 +58,12 @@ select a from t where b=NULL query for system_time as of timestamp now(6); a Warnings: Warning 4075 Attempt to read unversioned field `b` in historical query +select a from t where b is NULL query for system_time as of timestamp now(6); +a +1 +3 +Warnings: +Warning 4075 Attempt to read unversioned field `b` in historical query select count(*), b from t group by b having b=NULL query for system_time as of timestamp now(6); count(*) b Warnings: diff --git a/mysql-test/suite/versioning/t/optimized_fields.test b/mysql-test/suite/versioning/t/optimized_fields.test index 02f51423cc1..d1490d893a4 100644 --- a/mysql-test/suite/versioning/t/optimized_fields.test +++ b/mysql-test/suite/versioning/t/optimized_fields.test @@ -16,6 +16,7 @@ select * from t group by a having a=2 query for system_time as of timestamp now( select * from t group by b having b=2 query for system_time as of timestamp now(6); select a from t where b=2 query for system_time as of timestamp now(6); select a from t where b=NULL query for system_time as of timestamp now(6); +select a from t where b is NULL query for system_time as of timestamp now(6); select count(*), b from t group by b having b=NULL query for system_time as of timestamp now(6); select a, b from t; -- cgit v1.2.1 From dcb54040bcb6927e1fafe039979b816865c7c805 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Fri, 7 Jul 2017 17:52:23 +0300 Subject: SQL: VTQ testing iface moved to plugin [closes #224] --- mysql-test/suite/versioning/common.opt | 1 + mysql-test/suite/versioning/t/cte_recursive.opt | 1 + mysql-test/suite/versioning/t/simple.opt | 1 + mysql-test/suite/versioning/t/view.opt | 1 + plugin/versioning/versioning.cc | 196 +++++++++++++++++++++--- sql/item_create.cc | 169 ++------------------ sql/item_create.h | 40 +++++ sql/item_func.h | 3 + sql/item_vers.cc | 63 ++------ sql/item_vers.h | 24 ++- sql/sql_plugin.cc | 14 -- sql/sql_plugin.h | 2 - sql/sql_select.cc | 27 ++-- sql/vers_string.h | 4 + 14 files changed, 273 insertions(+), 273 deletions(-) diff --git a/mysql-test/suite/versioning/common.opt b/mysql-test/suite/versioning/common.opt index 5575069d6ee..132aab2d0ec 100644 --- a/mysql-test/suite/versioning/common.opt +++ b/mysql-test/suite/versioning/common.opt @@ -16,3 +16,4 @@ --innodb-sys-virtual --innodb-vtq --versioning-hide=implicit +--plugin-load=versioning diff --git a/mysql-test/suite/versioning/t/cte_recursive.opt b/mysql-test/suite/versioning/t/cte_recursive.opt index 3596fc4d3bd..993df05011e 100644 --- a/mysql-test/suite/versioning/t/cte_recursive.opt +++ b/mysql-test/suite/versioning/t/cte_recursive.opt @@ -1 +1,2 @@ --innodb --default-storage-engine=innodb +--plugin-load=versioning diff --git a/mysql-test/suite/versioning/t/simple.opt b/mysql-test/suite/versioning/t/simple.opt index 3596fc4d3bd..993df05011e 100644 --- a/mysql-test/suite/versioning/t/simple.opt +++ b/mysql-test/suite/versioning/t/simple.opt @@ -1 +1,2 @@ --innodb --default-storage-engine=innodb +--plugin-load=versioning diff --git a/mysql-test/suite/versioning/t/view.opt b/mysql-test/suite/versioning/t/view.opt index c1a585b67eb..9baff80804d 100644 --- a/mysql-test/suite/versioning/t/view.opt +++ b/mysql-test/suite/versioning/t/view.opt @@ -1 +1,2 @@ --versioning-hide=implicit +--plugin-load=versioning diff --git a/plugin/versioning/versioning.cc b/plugin/versioning/versioning.cc index 016367f89f4..fb8a8b8ee32 100644 --- a/plugin/versioning/versioning.cc +++ b/plugin/versioning/versioning.cc @@ -14,10 +14,144 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#define MYSQL_SERVER 1 #include #include +#include #include "sql_plugin.h" // st_plugin_int #include "sql_class.h" +#include "item.h" +#include "vtq.h" +#include "vers_utils.h" + +plugin_ref innodb_plugin= NULL; +static handlerton* innodb_hton= NULL; + +/* System Versioning: VTQ_TRX_ID(), VTQ_COMMIT_ID(), VTQ_BEGIN_TS(), VTQ_COMMIT_TS(), VTQ_ISO_LEVEL() */ +template +class Create_func_vtq : public Create_native_func +{ +public: + virtual Item *create_native(THD *thd, LEX_STRING name, List *item_list); + + static Create_func_vtq s_singleton; + +protected: + Create_func_vtq() {} + virtual ~Create_func_vtq() {} +}; + +template +Create_func_vtq Create_func_vtq::s_singleton; + +template +Item* +Create_func_vtq::create_native(THD *thd, LEX_STRING name, + List *item_list) +{ + Item *func= NULL; + int arg_count= 0; + + if (item_list != NULL) + arg_count= item_list->elements; + + switch (arg_count) { + case 1: + { + Item *param_1= item_list->pop(); + switch (VTQ_FIELD) + { + case VTQ_BEGIN_TS: + case VTQ_COMMIT_TS: + func= new (thd->mem_root) Item_func_vtq_ts(thd, innodb_hton, param_1, VTQ_FIELD); + break; + case VTQ_TRX_ID: + case VTQ_COMMIT_ID: + case VTQ_ISO_LEVEL: + func= new (thd->mem_root) Item_func_vtq_id(thd, innodb_hton, param_1, VTQ_FIELD); + break; + default: + DBUG_ASSERT(0); + } + break; + } + case 2: + { + Item *param_1= item_list->pop(); + Item *param_2= item_list->pop(); + switch (VTQ_FIELD) + { + case VTQ_TRX_ID: + case VTQ_COMMIT_ID: + func= new (thd->mem_root) Item_func_vtq_id(thd, innodb_hton, param_1, param_2, VTQ_FIELD); + break; + default: + goto error; + } + break; + } + error: + default: + { + my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str); + break; + } + } + + return func; +}; + +template +class Create_func_vtq_trx_sees : public Create_native_func +{ +public: + virtual Item *create_native(THD *thd, LEX_STRING name, List *item_list) + { + Item *func= NULL; + int arg_count= 0; + + if (item_list != NULL) + arg_count= item_list->elements; + + switch (arg_count) { + case 2: + { + Item *param_1= item_list->pop(); + Item *param_2= item_list->pop(); + func= new (thd->mem_root) Item_func_vtq_trx_seesX(thd, innodb_hton, param_1, param_2); + break; + } + default: + my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str); + break; + } + + return func; + } + + static Create_func_vtq_trx_sees s_singleton; + +protected: + Create_func_vtq_trx_sees() {} + virtual ~Create_func_vtq_trx_sees() {} +}; + +template +Create_func_vtq_trx_sees Create_func_vtq_trx_sees::s_singleton; + +#define BUILDER(F) & F::s_singleton + +static Native_func_registry func_array[] = +{ + { { C_STRING_WITH_LEN("VTQ_BEGIN_TS") }, BUILDER(Create_func_vtq)}, + { { C_STRING_WITH_LEN("VTQ_COMMIT_ID") }, BUILDER(Create_func_vtq)}, + { { C_STRING_WITH_LEN("VTQ_COMMIT_TS") }, BUILDER(Create_func_vtq)}, + { { C_STRING_WITH_LEN("VTQ_ISO_LEVEL") }, BUILDER(Create_func_vtq)}, + { { C_STRING_WITH_LEN("VTQ_TRX_ID") }, BUILDER(Create_func_vtq)}, + { { C_STRING_WITH_LEN("VTQ_TRX_SEES") }, BUILDER(Create_func_vtq_trx_sees)}, + { { C_STRING_WITH_LEN("VTQ_TRX_SEES_EQ") }, BUILDER(Create_func_vtq_trx_sees)} +}; + /* Disable __attribute__() on non-gcc compilers. @@ -26,45 +160,61 @@ #define __attribute__(A) #endif -static int forced_versioning_init(void *p __attribute__ ((unused))) +static int versioning_plugin_init(void *p __attribute__ ((unused))) { + static LString InnoDB= "InnoDB"; + + DBUG_ENTER("versioning_plugin_init"); + // No need in locking since we so far single-threaded + int res= item_create_append(func_array); + if (res) + { + my_message(ER_PLUGIN_IS_NOT_LOADED, "Can't append function array" , MYF(0)); + DBUG_RETURN(res); + } + + innodb_plugin= ha_resolve_by_name(NULL, &InnoDB.lex_string(), false); + if (!innodb_plugin) + { + my_error(ER_PLUGIN_IS_NOT_LOADED, MYF(0), InnoDB.ptr()); + DBUG_RETURN(1); + } + + innodb_hton= plugin_hton(innodb_plugin); + if (!innodb_hton || (innodb_hton->flags & HTON_NOT_USER_SELECTABLE)) + { + my_message(ER_PLUGIN_IS_NOT_LOADED, "Can't get handlerton" , MYF(0)); + DBUG_RETURN(1); + } - DBUG_ENTER("forced_versioning_init"); - mysql_mutex_lock(&LOCK_global_system_variables); - global_system_variables.vers_force= true; - global_system_variables.vers_hide= VERS_HIDE_FULL; - mysql_mutex_unlock(&LOCK_global_system_variables); DBUG_RETURN(0); } -static int forced_versioning_deinit(void *p __attribute__ ((unused))) +static int versioning_plugin_deinit(void *p __attribute__ ((unused))) { - DBUG_ENTER("forced_versioning_deinit"); - mysql_mutex_lock(&LOCK_global_system_variables); - global_system_variables.vers_force= false; - global_system_variables.vers_hide= VERS_HIDE_AUTO; - mysql_mutex_unlock(&LOCK_global_system_variables); + DBUG_ENTER("versioning_plugin_deinit"); + if (innodb_plugin) + plugin_unlock(NULL, innodb_plugin); DBUG_RETURN(0); } - -struct st_mysql_daemon forced_versioning_plugin= -{ MYSQL_DAEMON_INTERFACE_VERSION }; +struct st_mysql_daemon versioning_plugin= +{ MYSQL_REPLICATION_INTERFACE_VERSION }; /* Plugin library descriptor */ -maria_declare_plugin(forced_versioning) +maria_declare_plugin(versioning) { - MYSQL_DAEMON_PLUGIN, - &forced_versioning_plugin, - "forced_versioning", - "Natsys Lab", - "Enable System Vesioning for all newly created tables", + MYSQL_REPLICATION_PLUGIN, // initialized after MYSQL_STORAGE_ENGINE_PLUGIN + &versioning_plugin, + "versioning", + "MariaDB Corp", + "System Vesioning testing features", PLUGIN_LICENSE_GPL, - forced_versioning_init, /* Plugin Init */ - forced_versioning_deinit, /* Plugin Deinit */ + versioning_plugin_init, /* Plugin Init */ + versioning_plugin_deinit, /* Plugin Deinit */ 0x0100 /* 1.0 */, NULL, /* status variables */ NULL, /* system variables */ diff --git a/sql/item_create.cc b/sql/item_create.cc index 7e8c60591e6..140abdd074d 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -104,36 +104,6 @@ bool get_length_and_scale(ulonglong length, ulonglong decimals, ============================================================================= */ -/** - Adapter for native functions with a variable number of arguments. - The main use of this class is to discard the following calls: - foo(expr1 AS name1, expr2 AS name2, ...) - which are syntactically correct (the syntax can refer to a UDF), - but semantically invalid for native functions. -*/ - -class Create_native_func : public Create_func -{ -public: - virtual Item *create_func(THD *thd, LEX_STRING name, List *item_list); - - /** - Builder method, with no arguments. - @param thd The current thread - @param name The native function name - @param item_list The function parameters, none of which are named - @return An item representing the function call - */ - virtual Item *create_native(THD *thd, LEX_STRING name, - List *item_list) = 0; - -protected: - /** Constructor. */ - Create_native_func() {} - /** Destructor. */ - virtual ~Create_native_func() {} -}; - /** Adapter for functions that takes exactly zero arguments. @@ -6678,125 +6648,6 @@ Create_func_year_week::create_native(THD *thd, LEX_STRING name, } -/* System Versioning: VTQ_TRX_ID(), VTQ_COMMIT_ID(), VTQ_BEGIN_TS(), VTQ_COMMIT_TS(), VTQ_ISO_LEVEL() */ -template -class Create_func_vtq : public Create_native_func -{ -public: - virtual Item *create_native(THD *thd, LEX_STRING name, List *item_list); - - static Create_func_vtq s_singleton; - -protected: - Create_func_vtq() {} - virtual ~Create_func_vtq() {} -}; - -template -Create_func_vtq Create_func_vtq::s_singleton; - -template -Item* -Create_func_vtq::create_native(THD *thd, LEX_STRING name, - List *item_list) -{ - Item *func= NULL; - int arg_count= 0; - - if (item_list != NULL) - arg_count= item_list->elements; - - switch (arg_count) { - case 1: - { - Item *param_1= item_list->pop(); - switch (VTQ_FIELD) - { - case VTQ_BEGIN_TS: - case VTQ_COMMIT_TS: - func= new (thd->mem_root) Item_func_vtq_ts(thd, param_1, VTQ_FIELD); - break; - case VTQ_TRX_ID: - case VTQ_COMMIT_ID: - case VTQ_ISO_LEVEL: - func= new (thd->mem_root) Item_func_vtq_id(thd, param_1, VTQ_FIELD); - break; - default: - DBUG_ASSERT(0); - } - break; - } - case 2: - { - Item *param_1= item_list->pop(); - Item *param_2= item_list->pop(); - switch (VTQ_FIELD) - { - case VTQ_TRX_ID: - case VTQ_COMMIT_ID: - func= new (thd->mem_root) Item_func_vtq_id(thd, param_1, param_2, VTQ_FIELD); - break; - default: - goto error; - } - break; - } - error: - default: - { - my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str); - break; - } - } - - return func; -}; - -template -class Create_func_vtq_trx_sees : public Create_native_func -{ -public: - virtual Item *create_native(THD *thd, LEX_STRING name, List *item_list) - { - Item *func= NULL; - int arg_count= 0; - - if (item_list != NULL) - arg_count= item_list->elements; - - switch (arg_count) { - case 2: - { - Item *param_1= item_list->pop(); - Item *param_2= item_list->pop(); - func= new (thd->mem_root) Item_func_vtq_trx_seesX(thd, param_1, param_2); - break; - } - default: - my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str); - break; - } - - return func; - } - - static Create_func_vtq_trx_sees s_singleton; - -protected: - Create_func_vtq_trx_sees() {} - virtual ~Create_func_vtq_trx_sees() {} -}; - -template -Create_func_vtq_trx_sees Create_func_vtq_trx_sees::s_singleton; - - -struct Native_func_registry -{ - LEX_STRING name; - Create_func *builder; -}; - #define BUILDER(F) & F::s_singleton #ifdef HAVE_SPATIAL @@ -7146,13 +6997,6 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("UUID") }, BUILDER(Create_func_uuid)}, { { C_STRING_WITH_LEN("UUID_SHORT") }, BUILDER(Create_func_uuid_short)}, { { C_STRING_WITH_LEN("VERSION") }, BUILDER(Create_func_version)}, - { { C_STRING_WITH_LEN("VTQ_BEGIN_TS") }, BUILDER(Create_func_vtq)}, - { { C_STRING_WITH_LEN("VTQ_COMMIT_ID") }, BUILDER(Create_func_vtq)}, - { { C_STRING_WITH_LEN("VTQ_COMMIT_TS") }, BUILDER(Create_func_vtq)}, - { { C_STRING_WITH_LEN("VTQ_ISO_LEVEL") }, BUILDER(Create_func_vtq)}, - { { C_STRING_WITH_LEN("VTQ_TRX_ID") }, BUILDER(Create_func_vtq)}, - { { C_STRING_WITH_LEN("VTQ_TRX_SEES") }, BUILDER(Create_func_vtq_trx_sees)}, - { { C_STRING_WITH_LEN("VTQ_TRX_SEES_EQ") }, BUILDER(Create_func_vtq_trx_sees)}, { { C_STRING_WITH_LEN("WEEKDAY") }, BUILDER(Create_func_weekday)}, { { C_STRING_WITH_LEN("WEEKOFYEAR") }, BUILDER(Create_func_weekofyear)}, { { C_STRING_WITH_LEN("WITHIN") }, GEOM_BUILDER(Create_func_within)}, @@ -7182,8 +7026,6 @@ get_native_fct_hash_key(const uchar *buff, size_t *length, int item_create_init() { - Native_func_registry *func; - DBUG_ENTER("item_create_init"); if (my_hash_init(& native_functions_hash, @@ -7196,7 +7038,16 @@ int item_create_init() MYF(0))) DBUG_RETURN(1); - for (func= func_array; func->builder != NULL; func++) + DBUG_RETURN(item_create_append(func_array)); +} + +int item_create_append(Native_func_registry array[]) +{ + Native_func_registry *func; + + DBUG_ENTER("item_create_append"); + + for (func= array; func->builder != NULL; func++) { if (my_hash_insert(& native_functions_hash, (uchar*) func)) DBUG_RETURN(1); diff --git a/sql/item_create.h b/sql/item_create.h index 05fe48f656a..b8749a4513a 100644 --- a/sql/item_create.h +++ b/sql/item_create.h @@ -19,6 +19,8 @@ #ifndef ITEM_CREATE_H #define ITEM_CREATE_H +#include "item_func.h" // Cast_target + typedef struct st_udf_func udf_func; /** @@ -66,6 +68,37 @@ protected: }; +/** + Adapter for native functions with a variable number of arguments. + The main use of this class is to discard the following calls: + foo(expr1 AS name1, expr2 AS name2, ...) + which are syntactically correct (the syntax can refer to a UDF), + but semantically invalid for native functions. +*/ + +class Create_native_func : public Create_func +{ +public: + virtual Item *create_func(THD *thd, LEX_STRING name, List *item_list); + + /** + Builder method, with no arguments. + @param thd The current thread + @param name The native function name + @param item_list The function parameters, none of which are named + @return An item representing the function call + */ + virtual Item *create_native(THD *thd, LEX_STRING name, + List *item_list) = 0; + +protected: + /** Constructor. */ + Create_native_func() {} + /** Destructor. */ + virtual ~Create_native_func() {} +}; + + /** Function builder for qualified functions. This builder is used with functions call using a qualified function name @@ -183,7 +216,14 @@ Item *create_temporal_literal(THD *thd, const String *str, type, send_error); } +struct Native_func_registry +{ + LEX_STRING name; + Create_func *builder; +}; + int item_create_init(); +int item_create_append(Native_func_registry array[]); void item_create_cleanup(); Item *create_func_dyncol_create(THD *thd, List &list); diff --git a/sql/item_func.h b/sql/item_func.h index 0b398adb937..b7fb5d9cdfa 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -30,6 +30,9 @@ extern "C" /* Bug in BSDI include file */ } #endif +#include "sql_udf.h" // udf_handler +#include "my_decimal.h" // string2my_decimal + class Item_func :public Item_func_or_sum { diff --git a/sql/item_vers.cc b/sql/item_vers.cc index eff4c15db6b..3562cc7fbc9 100644 --- a/sql/item_vers.cc +++ b/sql/item_vers.cc @@ -25,57 +25,27 @@ Item_func_vtq_ts::Item_func_vtq_ts( THD *thd, - Item* a, - vtq_field_t _vtq_field, - handlerton* hton) : - VTQ_common(thd, a, hton), - vtq_field(_vtq_field) -{ - decimals= 6; - null_value= true; - DBUG_ASSERT(arg_count == 1 && args[0]); -} - -Item_func_vtq_ts::Item_func_vtq_ts( - THD *thd, + handlerton* hton, Item* a, vtq_field_t _vtq_field) : - VTQ_common(thd, a), + VTQ_common(thd, hton, a), vtq_field(_vtq_field) { decimals= 6; null_value= true; DBUG_ASSERT(arg_count == 1 && args[0]); + check_hton(); } template void -VTQ_common::init_hton() +VTQ_common::check_hton() { - if (!hton) + DBUG_ASSERT(hton); + if (!(hton->flags & HTON_NATIVE_SYS_VERSIONING) && hton->db_type != DB_TYPE_HEAP) { - if (Item_func_X::args[0]->type() == Item::FIELD_ITEM) - { - Item_field *f= - static_cast(Item_func_X::args[0]); - DBUG_ASSERT( - f->field && - f->field->table && - f->field->table->s && - f->field->table->s->db_plugin); - hton= f->field->table->file->partition_ht(); - DBUG_ASSERT(hton); - } - else if (innodb_plugin) - { - hton= plugin_hton(plugin_int_to_ref(innodb_plugin)); - DBUG_ASSERT(hton); - } - if (hton && !(hton->flags & HTON_NATIVE_SYS_VERSIONING)) - { - my_error(ER_VERS_ENGINE_UNSUPPORTED, MYF(0), Item::name ? Item::name : this->func_name()); - hton= NULL; - } + my_error(ER_VERS_ENGINE_UNSUPPORTED, MYF(0), Item::name ? Item::name : this->func_name()); + hton= NULL; } } @@ -92,8 +62,6 @@ Item_func_vtq_ts::get_date(MYSQL_TIME *res, ulonglong fuzzy_date) return false; } - init_hton(); - if (!hton) return true; @@ -106,10 +74,11 @@ Item_func_vtq_ts::get_date(MYSQL_TIME *res, ulonglong fuzzy_date) Item_func_vtq_id::Item_func_vtq_id( THD *thd, + handlerton *hton, Item* a, vtq_field_t _vtq_field, bool _backwards) : - VTQ_common(thd, a), + VTQ_common(thd, hton, a), vtq_field(_vtq_field), backwards(_backwards) { @@ -118,14 +87,16 @@ Item_func_vtq_id::Item_func_vtq_id( unsigned_flag= 1; null_value= true; DBUG_ASSERT(arg_count == 1 && args[0]); + check_hton(); } Item_func_vtq_id::Item_func_vtq_id( THD *thd, + handlerton *hton, Item* a, Item* b, vtq_field_t _vtq_field) : - VTQ_common(thd, a, b), + VTQ_common(thd, hton, a, b), vtq_field(_vtq_field), backwards(false) { @@ -134,6 +105,7 @@ Item_func_vtq_id::Item_func_vtq_id( unsigned_flag= 1; null_value= true; DBUG_ASSERT(arg_count == 2 && args[0] && args[1]); + check_hton(); } longlong @@ -186,8 +158,6 @@ Item_func_vtq_id::get_by_commit_ts(MYSQL_TIME &commit_ts, bool backwards) longlong Item_func_vtq_id::val_int() { - init_hton(); - if (!hton) { null_value= true; @@ -222,9 +192,10 @@ Item_func_vtq_id::val_int() Item_func_vtq_trx_sees::Item_func_vtq_trx_sees( THD *thd, + handlerton *hton, Item* a, Item* b) : - VTQ_common(thd, a, b), + VTQ_common(thd, hton, a, b), accept_eq(false) { null_value= true; @@ -237,8 +208,6 @@ Item_func_vtq_trx_sees::val_int() THD *thd= current_thd; DBUG_ASSERT(thd); - init_hton(); - if (!hton) { null_value= true; diff --git a/sql/item_vers.h b/sql/item_vers.h index aa5575ff9b1..86e0711e5d2 100644 --- a/sql/item_vers.h +++ b/sql/item_vers.h @@ -29,15 +29,12 @@ class VTQ_common : public Item_func_X { protected: handlerton *hton; - void init_hton(); + void check_hton(); public: - VTQ_common(THD *thd, Item* a) : - Item_func_X(thd, a), - hton(NULL) {} - VTQ_common(THD *thd, Item* a, Item* b) : + VTQ_common(THD *thd, handlerton* _hton, Item* a, Item* b) : Item_func_X(thd, a, b), - hton(NULL) {} - VTQ_common(THD *thd, Item* a, handlerton* _hton) : + hton(_hton) {} + VTQ_common(THD *thd, handlerton* _hton, Item* a) : Item_func_X(thd, a), hton(_hton) {} }; @@ -47,8 +44,7 @@ class Item_func_vtq_ts : { vtq_field_t vtq_field; public: - Item_func_vtq_ts(THD *thd, Item* a, vtq_field_t _vtq_field, handlerton *hton); - Item_func_vtq_ts(THD *thd, Item* a, vtq_field_t _vtq_field); + Item_func_vtq_ts(THD *thd, handlerton *hton, Item* a, vtq_field_t _vtq_field); const char *func_name() const { if (vtq_field == VTQ_BEGIN_TS) @@ -73,8 +69,8 @@ class Item_func_vtq_id : longlong get_by_commit_ts(MYSQL_TIME &commit_ts, bool backwards); public: - Item_func_vtq_id(THD *thd, Item* a, vtq_field_t _vtq_field, bool _backwards= false); - Item_func_vtq_id(THD *thd, Item* a, Item* b, vtq_field_t _vtq_field); + Item_func_vtq_id(THD *thd, handlerton *hton, Item* a, vtq_field_t _vtq_field, bool _backwards= false); + Item_func_vtq_id(THD *thd, handlerton *hton, Item* a, Item* b, vtq_field_t _vtq_field); vtq_record_t *vtq_cached_result() { return &cached_result; } @@ -112,7 +108,7 @@ protected: bool accept_eq; public: - Item_func_vtq_trx_sees(THD *thd, Item* a, Item* b); + Item_func_vtq_trx_sees(THD *thd, handlerton *hton, Item* a, Item* b); const char *func_name() const { return "vtq_trx_sees"; @@ -126,8 +122,8 @@ class Item_func_vtq_trx_sees_eq : public Item_func_vtq_trx_sees { public: - Item_func_vtq_trx_sees_eq(THD *thd, Item* a, Item* b) : - Item_func_vtq_trx_sees(thd, a, b) + Item_func_vtq_trx_sees_eq(THD *thd, handlerton *hton, Item* a, Item* b) : + Item_func_vtq_trx_sees(thd, hton, a, b) { accept_eq= true; } diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 82fbb7c62cc..c307bc4f425 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -233,8 +233,6 @@ static int plugin_array_version=0; static bool initialized= 0; ulong dlopen_count; -st_plugin_int* innodb_plugin= NULL; - /* write-lock on LOCK_system_variables_hash is required before modifying @@ -1424,18 +1422,6 @@ static int plugin_initialize(MEM_ROOT *tmp_root, struct st_plugin_int *plugin, } state= PLUGIN_IS_READY; // plugin->init() succeeded - { - static const char * INNODB= "InnoDB"; - static const uint INNODB_LEN= strlen(INNODB); - - if (!my_strnncoll(&my_charset_latin1, - (const uchar *) plugin->name.str, plugin->name.length, - (const uchar *) INNODB, INNODB_LEN)) - { - innodb_plugin= plugin; - } - } - if (plugin->plugin->status_vars) { /* diff --git a/sql/sql_plugin.h b/sql/sql_plugin.h index e399fec8339..7b89246a9f9 100644 --- a/sql/sql_plugin.h +++ b/sql/sql_plugin.h @@ -160,8 +160,6 @@ extern ulong plugin_maturity; extern TYPELIB plugin_maturity_values; extern const char *plugin_maturity_names[]; -extern st_plugin_int* innodb_plugin; - extern int plugin_init(int *argc, char **argv, int init_flags); extern void plugin_shutdown(void); void add_plugin_options(DYNAMIC_ARRAY *options, MEM_ROOT *mem_root); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index fef673b8c33..208946c1191 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -875,15 +875,14 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, DBUG_ASSERT(hton); row_start= newx Item_func_vtq_ts( thd, + hton, row_start, - VTQ_COMMIT_TS, - // FIXME: is it needed to pass hton or it can be deduced from arg 'a'? - hton); + VTQ_COMMIT_TS); row_end= newx Item_func_vtq_ts( thd, + hton, row_end, - VTQ_COMMIT_TS, - hton); + VTQ_COMMIT_TS); } Item *cond1= 0, *cond2= 0, *curr= 0; @@ -952,17 +951,17 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, break; case FOR_SYSTEM_TIME_AS_OF: trx_id0= vers_conditions.unit == UNIT_TIMESTAMP ? - newx Item_func_vtq_id(thd, vers_conditions.start, VTQ_TRX_ID) : + newx Item_func_vtq_id(thd, hton, vers_conditions.start, VTQ_TRX_ID) : vers_conditions.start; - cond1= newx Item_func_vtq_trx_sees_eq(thd, trx_id0, row_start); - cond2= newx Item_func_vtq_trx_sees(thd, row_end, trx_id0); + cond1= newx Item_func_vtq_trx_sees_eq(thd, hton, trx_id0, row_start); + cond2= newx Item_func_vtq_trx_sees(thd, hton, row_end, trx_id0); break; case FOR_SYSTEM_TIME_FROM_TO: case FOR_SYSTEM_TIME_BETWEEN: if (vers_conditions.unit == UNIT_TIMESTAMP) { - trx_id0= newx Item_func_vtq_id(thd, vers_conditions.start, VTQ_TRX_ID, true); - trx_id1= newx Item_func_vtq_id(thd, vers_conditions.end, VTQ_TRX_ID, false); + trx_id0= newx Item_func_vtq_id(thd, hton, vers_conditions.start, VTQ_TRX_ID, true); + trx_id1= newx Item_func_vtq_id(thd, hton, vers_conditions.end, VTQ_TRX_ID, false); } else { @@ -971,13 +970,13 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, } cond1= vers_conditions.type == FOR_SYSTEM_TIME_FROM_TO ? - newx Item_func_vtq_trx_sees(thd, trx_id1, row_start) : - newx Item_func_vtq_trx_sees_eq(thd, trx_id1, row_start); - cond2= newx Item_func_vtq_trx_sees_eq(thd, row_end, trx_id0); + newx Item_func_vtq_trx_sees(thd, hton, trx_id1, row_start) : + newx Item_func_vtq_trx_sees_eq(thd, hton, trx_id1, row_start); + cond2= newx Item_func_vtq_trx_sees_eq(thd, hton, row_end, trx_id0); break; case FOR_SYSTEM_TIME_BEFORE: trx_id0= vers_conditions.unit == UNIT_TIMESTAMP ? - newx Item_func_vtq_id(thd, vers_conditions.start, VTQ_TRX_ID) : + newx Item_func_vtq_id(thd, hton, vers_conditions.start, VTQ_TRX_ID) : vers_conditions.start; cond1= newx Item_func_lt(thd, row_end, trx_id0); break; diff --git a/sql/vers_string.h b/sql/vers_string.h index ddd691276db..9f42692791b 100644 --- a/sql/vers_string.h +++ b/sql/vers_string.h @@ -60,6 +60,10 @@ struct LEX_STRING_u : public Storage { return *this; } + const LEX_STRING& lex_string() const + { + return *(LEX_STRING *)this; + } }; template > -- cgit v1.2.1 From 60e456df3328657bba1648157abd1c1aa4b0838c Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 12 Jul 2017 10:36:02 +0300 Subject: SQL: system_time propagation from derived table [fixes #228] --- mysql-test/suite/versioning/r/cte.result | 99 ++++++++++++++++++++++ mysql-test/suite/versioning/r/cte_recursive.result | 68 --------------- mysql-test/suite/versioning/r/derived.result | 16 +++- mysql-test/suite/versioning/t/cte.opt | 3 + mysql-test/suite/versioning/t/cte.test | 84 ++++++++++++++++++ mysql-test/suite/versioning/t/cte_recursive.opt | 2 - mysql-test/suite/versioning/t/cte_recursive.test | 69 --------------- mysql-test/suite/versioning/t/derived.test | 8 +- sql/sql_select.cc | 31 ++++--- 9 files changed, 227 insertions(+), 153 deletions(-) create mode 100644 mysql-test/suite/versioning/r/cte.result delete mode 100644 mysql-test/suite/versioning/r/cte_recursive.result create mode 100644 mysql-test/suite/versioning/t/cte.opt create mode 100644 mysql-test/suite/versioning/t/cte.test delete mode 100644 mysql-test/suite/versioning/t/cte_recursive.opt delete mode 100644 mysql-test/suite/versioning/t/cte_recursive.test diff --git a/mysql-test/suite/versioning/r/cte.result b/mysql-test/suite/versioning/r/cte.result new file mode 100644 index 00000000000..d03e55d2f80 --- /dev/null +++ b/mysql-test/suite/versioning/r/cte.result @@ -0,0 +1,99 @@ +create or replace table dept ( +dept_id int(10) primary key, +name varchar(100) +) +with system versioning; +create or replace table emp ( +emp_id int(10) primary key, +dept_id int(10) not null, +name varchar(100) not null, +mgr int(10), +salary int(10) not null, +constraint `dept-emp-fk` + foreign key (dept_id) references dept (dept_id) +on delete cascade +on update restrict, +constraint `mgr-fk` + foreign key (mgr) references emp (emp_id) +on delete restrict +on update restrict +) +with system versioning; +insert into dept (dept_id, name) values (10, "accounting"); +insert into emp (emp_id, name, salary, dept_id, mgr) values +(1, "bill", 1000, 10, null), +(20, "john", 500, 10, 1), +(30, "jane", 750, 10,1 ); +select vtq_commit_ts(max(sys_trx_start)) into @ts_1 from emp; +update emp set mgr=30 where name ="john"; +select vtq_commit_ts(sys_trx_start) into @ts_2 from emp where name="john"; +/* All report to 'Bill' */ +with recursive +ancestors +as +( +select e.emp_id, e.name, e.mgr, e.salary +from emp as e for system_time as of timestamp @ts_1 +where name = 'bill' + union +select e.emp_id, e.name, e.mgr, e.salary +from emp as e for system_time as of timestamp @ts_1, +ancestors as a +where e.mgr = a.emp_id +) +select * from ancestors for system_time as of now; +emp_id name mgr salary +1 bill NULL 1000 +30 jane 1 750 +/* Expected 3 rows */ +with recursive +ancestors +as +( +select e.emp_id, e.name, e.mgr, e.salary +from emp as e for system_time as of timestamp @ts_2 +where name = 'bill' + union +select e.emp_id, e.name, e.mgr, e.salary +from emp as e for system_time as of timestamp @ts_2, +ancestors as a +where e.mgr = a.emp_id +) +select * from ancestors; +emp_id name mgr salary +1 bill NULL 1000 +30 jane 1 750 +20 john 30 500 +create or replace table emp ( emp_id int, name varchar(127), mgr int) with system versioning; +create or replace table addr ( emp_id int, address varchar(100)) with system versioning; +insert emp values (1, 'bill', 0), (2, 'bill', 1), (3, 'kate', 1); +insert addr values (1, 'Moscow'), (2, 'New York'), (3, 'London'); +set @ts=now(6); +delete from emp; +delete from addr; +insert emp values (4, 'john', 1); +insert addr values (4, 'Paris'); +with ancestors as (select * from emp natural join addr) select * from ancestors; +emp_id name mgr address +4 john 1 Paris +with ancestors as (select * from emp natural join addr) select * from ancestors for system_time all; +emp_id name mgr address +1 bill 0 Moscow +2 bill 1 New York +3 kate 1 London +4 john 1 Paris +with ancestors as (select * from emp natural join addr query for system_time all) select * from ancestors; +emp_id name mgr address +1 bill 0 Moscow +2 bill 1 New York +3 kate 1 London +4 john 1 Paris +select * from emp natural join addr query for system_time all; +emp_id name mgr address +1 bill 0 Moscow +2 bill 1 New York +3 kate 1 London +4 john 1 Paris +drop table emp; +drop table dept; +drop table addr; diff --git a/mysql-test/suite/versioning/r/cte_recursive.result b/mysql-test/suite/versioning/r/cte_recursive.result deleted file mode 100644 index 4ad56b8f3a7..00000000000 --- a/mysql-test/suite/versioning/r/cte_recursive.result +++ /dev/null @@ -1,68 +0,0 @@ -create or replace table dept ( -dept_id int(10) primary key, -name varchar(100) -) -with system versioning; -create or replace table emp ( -emp_id int(10) primary key, -dept_id int(10) not null, -name varchar(100) not null, -mgr int(10), -salary int(10) not null, -constraint `dept-emp-fk` - foreign key (dept_id) references dept (dept_id) -on delete cascade -on update restrict, -constraint `mgr-fk` - foreign key (mgr) references emp (emp_id) -on delete restrict -on update restrict -) -with system versioning; -insert into dept (dept_id, name) values (10, "accounting"); -insert into emp (emp_id, name, salary, dept_id, mgr) values -(1, "bill", 1000, 10, null), -(20, "john", 500, 10, 1), -(30, "jane", 750, 10,1 ); -select vtq_commit_ts(max(sys_trx_start)) into @ts_1 from emp; -update emp set mgr=30 where name ="john"; -select vtq_commit_ts(sys_trx_start) into @ts_2 from emp where name="john"; -/* All report to 'Bill' */ -with recursive -ancestors -as -( -select e.emp_id, e.name, e.mgr, e.salary -from emp as e for system_time as of timestamp @ts_1 -where name = 'bill' - union -select e.emp_id, e.name, e.mgr, e.salary -from emp as e for system_time as of timestamp @ts_1, -ancestors as a -where e.mgr = a.emp_id -) -select * from ancestors for system_time as of now; -emp_id name mgr salary -1 bill NULL 1000 -30 jane 1 750 -/* Expected 3 rows */ -with recursive -ancestors -as -( -select e.emp_id, e.name, e.mgr, e.salary -from emp as e for system_time as of timestamp @ts_2 -where name = 'bill' - union -select e.emp_id, e.name, e.mgr, e.salary -from emp as e for system_time as of timestamp @ts_2, -ancestors as a -where e.mgr = a.emp_id -) -select * from ancestors; -emp_id name mgr salary -1 bill NULL 1000 -30 jane 1 750 -20 john 30 500 -drop table emp; -drop table dept; diff --git a/mysql-test/suite/versioning/r/derived.result b/mysql-test/suite/versioning/r/derived.result index 6b26b18adc0..06bdf9799dd 100644 --- a/mysql-test/suite/versioning/r/derived.result +++ b/mysql-test/suite/versioning/r/derived.result @@ -139,10 +139,22 @@ ERROR HY000: Derived table is prohibited: system fields from multiple tables `t1 select * from (select * from t1 for system_time as of timestamp @t0, t2) as s0; x y 1 10 -select * from (select *, t1.sys_trx_end from t2, t1 for system_time as of timestamp @t0) as s0; +with s1 as (select * from t1 for system_time as of timestamp @t0, t2) select * from s1; +x y +1 10 +select * from (select *, t1.sys_trx_end from t2, t1 for system_time as of timestamp @t0) as s2; +y x +10 1 +with s3 as (select *, t1.sys_trx_end from t2, t1 for system_time as of timestamp @t0) select * from s3; +y x +10 1 +select * from (select *, t1.sys_trx_start from t2 for system_time as of now, t1) as s4 query for system_time as of timestamp @t0; +y x +10 1 +with s5 as (select *, t1.sys_trx_start from t2 for system_time as of now, t1) select * from s5 for system_time as of timestamp @t0; y x 10 1 -select * from (select *, t1.sys_trx_start from t2 for system_time as of now, t1) as s0 query for system_time as of timestamp @t0; +with s6 as (select *, t1.sys_trx_start from t2 for system_time as of now, t1) select * from s6 query for system_time as of timestamp @t0; y x 10 1 set @q= concat("create view vt1 as select * from t1 for system_time as of timestamp '", @t0, "'"); diff --git a/mysql-test/suite/versioning/t/cte.opt b/mysql-test/suite/versioning/t/cte.opt new file mode 100644 index 00000000000..36f683f4f5b --- /dev/null +++ b/mysql-test/suite/versioning/t/cte.opt @@ -0,0 +1,3 @@ +--innodb --default-storage-engine=innodb +--plugin-load=versioning +--versioning-hide=implicit diff --git a/mysql-test/suite/versioning/t/cte.test b/mysql-test/suite/versioning/t/cte.test new file mode 100644 index 00000000000..2650590b552 --- /dev/null +++ b/mysql-test/suite/versioning/t/cte.test @@ -0,0 +1,84 @@ +create or replace table dept ( + dept_id int(10) primary key, + name varchar(100) +) +with system versioning; + +create or replace table emp ( + emp_id int(10) primary key, + dept_id int(10) not null, + name varchar(100) not null, + mgr int(10), + salary int(10) not null, + constraint `dept-emp-fk` + foreign key (dept_id) references dept (dept_id) + on delete cascade + on update restrict, + constraint `mgr-fk` + foreign key (mgr) references emp (emp_id) + on delete restrict + on update restrict +) +with system versioning; + +insert into dept (dept_id, name) values (10, "accounting"); + +insert into emp (emp_id, name, salary, dept_id, mgr) values +(1, "bill", 1000, 10, null), +(20, "john", 500, 10, 1), +(30, "jane", 750, 10,1 ); + +select vtq_commit_ts(max(sys_trx_start)) into @ts_1 from emp; + +update emp set mgr=30 where name ="john"; +select vtq_commit_ts(sys_trx_start) into @ts_2 from emp where name="john"; + +/* All report to 'Bill' */ +with recursive +ancestors +as +( + select e.emp_id, e.name, e.mgr, e.salary + from emp as e for system_time as of timestamp @ts_1 + where name = 'bill' + union + select e.emp_id, e.name, e.mgr, e.salary + from emp as e for system_time as of timestamp @ts_1, + ancestors as a + where e.mgr = a.emp_id +) +select * from ancestors for system_time as of now; + +/* Expected 3 rows */ +with recursive +ancestors +as +( + select e.emp_id, e.name, e.mgr, e.salary + from emp as e for system_time as of timestamp @ts_2 + where name = 'bill' + union + select e.emp_id, e.name, e.mgr, e.salary + from emp as e for system_time as of timestamp @ts_2, + ancestors as a + where e.mgr = a.emp_id +) +select * from ancestors; + +create or replace table emp ( emp_id int, name varchar(127), mgr int) with system versioning; +create or replace table addr ( emp_id int, address varchar(100)) with system versioning; +insert emp values (1, 'bill', 0), (2, 'bill', 1), (3, 'kate', 1); +insert addr values (1, 'Moscow'), (2, 'New York'), (3, 'London'); +set @ts=now(6); +delete from emp; +delete from addr; +insert emp values (4, 'john', 1); +insert addr values (4, 'Paris'); +with ancestors as (select * from emp natural join addr) select * from ancestors; +with ancestors as (select * from emp natural join addr) select * from ancestors for system_time all; +with ancestors as (select * from emp natural join addr query for system_time all) select * from ancestors; +select * from emp natural join addr query for system_time all; + +drop table emp; +drop table dept; +drop table addr; diff --git a/mysql-test/suite/versioning/t/cte_recursive.opt b/mysql-test/suite/versioning/t/cte_recursive.opt deleted file mode 100644 index 993df05011e..00000000000 --- a/mysql-test/suite/versioning/t/cte_recursive.opt +++ /dev/null @@ -1,2 +0,0 @@ ---innodb --default-storage-engine=innodb ---plugin-load=versioning diff --git a/mysql-test/suite/versioning/t/cte_recursive.test b/mysql-test/suite/versioning/t/cte_recursive.test deleted file mode 100644 index d1de218bf62..00000000000 --- a/mysql-test/suite/versioning/t/cte_recursive.test +++ /dev/null @@ -1,69 +0,0 @@ -create or replace table dept ( - dept_id int(10) primary key, - name varchar(100) -) -with system versioning; - -create or replace table emp ( - emp_id int(10) primary key, - dept_id int(10) not null, - name varchar(100) not null, - mgr int(10), - salary int(10) not null, - constraint `dept-emp-fk` - foreign key (dept_id) references dept (dept_id) - on delete cascade - on update restrict, - constraint `mgr-fk` - foreign key (mgr) references emp (emp_id) - on delete restrict - on update restrict -) -with system versioning; - -insert into dept (dept_id, name) values (10, "accounting"); - -insert into emp (emp_id, name, salary, dept_id, mgr) values -(1, "bill", 1000, 10, null), -(20, "john", 500, 10, 1), -(30, "jane", 750, 10,1 ); - -select vtq_commit_ts(max(sys_trx_start)) into @ts_1 from emp; - -update emp set mgr=30 where name ="john"; -select vtq_commit_ts(sys_trx_start) into @ts_2 from emp where name="john"; - -/* All report to 'Bill' */ -with recursive -ancestors -as -( - select e.emp_id, e.name, e.mgr, e.salary - from emp as e for system_time as of timestamp @ts_1 - where name = 'bill' - union - select e.emp_id, e.name, e.mgr, e.salary - from emp as e for system_time as of timestamp @ts_1, - ancestors as a - where e.mgr = a.emp_id -) -select * from ancestors for system_time as of now; - -/* Expected 3 rows */ -with recursive -ancestors -as -( - select e.emp_id, e.name, e.mgr, e.salary - from emp as e for system_time as of timestamp @ts_2 - where name = 'bill' - union - select e.emp_id, e.name, e.mgr, e.salary - from emp as e for system_time as of timestamp @ts_2, - ancestors as a - where e.mgr = a.emp_id -) -select * from ancestors; - -drop table emp; -drop table dept; diff --git a/mysql-test/suite/versioning/t/derived.test b/mysql-test/suite/versioning/t/derived.test index 867973aee7e..f4de94f2f27 100644 --- a/mysql-test/suite/versioning/t/derived.test +++ b/mysql-test/suite/versioning/t/derived.test @@ -103,10 +103,14 @@ select * from (select *, t1.sys_trx_end, t2.sys_trx_start from t1, t2) as s0; # system_time propagation from inner to outer select * from (select * from t1 for system_time as of timestamp @t0, t2) as s0; +with s1 as (select * from t1 for system_time as of timestamp @t0, t2) select * from s1; # leading table selection -select * from (select *, t1.sys_trx_end from t2, t1 for system_time as of timestamp @t0) as s0; +select * from (select *, t1.sys_trx_end from t2, t1 for system_time as of timestamp @t0) as s2; +with s3 as (select *, t1.sys_trx_end from t2, t1 for system_time as of timestamp @t0) select * from s3; # system_time propagation from outer to inner -select * from (select *, t1.sys_trx_start from t2 for system_time as of now, t1) as s0 query for system_time as of timestamp @t0; +select * from (select *, t1.sys_trx_start from t2 for system_time as of now, t1) as s4 query for system_time as of timestamp @t0; +with s5 as (select *, t1.sys_trx_start from t2 for system_time as of now, t1) select * from s5 for system_time as of timestamp @t0; +with s6 as (select *, t1.sys_trx_start from t2 for system_time as of now, t1) select * from s6 query for system_time as of timestamp @t0; # VIEW instead of t1 set @q= concat("create view vt1 as select * from t1 for system_time as of timestamp '", @t0, "'"); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 208946c1191..ff3ce427ef5 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -771,7 +771,7 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, } SELECT_LEX *outer_slex= slex->next_select_in_list(); - bool use_slex_conds= false; + bool force_slex_conds= false; if (outer_slex) { if (slex->vers_derived_conds) @@ -786,15 +786,26 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, } if (slex->vers_conditions.import_outer) { - // Propagate query conditions from nearest outer SELECT_LEX: - while (outer_slex && (!outer_slex->vers_conditions || outer_slex->vers_conditions.from_inner)) - outer_slex= outer_slex->next_select_in_list(); - if (outer_slex) + DBUG_ASSERT(slex->master_unit()); + TABLE_LIST* derived= slex->master_unit()->derived; + DBUG_ASSERT(derived); + if (derived->vers_conditions) { - slex->vers_conditions= outer_slex->vers_conditions; - outer_slex->vers_conditions.used= true; - DBUG_ASSERT(slex->master_unit()->derived); - use_slex_conds= slex->master_unit()->derived->is_view(); + slex->vers_conditions= derived->vers_conditions; + derived->vers_conditions.used= true; + force_slex_conds= derived->is_view(); + } + else + { + // Propagate query conditions from nearest outer SELECT_LEX: + while (outer_slex && (!outer_slex->vers_conditions || outer_slex->vers_conditions.from_inner)) + outer_slex= outer_slex->next_select_in_list(); + if (outer_slex) + { + slex->vers_conditions= outer_slex->vers_conditions; + outer_slex->vers_conditions.used= true; + force_slex_conds= derived->is_view(); + } } } } @@ -803,7 +814,7 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, { if (table->table && table->table->versioned()) { - vers_select_conds_t &vers_conditions= use_slex_conds || !table->vers_conditions? + vers_select_conds_t &vers_conditions= force_slex_conds || !table->vers_conditions? (slex->vers_conditions.used= true, slex->vers_conditions) : table->vers_conditions; -- cgit v1.2.1 From 91c8b43e77ea1ec65eb16a178d8e63a7b3065854 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 12 Jul 2017 11:24:03 +0300 Subject: Parser: syntax for query system_time [closes #230] Eliminated `QUERY FOR`. --- mysql-test/suite/versioning/r/cte.result | 4 +- mysql-test/suite/versioning/r/derived.result | 6 +- .../suite/versioning/r/optimized_fields.result | 14 +- mysql-test/suite/versioning/r/select.result | 14 +- mysql-test/suite/versioning/r/simple.result | 10 +- mysql-test/suite/versioning/r/truncate.result | 169 +++++++++++++++++++++ .../suite/versioning/r/truncate_history.result | 169 --------------------- mysql-test/suite/versioning/t/cte.test | 4 +- mysql-test/suite/versioning/t/derived.test | 6 +- .../suite/versioning/t/optimized_fields.test | 14 +- mysql-test/suite/versioning/t/select.test | 10 +- mysql-test/suite/versioning/t/simple.test | 10 +- mysql-test/suite/versioning/t/truncate.opt | 1 + mysql-test/suite/versioning/t/truncate.test | 119 +++++++++++++++ mysql-test/suite/versioning/t/truncate_history.opt | 1 - .../suite/versioning/t/truncate_history.test | 119 --------------- sql/sql_lex.cc | 15 -- sql/sql_select.cc | 6 +- sql/sql_yacc.yy | 11 +- sql/sql_yacc_ora.yy | 1 - 20 files changed, 343 insertions(+), 360 deletions(-) create mode 100644 mysql-test/suite/versioning/r/truncate.result delete mode 100644 mysql-test/suite/versioning/r/truncate_history.result create mode 100644 mysql-test/suite/versioning/t/truncate.opt create mode 100644 mysql-test/suite/versioning/t/truncate.test delete mode 100644 mysql-test/suite/versioning/t/truncate_history.opt delete mode 100644 mysql-test/suite/versioning/t/truncate_history.test diff --git a/mysql-test/suite/versioning/r/cte.result b/mysql-test/suite/versioning/r/cte.result index d03e55d2f80..5fe71901b44 100644 --- a/mysql-test/suite/versioning/r/cte.result +++ b/mysql-test/suite/versioning/r/cte.result @@ -82,13 +82,13 @@ emp_id name mgr address 2 bill 1 New York 3 kate 1 London 4 john 1 Paris -with ancestors as (select * from emp natural join addr query for system_time all) select * from ancestors; +with ancestors as (select * from emp natural join addr system_time all) select * from ancestors; emp_id name mgr address 1 bill 0 Moscow 2 bill 1 New York 3 kate 1 London 4 john 1 Paris -select * from emp natural join addr query for system_time all; +select * from emp natural join addr system_time all; emp_id name mgr address 1 bill 0 Moscow 2 bill 1 New York diff --git a/mysql-test/suite/versioning/r/derived.result b/mysql-test/suite/versioning/r/derived.result index 06bdf9799dd..96e8c0afa55 100644 --- a/mysql-test/suite/versioning/r/derived.result +++ b/mysql-test/suite/versioning/r/derived.result @@ -148,13 +148,13 @@ y x with s3 as (select *, t1.sys_trx_end from t2, t1 for system_time as of timestamp @t0) select * from s3; y x 10 1 -select * from (select *, t1.sys_trx_start from t2 for system_time as of now, t1) as s4 query for system_time as of timestamp @t0; +select * from (select *, t1.sys_trx_start from t2 for system_time as of now, t1) as s4 system_time as of timestamp @t0; y x 10 1 with s5 as (select *, t1.sys_trx_start from t2 for system_time as of now, t1) select * from s5 for system_time as of timestamp @t0; y x 10 1 -with s6 as (select *, t1.sys_trx_start from t2 for system_time as of now, t1) select * from s6 query for system_time as of timestamp @t0; +with s6 as (select *, t1.sys_trx_start from t2 for system_time as of now, t1) select * from s6 system_time as of timestamp @t0; y x 10 1 set @q= concat("create view vt1 as select * from t1 for system_time as of timestamp '", @t0, "'"); @@ -170,7 +170,7 @@ x y select * from (select *, vt1.sys_trx_end from t2, vt1) as s0; y x 10 1 -select * from (select *, vt1.sys_trx_start from t2 for system_time as of now, vt1) as s0 query for system_time as of timestamp @t0; +select * from (select *, vt1.sys_trx_start from t2 for system_time as of now, vt1) as s0 system_time as of timestamp @t0; y x 10 1 drop table t1, t2; diff --git a/mysql-test/suite/versioning/r/optimized_fields.result b/mysql-test/suite/versioning/r/optimized_fields.result index 4878f21b1f5..376eddb41b8 100644 --- a/mysql-test/suite/versioning/r/optimized_fields.result +++ b/mysql-test/suite/versioning/r/optimized_fields.result @@ -25,7 +25,7 @@ a b 3 NULL Warnings: Warning 4075 Attempt to read unversioned field `b` in historical query -select count(*) from t group by b query for system_time as of timestamp now(6); +select count(*) from t group by b system_time as of timestamp now(6); count(*) 2 Warnings: @@ -42,29 +42,29 @@ a b 3 NULL Warnings: Warning 4075 Attempt to read unversioned field `b` in historical query -select * from t group by a having a=2 query for system_time as of timestamp now(6); +select * from t group by a having a=2 system_time as of timestamp now(6); a b Warnings: Warning 4075 Attempt to read unversioned field `b` in historical query -select * from t group by b having b=2 query for system_time as of timestamp now(6); +select * from t group by b having b=2 system_time as of timestamp now(6); a b Warnings: Warning 4075 Attempt to read unversioned field `b` in historical query -select a from t where b=2 query for system_time as of timestamp now(6); +select a from t where b=2 system_time as of timestamp now(6); a Warnings: Warning 4075 Attempt to read unversioned field `b` in historical query -select a from t where b=NULL query for system_time as of timestamp now(6); +select a from t where b=NULL system_time as of timestamp now(6); a Warnings: Warning 4075 Attempt to read unversioned field `b` in historical query -select a from t where b is NULL query for system_time as of timestamp now(6); +select a from t where b is NULL system_time as of timestamp now(6); a 1 3 Warnings: Warning 4075 Attempt to read unversioned field `b` in historical query -select count(*), b from t group by b having b=NULL query for system_time as of timestamp now(6); +select count(*), b from t group by b having b=NULL system_time as of timestamp now(6); count(*) b Warnings: Warning 4075 Attempt to read unversioned field `b` in historical query diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index 39a5880250a..8a22b26fad1 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -146,11 +146,11 @@ select t1.x as RJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 delete from t1; delete from t2; select t1.x as IJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x -query for system_time as of timestamp @t0; +system_time as of timestamp @t0; select t1.x as LJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x -query for system_time as of timestamp @t0; +system_time as of timestamp @t0; select t1.x as RJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x -query for system_time as of timestamp @t0; +system_time as of timestamp @t0; drop table t1; drop table t2; end~~ @@ -333,7 +333,7 @@ A create or replace table t1 (x int); insert into t1 values (1); select * from t1 for system_time all; -ERROR HY000: System Versioning required: `FOR SYSTEM_TIME` query +ERROR HY000: System Versioning required: t1 create or replace table t1 (x int) with system versioning; insert into t1 values (1); select * from t1 for system_time all for update; @@ -431,13 +431,13 @@ create or replace table t2 (y int) with system versioning; insert into t1 values (1), (2), (3); delete from t1 where x = 3; insert into t2 values (1); -select * from t1, t2 query for system_time all; +select * from t1, t2 system_time all; x y 1 1 2 1 3 1 -select * from t1 for system_time all, t2 for system_time all query for system_time all; -ERROR HY000: Unused clause: 'QUERY FOR SYSTEM_TIME' +select * from t1 for system_time all, t2 for system_time all system_time all; +ERROR HY000: Unused clause: 'SYSTEM_TIME' drop view v1; drop table t1, t2; call innodb_verify_vtq(27); diff --git a/mysql-test/suite/versioning/r/simple.result b/mysql-test/suite/versioning/r/simple.result index 9454d487293..e0af556f073 100644 --- a/mysql-test/suite/versioning/r/simple.result +++ b/mysql-test/suite/versioning/r/simple.result @@ -44,28 +44,28 @@ emp_id dept_id name salary dept_id name select * from emp e, dept d where d.dept_id = 10 and d.dept_id = e.dept_id -query for system_time from timestamp @ts_1 to timestamp @ts_2; +system_time from timestamp @ts_1 to timestamp @ts_2; emp_id dept_id name salary sys_trx_start sys_trx_end dept_id name sys_trx_start sys_trx_end select * from emp e, dept d where d.dept_id = 10 and d.dept_id = e.dept_id -query for system_time as of timestamp @ts_0; +system_time as of timestamp @ts_0; emp_id dept_id name salary dept_id name select * from emp e, dept d where d.dept_id = 10 and d.dept_id = e.dept_id -query for system_time as of timestamp @ts_1; +system_time as of timestamp @ts_1; emp_id dept_id name salary dept_id name select * from emp e, dept d where d.dept_id = 10 and d.dept_id = e.dept_id -query for system_time as of timestamp @ts_2; +system_time as of timestamp @ts_2; emp_id dept_id name salary dept_id name 1 10 bill 1000 10 accounting select * from emp e, dept d where d.dept_id = 10 and d.dept_id = e.dept_id -query for system_time as of timestamp @ts_3; +system_time as of timestamp @ts_3; emp_id dept_id name salary dept_id name 1 10 bill 2000 10 accounting drop table emp, dept; diff --git a/mysql-test/suite/versioning/r/truncate.result b/mysql-test/suite/versioning/r/truncate.result new file mode 100644 index 00000000000..1ad9090f644 --- /dev/null +++ b/mysql-test/suite/versioning/r/truncate.result @@ -0,0 +1,169 @@ +create table t (a int); +truncate t for system_time all; +ERROR HY000: Unused clause: 'SYSTEM_TIME' +create procedure truncate_history_of_t() +begin +prepare stmt from 'truncate t for system_time timestamp between \'1-1-1\' and now(6)'; +execute stmt; +drop prepare stmt; +end~~ +create or replace table t (a int) with system versioning; +insert into t values (1); +update t set a=2; +select * from t for system_time all; +a +2 +1 +set @test = 'correct'; +create trigger trg_before before delete on t for each row set @test = 'incorrect'; +create trigger trg_after after delete on t for each row set @test = 'incorrect'; +truncate t for system_time all; +select * from t for system_time all; +a +2 +select @test from t; +@test +correct +drop trigger trg_before; +drop trigger trg_after; +update t set a=3; +update t set a=4; +truncate t for system_time as of timestamp now(6); +select * from t for system_time all; +a +4 +2 +3 +truncate t for system_time timestamp between '1-1-1' and now(6); +select * from t for system_time all; +a +4 +update t set a=5; +truncate t for system_time timestamp from '1-1-1' to now(6); +select * from t for system_time all; +a +5 +update t set a=6; +call truncate_history_of_t(); +select * from t for system_time all; +a +6 +set @ts1 = now(6); +update t set a=7; +set @ts2 = now(6); +update t set a=8; +truncate t for system_time timestamp from '1-1-1' to @ts1; +select * from t for system_time all; +a +8 +7 +update t set a=9; +truncate t for system_time timestamp between '1-1-1' and @ts2; +select * from t for system_time all; +a +9 +8 +create or replace table t (a int) with system versioning engine=innodb; +insert into t values (1); +update t set a=2; +select * from t for system_time all; +a +2 +1 +truncate t for system_time all; +select * from t for system_time all; +a +2 +update t set a=3; +update t set a=4; +truncate t for system_time as of timestamp now(6); +select * from t for system_time all; +a +4 +2 +3 +truncate t for system_time timestamp between '1-1-1' and now(6); +select * from t for system_time all; +a +4 +update t set a=5; +truncate t for system_time timestamp from '1-1-1' to now(6); +select * from t for system_time all; +a +5 +update t set a=6; +call truncate_history_of_t(); +select * from t for system_time all; +a +6 +set @ts1 = now(6); +update t set a=7; +set @ts2 = now(6); +update t set a=8; +truncate t for system_time timestamp from '1-1-1' to @ts1; +select * from t for system_time all; +a +8 +7 +update t set a=9; +truncate t for system_time timestamp between '1-1-1' and @ts2; +select * from t for system_time all; +a +9 +8 +create or replace table t (a int) with system versioning; +insert into t values (1), (2); +update t set a=11 where a=1; +set @ts1=now(6); +update t set a=22 where a=2; +select * from t for system_time all; +a +11 +22 +1 +2 +select * from t for system_time before timestamp @ts1; +a +1 +truncate t for system_time before timestamp @ts1; +select * from t for system_time all; +a +11 +22 +2 +truncate t for system_time before timestamp now(6); +select * from t for system_time all; +a +11 +22 +create or replace table t (a int) with system versioning engine=innodb; +insert into t values (1), (2); +update t set a=11 where a=1; +set @ts1=now(6); +update t set a=22 where a=2; +select * from t for system_time all; +a +11 +22 +1 +2 +select * from t for system_time before timestamp @ts1; +a +1 +select * from t for system_time before transaction 2000; +a +1 +2 +truncate t for system_time before timestamp @ts1; +select * from t for system_time all; +a +11 +22 +2 +truncate t for system_time before timestamp now(6); +select * from t for system_time all; +a +11 +22 +drop table t; +drop procedure truncate_history_of_t; diff --git a/mysql-test/suite/versioning/r/truncate_history.result b/mysql-test/suite/versioning/r/truncate_history.result deleted file mode 100644 index e0bf8816483..00000000000 --- a/mysql-test/suite/versioning/r/truncate_history.result +++ /dev/null @@ -1,169 +0,0 @@ -create table t (a int); -truncate t for system_time all; -ERROR HY000: System Versioning required: `FOR SYSTEM_TIME` query -create procedure truncate_history_of_t() -begin -prepare stmt from 'truncate t for system_time timestamp between \'1-1-1\' and now(6)'; -execute stmt; -drop prepare stmt; -end~~ -create or replace table t (a int) with system versioning; -insert into t values (1); -update t set a=2; -select * from t for system_time all; -a -2 -1 -set @test = 'correct'; -create trigger trg_before before delete on t for each row set @test = 'incorrect'; -create trigger trg_after after delete on t for each row set @test = 'incorrect'; -truncate t for system_time all; -select * from t for system_time all; -a -2 -select @test from t; -@test -correct -drop trigger trg_before; -drop trigger trg_after; -update t set a=3; -update t set a=4; -truncate t for system_time as of timestamp now(6); -select * from t for system_time all; -a -4 -2 -3 -truncate t for system_time timestamp between '1-1-1' and now(6); -select * from t for system_time all; -a -4 -update t set a=5; -truncate t for system_time timestamp from '1-1-1' to now(6); -select * from t for system_time all; -a -5 -update t set a=6; -call truncate_history_of_t(); -select * from t for system_time all; -a -6 -set @ts1 = now(6); -update t set a=7; -set @ts2 = now(6); -update t set a=8; -truncate t for system_time timestamp from '1-1-1' to @ts1; -select * from t for system_time all; -a -8 -7 -update t set a=9; -truncate t for system_time timestamp between '1-1-1' and @ts2; -select * from t for system_time all; -a -9 -8 -create or replace table t (a int) with system versioning engine=innodb; -insert into t values (1); -update t set a=2; -select * from t for system_time all; -a -2 -1 -truncate t for system_time all; -select * from t for system_time all; -a -2 -update t set a=3; -update t set a=4; -truncate t for system_time as of timestamp now(6); -select * from t for system_time all; -a -4 -2 -3 -truncate t for system_time timestamp between '1-1-1' and now(6); -select * from t for system_time all; -a -4 -update t set a=5; -truncate t for system_time timestamp from '1-1-1' to now(6); -select * from t for system_time all; -a -5 -update t set a=6; -call truncate_history_of_t(); -select * from t for system_time all; -a -6 -set @ts1 = now(6); -update t set a=7; -set @ts2 = now(6); -update t set a=8; -truncate t for system_time timestamp from '1-1-1' to @ts1; -select * from t for system_time all; -a -8 -7 -update t set a=9; -truncate t for system_time timestamp between '1-1-1' and @ts2; -select * from t for system_time all; -a -9 -8 -create or replace table t (a int) with system versioning; -insert into t values (1), (2); -update t set a=11 where a=1; -set @ts1=now(6); -update t set a=22 where a=2; -select * from t for system_time all; -a -11 -22 -1 -2 -select * from t for system_time before timestamp @ts1; -a -1 -truncate t for system_time before timestamp @ts1; -select * from t for system_time all; -a -11 -22 -2 -truncate t for system_time before timestamp now(6); -select * from t for system_time all; -a -11 -22 -create or replace table t (a int) with system versioning engine=innodb; -insert into t values (1), (2); -update t set a=11 where a=1; -set @ts1=now(6); -update t set a=22 where a=2; -select * from t for system_time all; -a -11 -22 -1 -2 -select * from t for system_time before timestamp @ts1; -a -1 -select * from t for system_time before transaction 2000; -a -1 -2 -truncate t for system_time before timestamp @ts1; -select * from t for system_time all; -a -11 -22 -2 -truncate t for system_time before timestamp now(6); -select * from t for system_time all; -a -11 -22 -drop table t; -drop procedure truncate_history_of_t; diff --git a/mysql-test/suite/versioning/t/cte.test b/mysql-test/suite/versioning/t/cte.test index 2650590b552..22c72bd9ed1 100644 --- a/mysql-test/suite/versioning/t/cte.test +++ b/mysql-test/suite/versioning/t/cte.test @@ -76,8 +76,8 @@ insert emp values (4, 'john', 1); insert addr values (4, 'Paris'); with ancestors as (select * from emp natural join addr) select * from ancestors; with ancestors as (select * from emp natural join addr) select * from ancestors for system_time all; -with ancestors as (select * from emp natural join addr query for system_time all) select * from ancestors; -select * from emp natural join addr query for system_time all; +with ancestors as (select * from emp natural join addr system_time all) select * from ancestors; +select * from emp natural join addr system_time all; drop table emp; drop table dept; diff --git a/mysql-test/suite/versioning/t/derived.test b/mysql-test/suite/versioning/t/derived.test index f4de94f2f27..d8b37298210 100644 --- a/mysql-test/suite/versioning/t/derived.test +++ b/mysql-test/suite/versioning/t/derived.test @@ -108,9 +108,9 @@ with s1 as (select * from t1 for system_time as of timestamp @t0, t2) select * f select * from (select *, t1.sys_trx_end from t2, t1 for system_time as of timestamp @t0) as s2; with s3 as (select *, t1.sys_trx_end from t2, t1 for system_time as of timestamp @t0) select * from s3; # system_time propagation from outer to inner -select * from (select *, t1.sys_trx_start from t2 for system_time as of now, t1) as s4 query for system_time as of timestamp @t0; +select * from (select *, t1.sys_trx_start from t2 for system_time as of now, t1) as s4 system_time as of timestamp @t0; with s5 as (select *, t1.sys_trx_start from t2 for system_time as of now, t1) select * from s5 for system_time as of timestamp @t0; -with s6 as (select *, t1.sys_trx_start from t2 for system_time as of now, t1) select * from s6 query for system_time as of timestamp @t0; +with s6 as (select *, t1.sys_trx_start from t2 for system_time as of now, t1) select * from s6 system_time as of timestamp @t0; # VIEW instead of t1 set @q= concat("create view vt1 as select * from t1 for system_time as of timestamp '", @t0, "'"); @@ -123,7 +123,7 @@ select * from (select * from vt1, t2) as s0; # leading table selection select * from (select *, vt1.sys_trx_end from t2, vt1) as s0; # system_time propagation from outer to inner -select * from (select *, vt1.sys_trx_start from t2 for system_time as of now, vt1) as s0 query for system_time as of timestamp @t0; +select * from (select *, vt1.sys_trx_start from t2 for system_time as of now, vt1) as s0 system_time as of timestamp @t0; drop table t1, t2; drop view vt1; diff --git a/mysql-test/suite/versioning/t/optimized_fields.test b/mysql-test/suite/versioning/t/optimized_fields.test index d1490d893a4..321fe6d104d 100644 --- a/mysql-test/suite/versioning/t/optimized_fields.test +++ b/mysql-test/suite/versioning/t/optimized_fields.test @@ -9,15 +9,15 @@ select * from t; select a from t for system_time as of timestamp now(6); select a, b, b+0 from t for system_time as of timestamp now(6); select * from t for system_time as of timestamp now(6); -select count(*) from t group by b query for system_time as of timestamp now(6); +select count(*) from t group by b system_time as of timestamp now(6); select * from t for system_time as of timestamp now(6) order by b asc; select * from t for system_time as of timestamp now(6) order by b desc; -select * from t group by a having a=2 query for system_time as of timestamp now(6); -select * from t group by b having b=2 query for system_time as of timestamp now(6); -select a from t where b=2 query for system_time as of timestamp now(6); -select a from t where b=NULL query for system_time as of timestamp now(6); -select a from t where b is NULL query for system_time as of timestamp now(6); -select count(*), b from t group by b having b=NULL query for system_time as of timestamp now(6); +select * from t group by a having a=2 system_time as of timestamp now(6); +select * from t group by b having b=2 system_time as of timestamp now(6); +select a from t where b=2 system_time as of timestamp now(6); +select a from t where b=NULL system_time as of timestamp now(6); +select a from t where b is NULL system_time as of timestamp now(6); +select count(*), b from t group by b having b=NULL system_time as of timestamp now(6); select a, b from t; drop table t; diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index ca8b9ccf56a..ef8dcb85664 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -99,11 +99,11 @@ begin delete from t2; select t1.x as IJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x - query for system_time as of timestamp @t0; + system_time as of timestamp @t0; select t1.x as LJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x - query for system_time as of timestamp @t0; + system_time as of timestamp @t0; select t1.x as RJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x - query for system_time as of timestamp @t0; + system_time as of timestamp @t0; drop table t1; drop table t2; @@ -195,10 +195,10 @@ create or replace table t2 (y int) with system versioning; insert into t1 values (1), (2), (3); delete from t1 where x = 3; insert into t2 values (1); -select * from t1, t2 query for system_time all; +select * from t1, t2 system_time all; --error ER_VERS_UNUSED_CLAUSE -select * from t1 for system_time all, t2 for system_time all query for system_time all; +select * from t1 for system_time all, t2 for system_time all system_time all; drop view v1; drop table t1, t2; diff --git a/mysql-test/suite/versioning/t/simple.test b/mysql-test/suite/versioning/t/simple.test index bb540f05c26..d32ea939279 100644 --- a/mysql-test/suite/versioning/t/simple.test +++ b/mysql-test/suite/versioning/t/simple.test @@ -45,26 +45,26 @@ where d.dept_id = 10 select * from emp e, dept d where d.dept_id = 10 and d.dept_id = e.dept_id -query for system_time from timestamp @ts_1 to timestamp @ts_2; +system_time from timestamp @ts_1 to timestamp @ts_2; select * from emp e, dept d where d.dept_id = 10 and d.dept_id = e.dept_id -query for system_time as of timestamp @ts_0; +system_time as of timestamp @ts_0; select * from emp e, dept d where d.dept_id = 10 and d.dept_id = e.dept_id -query for system_time as of timestamp @ts_1; +system_time as of timestamp @ts_1; select * from emp e, dept d where d.dept_id = 10 and d.dept_id = e.dept_id -query for system_time as of timestamp @ts_2; +system_time as of timestamp @ts_2; select * from emp e, dept d where d.dept_id = 10 and d.dept_id = e.dept_id -query for system_time as of timestamp @ts_3; +system_time as of timestamp @ts_3; drop table emp, dept; diff --git a/mysql-test/suite/versioning/t/truncate.opt b/mysql-test/suite/versioning/t/truncate.opt new file mode 100644 index 00000000000..c1a585b67eb --- /dev/null +++ b/mysql-test/suite/versioning/t/truncate.opt @@ -0,0 +1 @@ +--versioning-hide=implicit diff --git a/mysql-test/suite/versioning/t/truncate.test b/mysql-test/suite/versioning/t/truncate.test new file mode 100644 index 00000000000..7bf5c59acf8 --- /dev/null +++ b/mysql-test/suite/versioning/t/truncate.test @@ -0,0 +1,119 @@ +-- source include/have_innodb.inc + +create table t (a int); +--error ER_VERS_UNUSED_CLAUSE +truncate t for system_time all; + +delimiter ~~; +create procedure truncate_history_of_t() +begin + prepare stmt from 'truncate t for system_time timestamp between \'1-1-1\' and now(6)'; + execute stmt; + drop prepare stmt; +end~~ +delimiter ;~~ + +create or replace table t (a int) with system versioning; +insert into t values (1); +update t set a=2; +select * from t for system_time all; + +set @test = 'correct'; +create trigger trg_before before delete on t for each row set @test = 'incorrect'; +create trigger trg_after after delete on t for each row set @test = 'incorrect'; + +truncate t for system_time all; +select * from t for system_time all; + +select @test from t; +drop trigger trg_before; +drop trigger trg_after; + +update t set a=3; +update t set a=4; +truncate t for system_time as of timestamp now(6); +select * from t for system_time all; + +truncate t for system_time timestamp between '1-1-1' and now(6); +select * from t for system_time all; + +update t set a=5; +truncate t for system_time timestamp from '1-1-1' to now(6); +select * from t for system_time all; + +update t set a=6; +call truncate_history_of_t(); +select * from t for system_time all; + +set @ts1 = now(6); +update t set a=7; +set @ts2 = now(6); +update t set a=8; +truncate t for system_time timestamp from '1-1-1' to @ts1; +select * from t for system_time all; +update t set a=9; +truncate t for system_time timestamp between '1-1-1' and @ts2; +select * from t for system_time all; + + +create or replace table t (a int) with system versioning engine=innodb; +insert into t values (1); +update t set a=2; +select * from t for system_time all; + +truncate t for system_time all; +select * from t for system_time all; + +update t set a=3; +update t set a=4; +truncate t for system_time as of timestamp now(6); +select * from t for system_time all; + +truncate t for system_time timestamp between '1-1-1' and now(6); +select * from t for system_time all; + +update t set a=5; +truncate t for system_time timestamp from '1-1-1' to now(6); +select * from t for system_time all; + +update t set a=6; +call truncate_history_of_t(); +select * from t for system_time all; + +set @ts1 = now(6); +update t set a=7; +set @ts2 = now(6); +update t set a=8; +truncate t for system_time timestamp from '1-1-1' to @ts1; +select * from t for system_time all; +update t set a=9; +truncate t for system_time timestamp between '1-1-1' and @ts2; +select * from t for system_time all; + +create or replace table t (a int) with system versioning; +insert into t values (1), (2); +update t set a=11 where a=1; +set @ts1=now(6); +update t set a=22 where a=2; +select * from t for system_time all; +select * from t for system_time before timestamp @ts1; +truncate t for system_time before timestamp @ts1; +select * from t for system_time all; +truncate t for system_time before timestamp now(6); +select * from t for system_time all; + +create or replace table t (a int) with system versioning engine=innodb; +insert into t values (1), (2); +update t set a=11 where a=1; +set @ts1=now(6); +update t set a=22 where a=2; +select * from t for system_time all; +select * from t for system_time before timestamp @ts1; +select * from t for system_time before transaction 2000; +truncate t for system_time before timestamp @ts1; +select * from t for system_time all; +truncate t for system_time before timestamp now(6); +select * from t for system_time all; + +drop table t; +drop procedure truncate_history_of_t; diff --git a/mysql-test/suite/versioning/t/truncate_history.opt b/mysql-test/suite/versioning/t/truncate_history.opt deleted file mode 100644 index c1a585b67eb..00000000000 --- a/mysql-test/suite/versioning/t/truncate_history.opt +++ /dev/null @@ -1 +0,0 @@ ---versioning-hide=implicit diff --git a/mysql-test/suite/versioning/t/truncate_history.test b/mysql-test/suite/versioning/t/truncate_history.test deleted file mode 100644 index a512c432651..00000000000 --- a/mysql-test/suite/versioning/t/truncate_history.test +++ /dev/null @@ -1,119 +0,0 @@ --- source include/have_innodb.inc - -create table t (a int); ---error ER_VERSIONING_REQUIRED -truncate t for system_time all; - -delimiter ~~; -create procedure truncate_history_of_t() -begin - prepare stmt from 'truncate t for system_time timestamp between \'1-1-1\' and now(6)'; - execute stmt; - drop prepare stmt; -end~~ -delimiter ;~~ - -create or replace table t (a int) with system versioning; -insert into t values (1); -update t set a=2; -select * from t for system_time all; - -set @test = 'correct'; -create trigger trg_before before delete on t for each row set @test = 'incorrect'; -create trigger trg_after after delete on t for each row set @test = 'incorrect'; - -truncate t for system_time all; -select * from t for system_time all; - -select @test from t; -drop trigger trg_before; -drop trigger trg_after; - -update t set a=3; -update t set a=4; -truncate t for system_time as of timestamp now(6); -select * from t for system_time all; - -truncate t for system_time timestamp between '1-1-1' and now(6); -select * from t for system_time all; - -update t set a=5; -truncate t for system_time timestamp from '1-1-1' to now(6); -select * from t for system_time all; - -update t set a=6; -call truncate_history_of_t(); -select * from t for system_time all; - -set @ts1 = now(6); -update t set a=7; -set @ts2 = now(6); -update t set a=8; -truncate t for system_time timestamp from '1-1-1' to @ts1; -select * from t for system_time all; -update t set a=9; -truncate t for system_time timestamp between '1-1-1' and @ts2; -select * from t for system_time all; - - -create or replace table t (a int) with system versioning engine=innodb; -insert into t values (1); -update t set a=2; -select * from t for system_time all; - -truncate t for system_time all; -select * from t for system_time all; - -update t set a=3; -update t set a=4; -truncate t for system_time as of timestamp now(6); -select * from t for system_time all; - -truncate t for system_time timestamp between '1-1-1' and now(6); -select * from t for system_time all; - -update t set a=5; -truncate t for system_time timestamp from '1-1-1' to now(6); -select * from t for system_time all; - -update t set a=6; -call truncate_history_of_t(); -select * from t for system_time all; - -set @ts1 = now(6); -update t set a=7; -set @ts2 = now(6); -update t set a=8; -truncate t for system_time timestamp from '1-1-1' to @ts1; -select * from t for system_time all; -update t set a=9; -truncate t for system_time timestamp between '1-1-1' and @ts2; -select * from t for system_time all; - -create or replace table t (a int) with system versioning; -insert into t values (1), (2); -update t set a=11 where a=1; -set @ts1=now(6); -update t set a=22 where a=2; -select * from t for system_time all; -select * from t for system_time before timestamp @ts1; -truncate t for system_time before timestamp @ts1; -select * from t for system_time all; -truncate t for system_time before timestamp now(6); -select * from t for system_time all; - -create or replace table t (a int) with system versioning engine=innodb; -insert into t values (1), (2); -update t set a=11 where a=1; -set @ts1=now(6); -update t set a=22 where a=2; -select * from t for system_time all; -select * from t for system_time before timestamp @ts1; -select * from t for system_time before transaction 2000; -truncate t for system_time before timestamp @ts1; -select * from t for system_time all; -truncate t for system_time before timestamp now(6); -select * from t for system_time all; - -drop table t; -drop procedure truncate_history_of_t; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 067b78e3a05..589d02fb55b 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1368,21 +1368,6 @@ int MYSQLlex(YYSTYPE *yylval, THD *thd) return FOR_SYM; } break; - case QUERY_SYM: - { - CHARSET_INFO *cs= thd->charset(); - const char *p= lip->get_ptr(); - while (my_isspace(cs, *p)) - ++p; - if (lip->get_end_of_query() - p > 3 && my_isspace(cs, p[3]) && - 0 == strncasecmp(p, "for", 3)) - { - token= lex_one_token(yylval, thd); - lip->add_digest_token(token, yylval); - return QUERY_FOR_SYM; - } - return QUERY_SYM; - } default: break; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index ff3ce427ef5..2ae574398fc 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -708,7 +708,7 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, versioned_tables++; else if (table->vers_conditions) { - my_error(ER_VERSIONING_REQUIRED, MYF(0), "`FOR SYSTEM_TIME` query"); + my_error(ER_VERSIONING_REQUIRED, MYF(0), table->alias); DBUG_RETURN(-1); } } @@ -717,7 +717,7 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, { if (slex->vers_conditions) { - my_error(ER_VERSIONING_REQUIRED, MYF(0), "`FOR SYSTEM_TIME` query"); + my_error(ER_VERS_UNUSED_CLAUSE, MYF(0), "SYSTEM_TIME"); DBUG_RETURN(-1); } DBUG_RETURN(0); @@ -1014,7 +1014,7 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, if (!slex->vers_conditions.used && slex->vers_conditions) { - my_error(ER_VERS_UNUSED_CLAUSE, MYF(0), "QUERY FOR SYSTEM_TIME"); + my_error(ER_VERS_UNUSED_CLAUSE, MYF(0), "SYSTEM_TIME"); DBUG_RETURN(-1); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index b0365d2b97f..27705f6bd41 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1355,7 +1355,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token PURGE %token QUARTER_SYM %token QUERY_SYM -%token QUERY_FOR_SYM /* INTERNAL */ %token QUICK %token RAISE_SYM /* Oracle-PLSQL-R */ %token RANGE_SYM /* SQL-2003-R */ @@ -8804,7 +8803,7 @@ table_expression: opt_group_clause opt_having_clause opt_window_clause - opt_query_for_system_time_clause + opt_system_time_clause ; opt_table_expression: @@ -8850,10 +8849,10 @@ trans_or_timestamp: } ; -opt_query_for_system_time_clause: +opt_system_time_clause: /* empty */ {} - | QUERY_FOR_SYM SYSTEM_TIME_SYM for_system_time_expr + | SYSTEM_TIME_SYM system_time_expr { DBUG_ASSERT(Select); Select->vers_conditions= Lex->vers_conditions; @@ -8865,13 +8864,13 @@ opt_for_system_time_clause: { $$= false; } - | FOR_SYSTEM_TIME_SYM for_system_time_expr + | FOR_SYSTEM_TIME_SYM system_time_expr { $$= true; } ; -for_system_time_expr: +system_time_expr: AS OF_SYM trans_or_timestamp simple_expr { Lex->vers_conditions.init(FOR_SYSTEM_TIME_AS_OF, $3, $4); diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index f989e3b93ff..d7403228831 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -763,7 +763,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token PURGE %token QUARTER_SYM %token QUERY_SYM -%token QUERY_FOR_SYM /* INTERNAL */ %token QUICK %token RAISE_SYM /* Oracle-PLSQL-R */ %token RANGE_SYM /* SQL-2003-R */ -- cgit v1.2.1 From 909867d014d3fd29654a0e5bf26619c2e485b97b Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Thu, 13 Jul 2017 18:48:30 +0300 Subject: SQL: optimized fields fix for NOT NULL [fixes #226] --- .../suite/versioning/r/optimized_fields.result | 53 +++++++++++++++++++++- .../suite/versioning/t/optimized_fields.test | 19 +++++++- sql/field.cc | 2 +- sql/field.h | 4 -- sql/item.cc | 38 ++++++++++------ sql/item.h | 3 ++ sql/sql_select.cc | 50 ++++++++++++++++++++ 7 files changed, 148 insertions(+), 21 deletions(-) diff --git a/mysql-test/suite/versioning/r/optimized_fields.result b/mysql-test/suite/versioning/r/optimized_fields.result index 376eddb41b8..0cd59992ad3 100644 --- a/mysql-test/suite/versioning/r/optimized_fields.result +++ b/mysql-test/suite/versioning/r/optimized_fields.result @@ -1,4 +1,4 @@ -create table t( +create table t ( a int, b int without system versioning ) with system versioning; @@ -36,12 +36,14 @@ a b 3 NULL Warnings: Warning 4075 Attempt to read unversioned field `b` in historical query +Warning 4075 Attempt to read unversioned field `b` in historical query select * from t for system_time as of timestamp now(6) order by b desc; a b 1 NULL 3 NULL Warnings: Warning 4075 Attempt to read unversioned field `b` in historical query +Warning 4075 Attempt to read unversioned field `b` in historical query select * from t group by a having a=2 system_time as of timestamp now(6); a b Warnings: @@ -50,6 +52,7 @@ select * from t group by b having b=2 system_time as of timestamp now(6); a b Warnings: Warning 4075 Attempt to read unversioned field `b` in historical query +Warning 4075 Attempt to read unversioned field `b` in historical query select a from t where b=2 system_time as of timestamp now(6); a Warnings: @@ -68,8 +71,56 @@ select count(*), b from t group by b having b=NULL system_time as of timestamp n count(*) b Warnings: Warning 4075 Attempt to read unversioned field `b` in historical query +Warning 4075 Attempt to read unversioned field `b` in historical query select a, b from t; a b 1 2 3 4 +select count(*) from t for system_time as of timestamp now(6) group by b; +count(*) +2 +Warnings: +Warning 4075 Attempt to read unversioned field `b` in historical query +select * from t for system_time as of timestamp now(6) group by b having b=2; +a b +Warnings: +Warning 4075 Attempt to read unversioned field `b` in historical query +Warning 4075 Attempt to read unversioned field `b` in historical query +select a from t for system_time as of timestamp now(6) where b=2; +a +Warnings: +Warning 4075 Attempt to read unversioned field `b` in historical query +select a from t for system_time as of timestamp now(6) where b=NULL; +a +Warnings: +Warning 4075 Attempt to read unversioned field `b` in historical query +select a from t for system_time as of timestamp now(6) where b is NULL; +a +1 +3 +Warnings: +Warning 4075 Attempt to read unversioned field `b` in historical query +select count(*), b from t for system_time as of timestamp now(6) group by b having b=NULL; +count(*) b +Warnings: +Warning 4075 Attempt to read unversioned field `b` in historical query +Warning 4075 Attempt to read unversioned field `b` in historical query +create or replace table t ( +a int, +b int not null without system versioning +) with system versioning; +insert into t values (1, 2), (3, 4); +select * from t for system_time as of timestamp now(6); +a b +1 NULL +3 NULL +Warnings: +Warning 4075 Attempt to read unversioned field `b` in historical query +select * from t for system_time as of timestamp now(6) where b is NULL; +a b +1 NULL +3 NULL +Warnings: +Warning 4075 Attempt to read unversioned field `b` in historical query +Warning 4075 Attempt to read unversioned field `b` in historical query drop table t; diff --git a/mysql-test/suite/versioning/t/optimized_fields.test b/mysql-test/suite/versioning/t/optimized_fields.test index 321fe6d104d..6c508d04508 100644 --- a/mysql-test/suite/versioning/t/optimized_fields.test +++ b/mysql-test/suite/versioning/t/optimized_fields.test @@ -1,4 +1,4 @@ -create table t( +create table t ( a int, b int without system versioning ) with system versioning; @@ -20,4 +20,21 @@ select a from t where b is NULL system_time as of timestamp now(6); select count(*), b from t group by b having b=NULL system_time as of timestamp now(6); select a, b from t; +select count(*) from t for system_time as of timestamp now(6) group by b; +select * from t for system_time as of timestamp now(6) group by b having b=2; +select a from t for system_time as of timestamp now(6) where b=2; +select a from t for system_time as of timestamp now(6) where b=NULL; +select a from t for system_time as of timestamp now(6) where b is NULL; +select count(*), b from t for system_time as of timestamp now(6) group by b having b=NULL; + +create or replace table t ( + a int, + b int not null without system versioning +) with system versioning; + +insert into t values (1, 2), (3, 4); + +select * from t for system_time as of timestamp now(6); +select * from t for system_time as of timestamp now(6) where b is NULL; + drop table t; diff --git a/sql/field.cc b/sql/field.cc index 3a1fee59937..ac0e59773be 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1631,7 +1631,7 @@ Field::Field(uchar *ptr_arg,uint32 length_arg,uchar *null_ptr_arg, :ptr(ptr_arg), null_ptr(null_ptr_arg), table(0), orig_table(0), table_name(0), field_name(field_name_arg), option_list(0), option_struct(0), key_start(0), part_of_key(0), - part_of_key_not_clustered(0), force_null(false), part_of_sortkey(0), + part_of_key_not_clustered(0), part_of_sortkey(0), unireg_check(unireg_check_arg), field_length(length_arg), null_bit(null_bit_arg), is_created_from_null_item(FALSE), read_stats(NULL), collected_stats(0), vcol_info(0), check_constraint(0), diff --git a/sql/field.h b/sql/field.h index 317ae018066..28d47b337a7 100644 --- a/sql/field.h +++ b/sql/field.h @@ -703,8 +703,6 @@ public: /* Field is part of the following keys */ key_map key_start, part_of_key, part_of_key_not_clustered; - bool force_null; - /* Bitmap of indexes that have records ordered by col1, ... this_field, ... @@ -1090,8 +1088,6 @@ public: virtual uint size_of() const =0; // For new field inline bool is_null(my_ptrdiff_t row_offset= 0) const { - if (force_null) - return true; /* The table may have been marked as containing only NULL values for all fields if it is a NULL-complemented row of an OUTER JOIN diff --git a/sql/item.cc b/sql/item.cc index d27ab95aaa4..0df22234f88 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2759,20 +2759,6 @@ void Item_field::set_field(Field *field_par) fixed= 1; if (field->table->s->tmp_table == SYSTEM_TMP_TABLE) any_privileges= 0; - - field->force_null= false; - if (field->flags & VERS_OPTIMIZED_UPDATE_FLAG && context && - ((field->table->pos_in_table_list && - field->table->pos_in_table_list->vers_conditions) || - (context->select_lex && context->select_lex->vers_conditions))) - { - field->force_null= true; - push_warning_printf( - current_thd, Sql_condition::WARN_LEVEL_WARN, - ER_NON_VERSIONED_FIELD_IN_VERSIONED_QUERY, - ER_THD(current_thd, ER_NON_VERSIONED_FIELD_IN_VERSIONED_QUERY), - field_name); - } } @@ -10757,6 +10743,30 @@ bool Item_field::exclusive_dependence_on_grouping_fields_processor(void *arg) return true; } +Item *Item_field::vers_optimized_fields_transformer(THD *thd, uchar *) +{ + if (!field) + return this; + + if (field->flags & VERS_OPTIMIZED_UPDATE_FLAG && context && + ((field->table->pos_in_table_list && + field->table->pos_in_table_list->vers_conditions) || + (context->select_lex && context->select_lex->vers_conditions))) + { + push_warning_printf( + current_thd, Sql_condition::WARN_LEVEL_WARN, + ER_NON_VERSIONED_FIELD_IN_VERSIONED_QUERY, + ER_THD(current_thd, ER_NON_VERSIONED_FIELD_IN_VERSIONED_QUERY), + field_name); + + Item *null_item= new (thd->mem_root) Item_null(thd); + if (null_item) + return null_item; + } + + return this; +} + void Item::register_in(THD *thd) { next= thd->free_list; diff --git a/sql/item.h b/sql/item.h index eb695726472..ab2c9dd65a9 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1655,6 +1655,8 @@ public: virtual Item_field *field_for_view_update() { return 0; } + virtual Item *vers_optimized_fields_transformer(THD *thd, uchar *) + { return this; } virtual Item *neg_transformer(THD *thd) { return NULL; } virtual Item *update_value_transformer(THD *thd, uchar *select_arg) { return this; } @@ -2750,6 +2752,7 @@ public: uint32 max_display_length() const { return field->max_display_length(); } Item_field *field_for_view_update() { return this; } int fix_outer_field(THD *thd, Field **field, Item **reference); + virtual Item *vers_optimized_fields_transformer(THD *thd, uchar *); virtual Item *update_value_transformer(THD *thd, uchar *select_arg); Item *derived_field_transformer_for_having(THD *thd, uchar *arg); Item *derived_field_transformer_for_where(THD *thd, uchar *arg); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 2ae574398fc..a1fc9f16b21 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1380,6 +1380,46 @@ JOIN::prepare(TABLE_LIST *tables_init, if (!procedure && result && result->prepare(fields_list, unit_arg)) goto err; /* purecov: inspected */ + if (!thd->stmt_arena->is_stmt_prepare()) + { + bool have_versioned_tables= false; + for (TABLE_LIST *table= tables_list; table; table= table->next_local) + { + if (table->table && table->table->versioned()) + { + have_versioned_tables= true; + break; + } + } + + if (have_versioned_tables) + { + Item_transformer transformer= &Item::vers_optimized_fields_transformer; + + if (conds) + { + conds= conds->transform(thd, transformer, NULL); + } + + for (ORDER *ord= order; ord; ord= ord->next) + { + ord->item_ptr= (*ord->item)->transform(thd, transformer, NULL); + ord->item= &ord->item_ptr; + } + + for (ORDER *ord= group_list; ord; ord= ord->next) + { + ord->item_ptr= (*ord->item)->transform(thd, transformer, NULL); + ord->item= &ord->item_ptr; + } + + if (having) + { + having= having->transform(thd, transformer, NULL); + } + } + } + unit= unit_arg; if (prepare_stage2()) goto err; @@ -3827,6 +3867,16 @@ void JOIN::exec_inner() result->send_result_set_metadata( procedure ? procedure_fields_list : *fields, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF); + + { + List_iterator it(*columns_list); + while (Item *item= it++) + { + Item_transformer transformer= &Item::vers_optimized_fields_transformer; + it.replace(item->transform(thd, transformer, NULL)); + } + } + error= do_select(this, procedure); /* Accumulate the counts from all join iterations of all join parts. */ thd->inc_examined_row_count(join_examined_rows); -- cgit v1.2.1 From f8b625699282df07b4166809c0195760c7abb357 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Sat, 15 Jul 2017 13:59:15 +0300 Subject: SQL: disallow ALTER CHANGE of system fields [fixes #213] --- mysql-test/suite/versioning/r/alter.result | 16 ++++++++++++++++ mysql-test/suite/versioning/t/alter.test | 18 ++++++++++++++++++ sql/handler.cc | 6 ++++++ sql/share/errmsg-utf8.txt | 3 +++ 4 files changed, 43 insertions(+) diff --git a/mysql-test/suite/versioning/r/alter.result b/mysql-test/suite/versioning/r/alter.result index 5dff4e706cb..a4e51b1a3e2 100644 --- a/mysql-test/suite/versioning/r/alter.result +++ b/mysql-test/suite/versioning/r/alter.result @@ -495,6 +495,22 @@ alter table t without system versioning, algorithm=inplace; select * from t; a b 2 NULL +create or replace table t ( +a int, +sys_trx_start bigint(20) unsigned generated always as row start, +sys_trx_end bigint(20) unsigned generated always as row end, +period for system_time(sys_trx_start, sys_trx_end) +) with system versioning engine innodb; +alter table t change column sys_trx_start asdf bigint unsigned; +ERROR HY000: Can not change system versioning field 'sys_trx_start' +create or replace table t ( +a int, +sys_trx_start timestamp(6) generated always as row start, +sys_trx_end timestamp(6) generated always as row end, +period for system_time(sys_trx_start, sys_trx_end) +) with system versioning engine myisam; +alter table t change column sys_trx_start asdf timestamp(6); +ERROR HY000: Can not change system versioning field 'sys_trx_start' call verify_vtq; No A B C D 1 1 1 1 1 diff --git a/mysql-test/suite/versioning/t/alter.test b/mysql-test/suite/versioning/t/alter.test index 40d65f258a3..edbb107b566 100644 --- a/mysql-test/suite/versioning/t/alter.test +++ b/mysql-test/suite/versioning/t/alter.test @@ -220,6 +220,24 @@ select * from t for system_time all; alter table t without system versioning, algorithm=inplace; select * from t; +create or replace table t ( + a int, + sys_trx_start bigint(20) unsigned generated always as row start, + sys_trx_end bigint(20) unsigned generated always as row end, + period for system_time(sys_trx_start, sys_trx_end) +) with system versioning engine innodb; +--error ER_VERS_ALTER_SYSTEM_FIELD +alter table t change column sys_trx_start asdf bigint unsigned; + +create or replace table t ( + a int, + sys_trx_start timestamp(6) generated always as row start, + sys_trx_end timestamp(6) generated always as row end, + period for system_time(sys_trx_start, sys_trx_end) +) with system versioning engine myisam; +--error ER_VERS_ALTER_SYSTEM_FIELD +alter table t change column sys_trx_start asdf timestamp(6); + call verify_vtq; drop table t; diff --git a/sql/handler.cc b/sql/handler.cc index ae685482219..9f4ab646aaa 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6869,6 +6869,12 @@ bool Vers_parse_info::check_and_fix_alter(THD *thd, Alter_info *alter_info, { if (f->versioning == Column_definition::WITHOUT_VERSIONING) f->flags|= VERS_OPTIMIZED_UPDATE_FLAG; + + if (f->change && (!strcmp(f->change, start) || !strcmp(f->change, end))) + { + my_error(ER_VERS_ALTER_SYSTEM_FIELD, MYF(0), f->change); + return true; + } } } diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index bbe4e6cff0e..1a386c4f16c 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7591,3 +7591,6 @@ ER_VERS_HISTORY_LOCK ER_WRONG_TABLESPACE_NAME 42000 eng "Incorrect tablespace name `%-.192s`" + +ER_VERS_ALTER_SYSTEM_FIELD + eng "Can not change system versioning field '%s'" -- cgit v1.2.1 From c99bd3ac1ac94f32c7945c485d8079e03b2ea577 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Thu, 20 Jul 2017 15:00:10 +0300 Subject: Tests: truncate.test: get rid of transaction number --- mysql-test/suite/versioning/r/truncate.result | 6 +++++- mysql-test/suite/versioning/t/truncate.test | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/versioning/r/truncate.result b/mysql-test/suite/versioning/r/truncate.result index 1ad9090f644..9d8b92d6254 100644 --- a/mysql-test/suite/versioning/r/truncate.result +++ b/mysql-test/suite/versioning/r/truncate.result @@ -150,7 +150,9 @@ a select * from t for system_time before timestamp @ts1; a 1 -select * from t for system_time before transaction 2000; +insert into t values (33); +select max(sys_trx_start) from t into @tx; +select * from t for system_time before transaction @tx; a 1 2 @@ -160,10 +162,12 @@ a 11 22 2 +33 truncate t for system_time before timestamp now(6); select * from t for system_time all; a 11 22 +33 drop table t; drop procedure truncate_history_of_t; diff --git a/mysql-test/suite/versioning/t/truncate.test b/mysql-test/suite/versioning/t/truncate.test index 7bf5c59acf8..b51e2ad9311 100644 --- a/mysql-test/suite/versioning/t/truncate.test +++ b/mysql-test/suite/versioning/t/truncate.test @@ -109,7 +109,9 @@ set @ts1=now(6); update t set a=22 where a=2; select * from t for system_time all; select * from t for system_time before timestamp @ts1; -select * from t for system_time before transaction 2000; +insert into t values (33); +select max(sys_trx_start) from t into @tx; +select * from t for system_time before transaction @tx; truncate t for system_time before timestamp @ts1; select * from t for system_time all; truncate t for system_time before timestamp now(6); -- cgit v1.2.1 From c2f6214671a07965a1fa5e629f69e1226ea40fa5 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Fri, 21 Jul 2017 07:53:58 +0300 Subject: Tests: renamed optimized_fields to optimized --- mysql-test/suite/versioning/r/optimized.result | 126 +++++++++++++++++++++ .../suite/versioning/r/optimized_fields.result | 126 --------------------- mysql-test/suite/versioning/t/optimized.test | 40 +++++++ .../suite/versioning/t/optimized_fields.test | 40 ------- 4 files changed, 166 insertions(+), 166 deletions(-) create mode 100644 mysql-test/suite/versioning/r/optimized.result delete mode 100644 mysql-test/suite/versioning/r/optimized_fields.result create mode 100644 mysql-test/suite/versioning/t/optimized.test delete mode 100644 mysql-test/suite/versioning/t/optimized_fields.test diff --git a/mysql-test/suite/versioning/r/optimized.result b/mysql-test/suite/versioning/r/optimized.result new file mode 100644 index 00000000000..0cd59992ad3 --- /dev/null +++ b/mysql-test/suite/versioning/r/optimized.result @@ -0,0 +1,126 @@ +create table t ( +a int, +b int without system versioning +) with system versioning; +insert into t values(1, 2); +insert into t values(3, 4); +select * from t; +a b +1 2 +3 4 +select a from t for system_time as of timestamp now(6); +a +1 +3 +select a, b, b+0 from t for system_time as of timestamp now(6); +a b b+0 +1 NULL NULL +3 NULL NULL +Warnings: +Warning 4075 Attempt to read unversioned field `b` in historical query +Warning 4075 Attempt to read unversioned field `b` in historical query +select * from t for system_time as of timestamp now(6); +a b +1 NULL +3 NULL +Warnings: +Warning 4075 Attempt to read unversioned field `b` in historical query +select count(*) from t group by b system_time as of timestamp now(6); +count(*) +2 +Warnings: +Warning 4075 Attempt to read unversioned field `b` in historical query +select * from t for system_time as of timestamp now(6) order by b asc; +a b +1 NULL +3 NULL +Warnings: +Warning 4075 Attempt to read unversioned field `b` in historical query +Warning 4075 Attempt to read unversioned field `b` in historical query +select * from t for system_time as of timestamp now(6) order by b desc; +a b +1 NULL +3 NULL +Warnings: +Warning 4075 Attempt to read unversioned field `b` in historical query +Warning 4075 Attempt to read unversioned field `b` in historical query +select * from t group by a having a=2 system_time as of timestamp now(6); +a b +Warnings: +Warning 4075 Attempt to read unversioned field `b` in historical query +select * from t group by b having b=2 system_time as of timestamp now(6); +a b +Warnings: +Warning 4075 Attempt to read unversioned field `b` in historical query +Warning 4075 Attempt to read unversioned field `b` in historical query +select a from t where b=2 system_time as of timestamp now(6); +a +Warnings: +Warning 4075 Attempt to read unversioned field `b` in historical query +select a from t where b=NULL system_time as of timestamp now(6); +a +Warnings: +Warning 4075 Attempt to read unversioned field `b` in historical query +select a from t where b is NULL system_time as of timestamp now(6); +a +1 +3 +Warnings: +Warning 4075 Attempt to read unversioned field `b` in historical query +select count(*), b from t group by b having b=NULL system_time as of timestamp now(6); +count(*) b +Warnings: +Warning 4075 Attempt to read unversioned field `b` in historical query +Warning 4075 Attempt to read unversioned field `b` in historical query +select a, b from t; +a b +1 2 +3 4 +select count(*) from t for system_time as of timestamp now(6) group by b; +count(*) +2 +Warnings: +Warning 4075 Attempt to read unversioned field `b` in historical query +select * from t for system_time as of timestamp now(6) group by b having b=2; +a b +Warnings: +Warning 4075 Attempt to read unversioned field `b` in historical query +Warning 4075 Attempt to read unversioned field `b` in historical query +select a from t for system_time as of timestamp now(6) where b=2; +a +Warnings: +Warning 4075 Attempt to read unversioned field `b` in historical query +select a from t for system_time as of timestamp now(6) where b=NULL; +a +Warnings: +Warning 4075 Attempt to read unversioned field `b` in historical query +select a from t for system_time as of timestamp now(6) where b is NULL; +a +1 +3 +Warnings: +Warning 4075 Attempt to read unversioned field `b` in historical query +select count(*), b from t for system_time as of timestamp now(6) group by b having b=NULL; +count(*) b +Warnings: +Warning 4075 Attempt to read unversioned field `b` in historical query +Warning 4075 Attempt to read unversioned field `b` in historical query +create or replace table t ( +a int, +b int not null without system versioning +) with system versioning; +insert into t values (1, 2), (3, 4); +select * from t for system_time as of timestamp now(6); +a b +1 NULL +3 NULL +Warnings: +Warning 4075 Attempt to read unversioned field `b` in historical query +select * from t for system_time as of timestamp now(6) where b is NULL; +a b +1 NULL +3 NULL +Warnings: +Warning 4075 Attempt to read unversioned field `b` in historical query +Warning 4075 Attempt to read unversioned field `b` in historical query +drop table t; diff --git a/mysql-test/suite/versioning/r/optimized_fields.result b/mysql-test/suite/versioning/r/optimized_fields.result deleted file mode 100644 index 0cd59992ad3..00000000000 --- a/mysql-test/suite/versioning/r/optimized_fields.result +++ /dev/null @@ -1,126 +0,0 @@ -create table t ( -a int, -b int without system versioning -) with system versioning; -insert into t values(1, 2); -insert into t values(3, 4); -select * from t; -a b -1 2 -3 4 -select a from t for system_time as of timestamp now(6); -a -1 -3 -select a, b, b+0 from t for system_time as of timestamp now(6); -a b b+0 -1 NULL NULL -3 NULL NULL -Warnings: -Warning 4075 Attempt to read unversioned field `b` in historical query -Warning 4075 Attempt to read unversioned field `b` in historical query -select * from t for system_time as of timestamp now(6); -a b -1 NULL -3 NULL -Warnings: -Warning 4075 Attempt to read unversioned field `b` in historical query -select count(*) from t group by b system_time as of timestamp now(6); -count(*) -2 -Warnings: -Warning 4075 Attempt to read unversioned field `b` in historical query -select * from t for system_time as of timestamp now(6) order by b asc; -a b -1 NULL -3 NULL -Warnings: -Warning 4075 Attempt to read unversioned field `b` in historical query -Warning 4075 Attempt to read unversioned field `b` in historical query -select * from t for system_time as of timestamp now(6) order by b desc; -a b -1 NULL -3 NULL -Warnings: -Warning 4075 Attempt to read unversioned field `b` in historical query -Warning 4075 Attempt to read unversioned field `b` in historical query -select * from t group by a having a=2 system_time as of timestamp now(6); -a b -Warnings: -Warning 4075 Attempt to read unversioned field `b` in historical query -select * from t group by b having b=2 system_time as of timestamp now(6); -a b -Warnings: -Warning 4075 Attempt to read unversioned field `b` in historical query -Warning 4075 Attempt to read unversioned field `b` in historical query -select a from t where b=2 system_time as of timestamp now(6); -a -Warnings: -Warning 4075 Attempt to read unversioned field `b` in historical query -select a from t where b=NULL system_time as of timestamp now(6); -a -Warnings: -Warning 4075 Attempt to read unversioned field `b` in historical query -select a from t where b is NULL system_time as of timestamp now(6); -a -1 -3 -Warnings: -Warning 4075 Attempt to read unversioned field `b` in historical query -select count(*), b from t group by b having b=NULL system_time as of timestamp now(6); -count(*) b -Warnings: -Warning 4075 Attempt to read unversioned field `b` in historical query -Warning 4075 Attempt to read unversioned field `b` in historical query -select a, b from t; -a b -1 2 -3 4 -select count(*) from t for system_time as of timestamp now(6) group by b; -count(*) -2 -Warnings: -Warning 4075 Attempt to read unversioned field `b` in historical query -select * from t for system_time as of timestamp now(6) group by b having b=2; -a b -Warnings: -Warning 4075 Attempt to read unversioned field `b` in historical query -Warning 4075 Attempt to read unversioned field `b` in historical query -select a from t for system_time as of timestamp now(6) where b=2; -a -Warnings: -Warning 4075 Attempt to read unversioned field `b` in historical query -select a from t for system_time as of timestamp now(6) where b=NULL; -a -Warnings: -Warning 4075 Attempt to read unversioned field `b` in historical query -select a from t for system_time as of timestamp now(6) where b is NULL; -a -1 -3 -Warnings: -Warning 4075 Attempt to read unversioned field `b` in historical query -select count(*), b from t for system_time as of timestamp now(6) group by b having b=NULL; -count(*) b -Warnings: -Warning 4075 Attempt to read unversioned field `b` in historical query -Warning 4075 Attempt to read unversioned field `b` in historical query -create or replace table t ( -a int, -b int not null without system versioning -) with system versioning; -insert into t values (1, 2), (3, 4); -select * from t for system_time as of timestamp now(6); -a b -1 NULL -3 NULL -Warnings: -Warning 4075 Attempt to read unversioned field `b` in historical query -select * from t for system_time as of timestamp now(6) where b is NULL; -a b -1 NULL -3 NULL -Warnings: -Warning 4075 Attempt to read unversioned field `b` in historical query -Warning 4075 Attempt to read unversioned field `b` in historical query -drop table t; diff --git a/mysql-test/suite/versioning/t/optimized.test b/mysql-test/suite/versioning/t/optimized.test new file mode 100644 index 00000000000..6c508d04508 --- /dev/null +++ b/mysql-test/suite/versioning/t/optimized.test @@ -0,0 +1,40 @@ +create table t ( + a int, + b int without system versioning +) with system versioning; + +insert into t values(1, 2); +insert into t values(3, 4); +select * from t; +select a from t for system_time as of timestamp now(6); +select a, b, b+0 from t for system_time as of timestamp now(6); +select * from t for system_time as of timestamp now(6); +select count(*) from t group by b system_time as of timestamp now(6); +select * from t for system_time as of timestamp now(6) order by b asc; +select * from t for system_time as of timestamp now(6) order by b desc; +select * from t group by a having a=2 system_time as of timestamp now(6); +select * from t group by b having b=2 system_time as of timestamp now(6); +select a from t where b=2 system_time as of timestamp now(6); +select a from t where b=NULL system_time as of timestamp now(6); +select a from t where b is NULL system_time as of timestamp now(6); +select count(*), b from t group by b having b=NULL system_time as of timestamp now(6); +select a, b from t; + +select count(*) from t for system_time as of timestamp now(6) group by b; +select * from t for system_time as of timestamp now(6) group by b having b=2; +select a from t for system_time as of timestamp now(6) where b=2; +select a from t for system_time as of timestamp now(6) where b=NULL; +select a from t for system_time as of timestamp now(6) where b is NULL; +select count(*), b from t for system_time as of timestamp now(6) group by b having b=NULL; + +create or replace table t ( + a int, + b int not null without system versioning +) with system versioning; + +insert into t values (1, 2), (3, 4); + +select * from t for system_time as of timestamp now(6); +select * from t for system_time as of timestamp now(6) where b is NULL; + +drop table t; diff --git a/mysql-test/suite/versioning/t/optimized_fields.test b/mysql-test/suite/versioning/t/optimized_fields.test deleted file mode 100644 index 6c508d04508..00000000000 --- a/mysql-test/suite/versioning/t/optimized_fields.test +++ /dev/null @@ -1,40 +0,0 @@ -create table t ( - a int, - b int without system versioning -) with system versioning; - -insert into t values(1, 2); -insert into t values(3, 4); -select * from t; -select a from t for system_time as of timestamp now(6); -select a, b, b+0 from t for system_time as of timestamp now(6); -select * from t for system_time as of timestamp now(6); -select count(*) from t group by b system_time as of timestamp now(6); -select * from t for system_time as of timestamp now(6) order by b asc; -select * from t for system_time as of timestamp now(6) order by b desc; -select * from t group by a having a=2 system_time as of timestamp now(6); -select * from t group by b having b=2 system_time as of timestamp now(6); -select a from t where b=2 system_time as of timestamp now(6); -select a from t where b=NULL system_time as of timestamp now(6); -select a from t where b is NULL system_time as of timestamp now(6); -select count(*), b from t group by b having b=NULL system_time as of timestamp now(6); -select a, b from t; - -select count(*) from t for system_time as of timestamp now(6) group by b; -select * from t for system_time as of timestamp now(6) group by b having b=2; -select a from t for system_time as of timestamp now(6) where b=2; -select a from t for system_time as of timestamp now(6) where b=NULL; -select a from t for system_time as of timestamp now(6) where b is NULL; -select count(*), b from t for system_time as of timestamp now(6) group by b having b=NULL; - -create or replace table t ( - a int, - b int not null without system versioning -) with system versioning; - -insert into t values (1, 2), (3, 4); - -select * from t for system_time as of timestamp now(6); -select * from t for system_time as of timestamp now(6) where b is NULL; - -drop table t; -- cgit v1.2.1 From a5ec9fc1b409c22b0d9a18999525c5b234c28113 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Fri, 21 Jul 2017 17:52:47 +0300 Subject: Style: mysqld.h comments --- sql/mysqld.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sql/mysqld.h b/sql/mysqld.h index e8a72b0b063..5ca5570460e 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -176,6 +176,7 @@ extern char *opt_backup_history_logname, *opt_backup_progress_logname, extern const char *log_output_str; extern const char *log_backup_output_str; +/* System Versioning begin */ enum vers_range_type_t { FOR_SYSTEM_TIME_UNSPECIFIED = 0, @@ -186,8 +187,11 @@ enum vers_range_type_t FOR_SYSTEM_TIME_BEFORE }; +/* Used only for @@versioning_current_time sysvar. This struct must be POD + * because of str_value, which is used as interface to user. + * So no virtual-anything! */ struct st_vers_current_time -{ // This struct must be POD, so no virtual-anything! +{ char *str_value; // must be first vers_range_type_t type; MYSQL_TIME ltime; @@ -197,12 +201,15 @@ struct st_vers_current_time {} }; -enum vers_hide_enum { +enum vers_hide_enum +{ VERS_HIDE_AUTO= 0, VERS_HIDE_IMPLICIT, VERS_HIDE_FULL, VERS_HIDE_NEVER }; +/* System Versioning end */ + extern char *mysql_home_ptr, *pidfile_name_ptr; extern MYSQL_PLUGIN_IMPORT char glob_hostname[FN_REFLEN]; extern char mysql_home[FN_REFLEN]; -- cgit v1.2.1 From aa292666cc3e25e267b5d69e80f30596f84f352d Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Sun, 23 Jul 2017 17:07:56 +0300 Subject: Parser: moved 'for system_time' before alias Due to standard (see 7.6
). --- mysql-test/suite/versioning/r/cte.result | 8 ++++---- mysql-test/suite/versioning/r/derived.result | 14 +++++++++----- mysql-test/suite/versioning/r/vtmd.result | 8 ++++---- mysql-test/suite/versioning/r/vtmd_show.result | 4 ++-- mysql-test/suite/versioning/t/cte.test | 8 ++++---- mysql-test/suite/versioning/t/derived.test | 12 ++++++++---- mysql-test/suite/versioning/t/vtmd.test | 8 ++++---- mysql-test/suite/versioning/t/vtmd_show.test | 4 ++-- sql/sql_yacc.yy | 6 +++--- 9 files changed, 40 insertions(+), 32 deletions(-) diff --git a/mysql-test/suite/versioning/r/cte.result b/mysql-test/suite/versioning/r/cte.result index 5fe71901b44..161255aeaa7 100644 --- a/mysql-test/suite/versioning/r/cte.result +++ b/mysql-test/suite/versioning/r/cte.result @@ -33,11 +33,11 @@ ancestors as ( select e.emp_id, e.name, e.mgr, e.salary -from emp as e for system_time as of timestamp @ts_1 +from emp for system_time as of timestamp @ts_1 as e where name = 'bill' union select e.emp_id, e.name, e.mgr, e.salary -from emp as e for system_time as of timestamp @ts_1, +from emp for system_time as of timestamp @ts_1 as e, ancestors as a where e.mgr = a.emp_id ) @@ -51,11 +51,11 @@ ancestors as ( select e.emp_id, e.name, e.mgr, e.salary -from emp as e for system_time as of timestamp @ts_2 +from emp for system_time as of timestamp @ts_2 as e where name = 'bill' union select e.emp_id, e.name, e.mgr, e.salary -from emp as e for system_time as of timestamp @ts_2, +from emp for system_time as of timestamp @ts_2 as e, ancestors as a where e.mgr = a.emp_id ) diff --git a/mysql-test/suite/versioning/r/derived.result b/mysql-test/suite/versioning/r/derived.result index 96e8c0afa55..04a237f6428 100644 --- a/mysql-test/suite/versioning/r/derived.result +++ b/mysql-test/suite/versioning/r/derived.result @@ -91,12 +91,14 @@ ancestors as ( select e.emp_id, e.name, e.mgr -from emp as e for system_time as of timestamp @ts +from emp as e where name = 'bill' - union + system_time as of timestamp @ts +union select ee.emp_id, ee.name, ee.mgr -from emp as ee for system_time as of timestamp @ts, ancestors as a for system_time as of timestamp @ts +from emp as ee, ancestors as a where ee.mgr = a.emp_id +system_time as of timestamp @ts ) select * from ancestors; emp_id name mgr @@ -109,12 +111,14 @@ ancestors as ( select e.emp_id, e.name, e.mgr - from emp as e for system_time as of timestamp @ts + from emp as e where name = 'bill' + system_time as of timestamp @ts union select ee.emp_id, ee.name, ee.mgr - from emp as ee for system_time as of timestamp @ts, ancestors as a for system_time as of timestamp @ts + from emp as ee, ancestors as a where ee.mgr = a.emp_id + system_time as of timestamp @ts ) select * from ancestors"; prepare stmt from @tmp; diff --git a/mysql-test/suite/versioning/r/vtmd.result b/mysql-test/suite/versioning/r/vtmd.result index 808f6e7d92d..d2cb726ac6f 100644 --- a/mysql-test/suite/versioning/r/vtmd.result +++ b/mysql-test/suite/versioning/r/vtmd.result @@ -8,8 +8,8 @@ declare continue handler for not found set cur_done = true; set @tmp= concat(' create or replace temporary table cur_tmp as - select vtmd.archive_name from ', vtmd_name, ' as vtmd - for system_time all + select vtmd.archive_name from ', vtmd_name, ' + for system_time all as vtmd where vtmd.archive_name is not null group by vtmd.archive_name'); prepare stmt from @tmp; execute stmt; drop prepare stmt; @@ -29,8 +29,8 @@ begin set @tmp= concat(' create or replace temporary table tmp_vtmd with system versioning as - select * from ', vtmd_name, ' as vtmd - for system_time all'); + select * from ', vtmd_name, ' + for system_time all as vtmd'); prepare stmt from @tmp; execute stmt; drop prepare stmt; set @inf= 0xFFFFFFFFFFFFFFFF + 0; set @start= null; diff --git a/mysql-test/suite/versioning/r/vtmd_show.result b/mysql-test/suite/versioning/r/vtmd_show.result index bcece5cba1f..5bc735f0a72 100644 --- a/mysql-test/suite/versioning/r/vtmd_show.result +++ b/mysql-test/suite/versioning/r/vtmd_show.result @@ -8,8 +8,8 @@ declare continue handler for not found set cur_done = true; set @tmp= concat(' create or replace temporary table cur_tmp as - select vtmd.archive_name from ', vtmd_name, ' as vtmd - for system_time all + select vtmd.archive_name from ', vtmd_name, ' + for system_time all as vtmd where vtmd.archive_name is not null group by vtmd.archive_name'); prepare stmt from @tmp; execute stmt; drop prepare stmt; diff --git a/mysql-test/suite/versioning/t/cte.test b/mysql-test/suite/versioning/t/cte.test index 22c72bd9ed1..7a35352f7c8 100644 --- a/mysql-test/suite/versioning/t/cte.test +++ b/mysql-test/suite/versioning/t/cte.test @@ -39,11 +39,11 @@ ancestors as ( select e.emp_id, e.name, e.mgr, e.salary - from emp as e for system_time as of timestamp @ts_1 + from emp for system_time as of timestamp @ts_1 as e where name = 'bill' union select e.emp_id, e.name, e.mgr, e.salary - from emp as e for system_time as of timestamp @ts_1, + from emp for system_time as of timestamp @ts_1 as e, ancestors as a where e.mgr = a.emp_id ) @@ -55,11 +55,11 @@ ancestors as ( select e.emp_id, e.name, e.mgr, e.salary - from emp as e for system_time as of timestamp @ts_2 + from emp for system_time as of timestamp @ts_2 as e where name = 'bill' union select e.emp_id, e.name, e.mgr, e.salary - from emp as e for system_time as of timestamp @ts_2, + from emp for system_time as of timestamp @ts_2 as e, ancestors as a where e.mgr = a.emp_id ) diff --git a/mysql-test/suite/versioning/t/derived.test b/mysql-test/suite/versioning/t/derived.test index d8b37298210..63683e251c9 100644 --- a/mysql-test/suite/versioning/t/derived.test +++ b/mysql-test/suite/versioning/t/derived.test @@ -62,12 +62,14 @@ ancestors as ( select e.emp_id, e.name, e.mgr - from emp as e for system_time as of timestamp @ts + from emp as e where name = 'bill' + system_time as of timestamp @ts union select ee.emp_id, ee.name, ee.mgr - from emp as ee for system_time as of timestamp @ts, ancestors as a for system_time as of timestamp @ts + from emp as ee, ancestors as a where ee.mgr = a.emp_id + system_time as of timestamp @ts ) select * from ancestors; set @tmp= " @@ -76,12 +78,14 @@ ancestors as ( select e.emp_id, e.name, e.mgr - from emp as e for system_time as of timestamp @ts + from emp as e where name = 'bill' + system_time as of timestamp @ts union select ee.emp_id, ee.name, ee.mgr - from emp as ee for system_time as of timestamp @ts, ancestors as a for system_time as of timestamp @ts + from emp as ee, ancestors as a where ee.mgr = a.emp_id + system_time as of timestamp @ts ) select * from ancestors"; prepare stmt from @tmp; execute stmt; drop prepare stmt; diff --git a/mysql-test/suite/versioning/t/vtmd.test b/mysql-test/suite/versioning/t/vtmd.test index 01b68275737..b81674f675e 100644 --- a/mysql-test/suite/versioning/t/vtmd.test +++ b/mysql-test/suite/versioning/t/vtmd.test @@ -11,8 +11,8 @@ begin set @tmp= concat(' create or replace temporary table cur_tmp as - select vtmd.archive_name from ', vtmd_name, ' as vtmd - for system_time all + select vtmd.archive_name from ', vtmd_name, ' + for system_time all as vtmd where vtmd.archive_name is not null group by vtmd.archive_name'); prepare stmt from @tmp; execute stmt; drop prepare stmt; @@ -37,8 +37,8 @@ begin set @tmp= concat(' create or replace temporary table tmp_vtmd with system versioning as - select * from ', vtmd_name, ' as vtmd - for system_time all'); + select * from ', vtmd_name, ' + for system_time all as vtmd'); prepare stmt from @tmp; execute stmt; drop prepare stmt; set @inf= 0xFFFFFFFFFFFFFFFF + 0; diff --git a/mysql-test/suite/versioning/t/vtmd_show.test b/mysql-test/suite/versioning/t/vtmd_show.test index a4d946bbd55..036c233bd9e 100644 --- a/mysql-test/suite/versioning/t/vtmd_show.test +++ b/mysql-test/suite/versioning/t/vtmd_show.test @@ -10,8 +10,8 @@ begin set @tmp= concat(' create or replace temporary table cur_tmp as - select vtmd.archive_name from ', vtmd_name, ' as vtmd - for system_time all + select vtmd.archive_name from ', vtmd_name, ' + for system_time all as vtmd where vtmd.archive_name is not null group by vtmd.archive_name'); prepare stmt from @tmp; execute stmt; drop prepare stmt; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 27705f6bd41..4cab239795d 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -11334,9 +11334,9 @@ table_primary_ident: SELECT_LEX *sel= Select; sel->table_join_options= 0; } - table_ident opt_use_partition opt_table_alias opt_key_definition opt_for_system_time_clause + table_ident opt_use_partition opt_for_system_time_clause opt_table_alias opt_key_definition { - if (!($$= Select->add_table_to_list(thd, $2, $4, + if (!($$= Select->add_table_to_list(thd, $2, $5, Select->get_table_join_options(), YYPS->m_lock_type, YYPS->m_mdl_type, @@ -11344,7 +11344,7 @@ table_primary_ident: $3))) MYSQL_YYABORT; Select->add_joined_table($$); - if ($6) + if ($4) $$->vers_conditions= Lex->vers_conditions; } ; -- cgit v1.2.1 From 88454b3320792a02b6d683e213e414d65fc6df8c Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 24 Jul 2017 16:22:59 +0300 Subject: SQL: comment and check about ALTER in update_auto_increment() --- sql/handler.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/handler.cc b/sql/handler.cc index 9f4ab646aaa..7e7f161f14f 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -3029,7 +3029,8 @@ int handler::update_auto_increment() enum enum_check_fields save_count_cuted_fields; DBUG_ENTER("handler::update_auto_increment"); - if (table->versioned_by_sql()) + // System Versioning: handle ALTER ADD COLUMN AUTO_INCREMENT + if (thd->lex->sql_command == SQLCOM_ALTER_TABLE && table->versioned_by_sql()) { Field *end= table->vers_end_field(); DBUG_ASSERT(end); -- cgit v1.2.1 From d998da03069dca1aae83ec6af7eb407bbdc9fc58 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Mon, 31 Jul 2017 11:42:48 +0300 Subject: SQL: replication fixes [fixes #234] --- mysql-test/suite/versioning/r/rpl_mixed.result | 118 +++++++++++++++++++++ mysql-test/suite/versioning/r/rpl_row.result | 54 ++++------ mysql-test/suite/versioning/r/rpl_stmt.result | 54 ++++------ .../suite/versioning/r/truncate_innodb_rpl.result | 7 -- .../suite/versioning/t/rpl_mixed.combinations | 5 + mysql-test/suite/versioning/t/rpl_mixed.test | 7 ++ mysql-test/suite/versioning/t/rpl_row.combinations | 5 + .../suite/versioning/t/rpl_stmt.combinations | 5 + mysql-test/suite/versioning/t/rpl_test.inc | 43 +++----- .../suite/versioning/t/truncate_innodb_rpl.test | 10 -- sql/handler.cc | 2 + sql/log_event.cc | 56 ++++++++-- sql/log_event.h | 5 + sql/sql_class.h | 18 ++++ sql/sql_delete.cc | 10 +- sql/sql_insert.cc | 6 +- sql/sql_update.cc | 21 +++- 17 files changed, 300 insertions(+), 126 deletions(-) create mode 100644 mysql-test/suite/versioning/r/rpl_mixed.result delete mode 100644 mysql-test/suite/versioning/r/truncate_innodb_rpl.result create mode 100644 mysql-test/suite/versioning/t/rpl_mixed.combinations create mode 100644 mysql-test/suite/versioning/t/rpl_mixed.test create mode 100644 mysql-test/suite/versioning/t/rpl_row.combinations create mode 100644 mysql-test/suite/versioning/t/rpl_stmt.combinations delete mode 100644 mysql-test/suite/versioning/t/truncate_innodb_rpl.test diff --git a/mysql-test/suite/versioning/r/rpl_mixed.result b/mysql-test/suite/versioning/r/rpl_mixed.result new file mode 100644 index 00000000000..b91c8fd33c8 --- /dev/null +++ b/mysql-test/suite/versioning/r/rpl_mixed.result @@ -0,0 +1,118 @@ +include/master-slave.inc +[connection master] +connection slave; +connection master; +CREATE TABLE t1 (x int) with system versioning; +insert into t1 values (1); +SELECT * FROM t1; +x +1 +delete from t1; +select * from t1; +x +select * from t1 for system_time all; +x +1 +connection slave; +select * from t1; +x +select * from t1 for system_time all; +x +1 +connection master; +insert into t1 values (2); +connection slave; +select * from t1; +x +2 +connection master; +update t1 set x = 3; +connection slave; +select * from t1; +x +3 +select * from t1 for system_time all; +x +1 +3 +2 +connection master; +create or replace table t1 (x int primary key); +connection slave; +alter table t1 with system versioning; +connection master; +insert into t1 values (1); +connection slave; +select * from t1; +x +1 +select * from t1 for system_time all; +x +1 +connection master; +update t1 set x= 2 where x = 1; +connection slave; +select * from t1; +x +2 +select * from t1 for system_time all; +x +1 +2 +connection master; +delete from t1; +connection slave; +select * from t1; +x +select * from t1 for system_time all; +x +1 +2 +connection master; +create or replace table t1 (x int); +connection slave; +alter table t1 with system versioning; +connection master; +insert into t1 values (1); +update t1 set x= 2 where x = 1; +connection slave; +select * from t1; +x +2 +select * from t1 for system_time all; +x +2 +1 +connection master; +delete from t1; +connection slave; +select * from t1; +x +select * from t1 for system_time all; +x +2 +1 +connection master; +create or replace table t1 (x int) with system versioning; +create or replace table t2 (x int) with system versioning; +insert into t1 values (1); +insert into t2 values (2); +update t1, t2 set t1.x=11, t2.x=22; +connection slave; +select * from t1; +x +11 +select * from t2; +x +22 +select * from t1 for system_time all; +x +11 +1 +select * from t2 for system_time all; +x +22 +2 +connection master; +drop table t1, t2; +include/rpl_end.inc diff --git a/mysql-test/suite/versioning/r/rpl_row.result b/mysql-test/suite/versioning/r/rpl_row.result index 6d41ed6ff7b..b91c8fd33c8 100644 --- a/mysql-test/suite/versioning/r/rpl_row.result +++ b/mysql-test/suite/versioning/r/rpl_row.result @@ -2,7 +2,7 @@ include/master-slave.inc [connection master] connection slave; connection master; -CREATE TABLE t1 (x int) with system versioning ENGINE = innodb; +CREATE TABLE t1 (x int) with system versioning; insert into t1 values (1); SELECT * FROM t1; x @@ -37,11 +37,19 @@ x 3 2 connection master; -create or replace table t1 (x int primary key) engine = innodb; +create or replace table t1 (x int primary key); connection slave; alter table t1 with system versioning; connection master; insert into t1 values (1); +connection slave; +select * from t1; +x +1 +select * from t1 for system_time all; +x +1 +connection master; update t1 set x= 2 where x = 1; connection slave; select * from t1; @@ -61,7 +69,7 @@ x 1 2 connection master; -create or replace table t1 (x int) engine = innodb; +create or replace table t1 (x int); connection slave; alter table t1 with system versioning; connection master; @@ -85,42 +93,26 @@ x 2 1 connection master; -create or replace table t1 (x int primary key) with system versioning engine = innodb; -connection slave; -alter table t1 without system versioning; -connection master; +create or replace table t1 (x int) with system versioning; +create or replace table t2 (x int) with system versioning; insert into t1 values (1); -update t1 set x= 2 where x = 1; -select * from t1 for system_time all; -x -1 -2 +insert into t2 values (2); +update t1, t2 set t1.x=11, t2.x=22; connection slave; select * from t1; x -2 -connection master; -delete from t1; +11 +select * from t2; +x +22 select * from t1 for system_time all; x +11 1 -2 -connection slave; -select * from t1; +select * from t2 for system_time all; x -connection master; -create or replace table t1 (a int) with system versioning engine = innodb; -insert into t1 values (1); -update t1 set a=2; -select * from t1 for system_time all; -a +22 2 -1 -connection slave; -select * from t1 for system_time all; -a -2 -1 connection master; -drop table t1; +drop table t1, t2; include/rpl_end.inc diff --git a/mysql-test/suite/versioning/r/rpl_stmt.result b/mysql-test/suite/versioning/r/rpl_stmt.result index 6d41ed6ff7b..b91c8fd33c8 100644 --- a/mysql-test/suite/versioning/r/rpl_stmt.result +++ b/mysql-test/suite/versioning/r/rpl_stmt.result @@ -2,7 +2,7 @@ include/master-slave.inc [connection master] connection slave; connection master; -CREATE TABLE t1 (x int) with system versioning ENGINE = innodb; +CREATE TABLE t1 (x int) with system versioning; insert into t1 values (1); SELECT * FROM t1; x @@ -37,11 +37,19 @@ x 3 2 connection master; -create or replace table t1 (x int primary key) engine = innodb; +create or replace table t1 (x int primary key); connection slave; alter table t1 with system versioning; connection master; insert into t1 values (1); +connection slave; +select * from t1; +x +1 +select * from t1 for system_time all; +x +1 +connection master; update t1 set x= 2 where x = 1; connection slave; select * from t1; @@ -61,7 +69,7 @@ x 1 2 connection master; -create or replace table t1 (x int) engine = innodb; +create or replace table t1 (x int); connection slave; alter table t1 with system versioning; connection master; @@ -85,42 +93,26 @@ x 2 1 connection master; -create or replace table t1 (x int primary key) with system versioning engine = innodb; -connection slave; -alter table t1 without system versioning; -connection master; +create or replace table t1 (x int) with system versioning; +create or replace table t2 (x int) with system versioning; insert into t1 values (1); -update t1 set x= 2 where x = 1; -select * from t1 for system_time all; -x -1 -2 +insert into t2 values (2); +update t1, t2 set t1.x=11, t2.x=22; connection slave; select * from t1; x -2 -connection master; -delete from t1; +11 +select * from t2; +x +22 select * from t1 for system_time all; x +11 1 -2 -connection slave; -select * from t1; +select * from t2 for system_time all; x -connection master; -create or replace table t1 (a int) with system versioning engine = innodb; -insert into t1 values (1); -update t1 set a=2; -select * from t1 for system_time all; -a +22 2 -1 -connection slave; -select * from t1 for system_time all; -a -2 -1 connection master; -drop table t1; +drop table t1, t2; include/rpl_end.inc diff --git a/mysql-test/suite/versioning/r/truncate_innodb_rpl.result b/mysql-test/suite/versioning/r/truncate_innodb_rpl.result deleted file mode 100644 index 1aa29d7b95f..00000000000 --- a/mysql-test/suite/versioning/r/truncate_innodb_rpl.result +++ /dev/null @@ -1,7 +0,0 @@ -include/master-slave.inc -[connection master] -create table t (a int) with system versioning engine=innodb; -truncate t for system_time all; -ERROR HY000: `TRUNCATE FOR SYSTEM_TIME with row-based replication` is not allowed for versioned table -drop table t; -include/rpl_end.inc diff --git a/mysql-test/suite/versioning/t/rpl_mixed.combinations b/mysql-test/suite/versioning/t/rpl_mixed.combinations new file mode 100644 index 00000000000..9a1c771672c --- /dev/null +++ b/mysql-test/suite/versioning/t/rpl_mixed.combinations @@ -0,0 +1,5 @@ +[myisam] +default-storage-engine=myisam + +[innodb] +default-storage-engine=innodb diff --git a/mysql-test/suite/versioning/t/rpl_mixed.test b/mysql-test/suite/versioning/t/rpl_mixed.test new file mode 100644 index 00000000000..09612e664dc --- /dev/null +++ b/mysql-test/suite/versioning/t/rpl_mixed.test @@ -0,0 +1,7 @@ +-- source include/have_binlog_format_mixed.inc +-- source include/master-slave.inc +-- source include/have_innodb.inc + +-- source rpl_test.inc + +-- source include/rpl_end.inc diff --git a/mysql-test/suite/versioning/t/rpl_row.combinations b/mysql-test/suite/versioning/t/rpl_row.combinations new file mode 100644 index 00000000000..9a1c771672c --- /dev/null +++ b/mysql-test/suite/versioning/t/rpl_row.combinations @@ -0,0 +1,5 @@ +[myisam] +default-storage-engine=myisam + +[innodb] +default-storage-engine=innodb diff --git a/mysql-test/suite/versioning/t/rpl_stmt.combinations b/mysql-test/suite/versioning/t/rpl_stmt.combinations new file mode 100644 index 00000000000..75fb20d9f5e --- /dev/null +++ b/mysql-test/suite/versioning/t/rpl_stmt.combinations @@ -0,0 +1,5 @@ +[innodb] +default-storage-engine=innodb + +[myisam] +default-storage-engine=myisam diff --git a/mysql-test/suite/versioning/t/rpl_test.inc b/mysql-test/suite/versioning/t/rpl_test.inc index 74ed3bfd15b..5beee9f9dc6 100644 --- a/mysql-test/suite/versioning/t/rpl_test.inc +++ b/mysql-test/suite/versioning/t/rpl_test.inc @@ -8,7 +8,7 @@ let $slave_com_delete_before= query_get_value(SHOW GLOBAL STATUS LIKE 'com_delet let $slave_com_update_before= query_get_value(SHOW GLOBAL STATUS LIKE 'com_update', Value, 1); connection master; -CREATE TABLE t1 (x int) with system versioning ENGINE = innodb; +CREATE TABLE t1 (x int) with system versioning; insert into t1 values (1); SELECT * FROM t1; delete from t1; @@ -31,12 +31,17 @@ select * from t1 for system_time all; # check unversioned -> versioned replication connection master; -create or replace table t1 (x int primary key) engine = innodb; +create or replace table t1 (x int primary key); sync_slave_with_master; alter table t1 with system versioning; connection master; insert into t1 values (1); +sync_slave_with_master; +select * from t1; +select * from t1 for system_time all; + +connection master; update t1 set x= 2 where x = 1; sync_slave_with_master; select * from t1; @@ -50,7 +55,7 @@ select * from t1 for system_time all; # same thing (UPDATE, DELETE), but without PK connection master; -create or replace table t1 (x int) engine = innodb; +create or replace table t1 (x int); sync_slave_with_master; alter table t1 with system versioning; @@ -67,35 +72,19 @@ sync_slave_with_master; select * from t1; select * from t1 for system_time all; -# same thing, but reverse: versioned -> unversioned -connection master; -create or replace table t1 (x int primary key) with system versioning engine = innodb; -sync_slave_with_master; -alter table t1 without system versioning; - +# multi-update connection master; +create or replace table t1 (x int) with system versioning; +create or replace table t2 (x int) with system versioning; insert into t1 values (1); -update t1 set x= 2 where x = 1; -select * from t1 for system_time all; +insert into t2 values (2); +update t1, t2 set t1.x=11, t2.x=22; sync_slave_with_master; select * from t1; - -connection master; -delete from t1; +select * from t2; select * from t1 for system_time all; -sync_slave_with_master; -select * from t1; +select * from t2 for system_time all; -# at this point in this particular test master and slave have different curr_trx_id -# and the same rows have different sys_trx_start -# slave should ignore sys_trx_start while searching for a record to update in a InnoDB table -connection master; -create or replace table t1 (a int) with system versioning engine = innodb; -insert into t1 values (1); -update t1 set a=2; -select * from t1 for system_time all; -sync_slave_with_master; -select * from t1 for system_time all; connection master; -drop table t1; +drop table t1, t2; diff --git a/mysql-test/suite/versioning/t/truncate_innodb_rpl.test b/mysql-test/suite/versioning/t/truncate_innodb_rpl.test deleted file mode 100644 index 57fad82f3ba..00000000000 --- a/mysql-test/suite/versioning/t/truncate_innodb_rpl.test +++ /dev/null @@ -1,10 +0,0 @@ --- source include/have_binlog_format_row.inc --- source include/master-slave.inc --- source include/have_innodb.inc - -create table t (a int) with system versioning engine=innodb; ---error ER_VERS_NOT_ALLOWED -truncate t for system_time all; -drop table t; - --- source include/rpl_end.inc diff --git a/sql/handler.cc b/sql/handler.cc index 7e7f161f14f..3adf4969f73 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -5697,6 +5697,8 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat) bool handler::check_table_binlog_row_based(bool binlog_row) { + if (table->versioned_by_engine()) + return false; if (unlikely((table->in_use->variables.sql_log_bin_off))) return 0; /* Called by partitioning engine */ if (unlikely((!check_table_binlog_row_based_done))) diff --git a/sql/log_event.cc b/sql/log_event.cc index 4a48ebce077..1bedaf152f3 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -44,6 +44,7 @@ #include #include "compat56.h" #include "wsrep_mysqld.h" +#include "sql_insert.h" #endif /* MYSQL_CLIENT */ #include @@ -12509,6 +12510,22 @@ Rows_log_event::write_row(rpl_group_info *rgi, DBUG_RETURN(HA_ERR_GENERIC); // in case if error is not set yet } + // Handle INSERT. + // Set vers fields when replicating from not system-versioned table. + if (m_type == WRITE_ROWS_EVENT_V1 && table->versioned_by_sql()) + { + bitmap_set_bit(table->read_set, table->vers_start_field()->field_index); + // Check whether a row came from unversioned table and fix vers fields. + if (table->vers_start_field()->get_timestamp() == 0) + { + bitmap_set_bit(table->write_set, table->vers_start_field()->field_index); + bitmap_set_bit(table->write_set, table->vers_end_field()->field_index); + thd->set_current_time(); + table->vers_start_field()->set_time(); + table->vers_end_field()->set_max(); + } + } + /* Try to write record. If a corresponding record already exists in the table, we try to change it using ha_update_row() if possible. Otherwise we delete @@ -12799,7 +12816,7 @@ static bool record_compare(TABLE *table) /* Compare fields */ for (Field **ptr=table->field ; *ptr ; ptr++) { - if (table->versioned_by_engine() && *ptr == table->vers_start_field()) + if (table->versioned() && (*ptr)->vers_sys_field()) { continue; } @@ -12997,19 +13014,19 @@ int Rows_log_event::find_row(rpl_group_info *rgi) prepare_record(table, m_width, FALSE); error= unpack_current_row(rgi); - + m_vers_from_plain= false; if (table->versioned()) { Field *sys_trx_end= table->vers_end_field(); DBUG_ASSERT(table->read_set); bitmap_set_bit(table->read_set, sys_trx_end->field_index); - // master table is unversioned + // check whether master table is unversioned if (sys_trx_end->val_int() == 0) { - DBUG_ASSERT(table->write_set); - bitmap_set_bit(table->write_set, sys_trx_end->field_index); - sys_trx_end->set_max(); table->vers_start_field()->set_notnull(); + bitmap_set_bit(table->write_set, sys_trx_end->field_index); + table->vers_end_field()->set_max(); + m_vers_from_plain= true; } } @@ -13395,7 +13412,19 @@ int Delete_rows_log_event::do_exec_row(rpl_group_info *rgi) if (!error) { m_table->mark_columns_per_binlog_row_image(); - error= m_table->file->ha_delete_row(m_table->record[0]); + if (m_vers_from_plain && m_table->versioned_by_sql()) + { + Field *end= m_table->vers_end_field(); + bitmap_set_bit(m_table->write_set, end->field_index); + store_record(m_table, record[1]); + end->set_time(); + error= m_table->file->ha_update_row(m_table->record[1], + m_table->record[0]); + } + else + { + error= m_table->file->ha_delete_row(m_table->record[0]); + } m_table->default_column_bitmaps(); } if (invoke_triggers && !error && @@ -13652,9 +13681,22 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) memcpy(m_table->write_set->bitmap, m_cols_ai.bitmap, (m_table->write_set->n_bits + 7) / 8); m_table->mark_columns_per_binlog_row_image(); + if (m_vers_from_plain && m_table->versioned_by_sql()) + { + bitmap_set_bit(m_table->write_set, + m_table->vers_start_field()->field_index); + thd->set_current_time(); + m_table->vers_start_field()->set_time(); + } error= m_table->file->ha_update_row(m_table->record[1], m_table->record[0]); if (error == HA_ERR_RECORD_IS_THE_SAME) error= 0; + if (m_vers_from_plain && m_table->versioned_by_sql()) + { + store_record(m_table, record[2]); + error= vers_insert_history_row(m_table); + restore_record(m_table, record[2]); + } m_table->default_column_bitmaps(); if (invoke_triggers && !error && diff --git a/sql/log_event.h b/sql/log_event.h index e45151c8564..6a9ebae3a51 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -4588,6 +4588,8 @@ protected: uchar *m_extra_row_data; /* Pointer to extra row data if any */ /* If non null, first byte is length */ + bool m_vers_from_plain; + /* helper functions */ @@ -4737,6 +4739,7 @@ public: __attribute__((unused)), const uchar *after_record) { + DBUG_ASSERT(!table->versioned_by_engine()); return thd->binlog_write_row(table, is_transactional, after_record); } #endif @@ -4818,6 +4821,7 @@ public: const uchar *before_record, const uchar *after_record) { + DBUG_ASSERT(!table->versioned_by_engine()); return thd->binlog_update_row(table, is_transactional, before_record, after_record); } @@ -4907,6 +4911,7 @@ public: const uchar *after_record __attribute__((unused))) { + DBUG_ASSERT(!table->versioned_by_engine()); return thd->binlog_delete_row(table, is_transactional, before_record); } diff --git a/sql/sql_class.h b/sql/sql_class.h index d024a27c2cd..0c7179e5569 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -6052,6 +6052,24 @@ public: } }; +class ScopedStatementReplication +{ +public: + ScopedStatementReplication(THD *thd) : thd(thd) + { + if (thd) + saved_binlog_format= thd->set_current_stmt_binlog_format_stmt(); + } + ~ScopedStatementReplication() + { + if (thd) + thd->restore_stmt_binlog_format(saved_binlog_format); + } + +private: + enum_binlog_format saved_binlog_format; + THD *thd; +}; #endif /* MYSQL_SERVER */ #endif /* SQL_CLASS_INCLUDED */ diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 27e112c3285..62171ae2423 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -270,14 +270,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, TABLE *table= table_list->table; DBUG_ASSERT(table); - if (table->versioned_by_engine() && - table->file->check_table_binlog_row_based(1)) - { - my_error(ER_VERS_NOT_ALLOWED, MYF(0), - "TRUNCATE FOR SYSTEM_TIME with row-based replication"); - DBUG_RETURN(TRUE); - } - DBUG_ASSERT(!conds); if (vers_setup_select(thd, table_list, &conds, select_lex)) DBUG_RETURN(TRUE); @@ -724,6 +716,8 @@ cleanup: else errcode= query_error_code(thd, killed_status == NOT_KILLED); + ScopedStatementReplication scoped_stmt_rpl( + table->versioned_by_engine() ? thd : NULL); /* [binlog]: If 'handler::delete_all_rows()' was called and the storage engine does not inject the rows itself, we replicate diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index b0e1d06365f..7c916efa3d4 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1137,8 +1137,10 @@ values_loop_end: } else errcode= query_error_code(thd, thd->killed == NOT_KILLED); - - /* bug#22725: + + ScopedStatementReplication scoped_stmt_rpl( + table->versioned_by_engine() ? thd : NULL); + /* bug#22725: A query which per-row-loop can not be interrupted with KILLED, like INSERT, and that does not invoke stored diff --git a/sql/sql_update.cc b/sql/sql_update.cc index b5f4d593a10..80a036ae18b 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1036,6 +1036,9 @@ int mysql_update(THD *thd, else errcode= query_error_code(thd, killed_status == NOT_KILLED); + ScopedStatementReplication scoped_stmt_rpl( + table->versioned_by_engine() ? thd : NULL); + if (thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(), thd->query_length(), transactional_table, FALSE, FALSE, errcode)) @@ -2674,9 +2677,21 @@ bool multi_update::send_eof() thd->clear_error(); else errcode= query_error_code(thd, killed_status == NOT_KILLED); - if (thd->binlog_query(THD::ROW_QUERY_TYPE, - thd->query(), thd->query_length(), - transactional_tables, FALSE, FALSE, errcode)) + + bool force_stmt= false; + for (TABLE *table= all_tables->table; table; table= table->next) + { + if (table->versioned_by_engine()) + { + force_stmt= true; + break; + } + } + ScopedStatementReplication scoped_stmt_rpl(force_stmt ? thd : NULL); + + if (thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(), + thd->query_length(), transactional_tables, FALSE, + FALSE, errcode)) { local_error= 1; // Rollback update } -- cgit v1.2.1 From c2c8808a16e561bb43ef448fa1b47ae5e32a0f40 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Thu, 3 Aug 2017 10:11:49 +0300 Subject: SQL: compare TRX_ID fields against timestamps [closes #231] --- mysql-test/suite/versioning/common.inc | 3 + mysql-test/suite/versioning/r/cte.result | 2 +- mysql-test/suite/versioning/r/select.result | 117 ++--- mysql-test/suite/versioning/r/select_sp.result | 478 +++++++++++++++++++++ mysql-test/suite/versioning/r/truncate.result | 2 +- mysql-test/suite/versioning/r/view.result | 75 +++- mysql-test/suite/versioning/r/vtmd.result | 2 +- mysql-test/suite/versioning/t/cte.test | 2 +- mysql-test/suite/versioning/t/select.test | 218 +++++----- .../suite/versioning/t/select_sp.combinations | 5 + mysql-test/suite/versioning/t/select_sp.test | 211 +++++++++ mysql-test/suite/versioning/t/truncate.test | 2 +- mysql-test/suite/versioning/t/view.test | 3 + mysql-test/suite/versioning/t/vtmd.test | 2 +- sql/field.cc | 58 ++- sql/field.h | 30 +- sql/item.cc | 15 +- sql/item.h | 12 + sql/item_cmpfunc.cc | 52 +++ sql/item_cmpfunc.h | 1 + sql/item_vers.cc | 19 +- sql/share/errmsg-utf8.txt | 3 + sql/sql_base.cc | 1 + sql/sql_select.cc | 20 +- sql/table.cc | 57 +-- sql/unireg.cc | 3 +- 26 files changed, 1122 insertions(+), 271 deletions(-) create mode 100644 mysql-test/suite/versioning/r/select_sp.result create mode 100644 mysql-test/suite/versioning/t/select_sp.combinations create mode 100644 mysql-test/suite/versioning/t/select_sp.test diff --git a/mysql-test/suite/versioning/common.inc b/mysql-test/suite/versioning/common.inc index 288c188c43d..fcd767b140e 100644 --- a/mysql-test/suite/versioning/common.inc +++ b/mysql-test/suite/versioning/common.inc @@ -67,3 +67,6 @@ begin end if; end~~ delimiter ;~~ + +let $default_engine= `select default_engine()`; +let sys_datatype= `select sys_datatype()`; diff --git a/mysql-test/suite/versioning/r/cte.result b/mysql-test/suite/versioning/r/cte.result index 161255aeaa7..e3b6ba0876e 100644 --- a/mysql-test/suite/versioning/r/cte.result +++ b/mysql-test/suite/versioning/r/cte.result @@ -24,7 +24,7 @@ insert into emp (emp_id, name, salary, dept_id, mgr) values (1, "bill", 1000, 10, null), (20, "john", 500, 10, 1), (30, "jane", 750, 10,1 ); -select vtq_commit_ts(max(sys_trx_start)) into @ts_1 from emp; +select vtq_commit_ts(max(sys_trx_start + 0)) into @ts_1 from emp; update emp set mgr=30 where name ="john"; select vtq_commit_ts(sys_trx_start) into @ts_2 from emp where name="john"; /* All report to 'Bill' */ diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index 8a22b26fad1..8599cb92b52 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -60,21 +60,10 @@ select * from tmp; drop table tmp; end if; end~~ -create procedure test_01() -begin -declare engine varchar(255) default default_engine(); -declare sys_type varchar(255) default sys_datatype(); -declare fields varchar(255) default sys_commit_ts('sys_start'); -set @str= concat(' - create table t1( - x int unsigned, - y int unsigned, - sys_start ', sys_type, ' generated always as row start, - sys_end ', sys_type, ' generated always as row end, - period for system_time (sys_start, sys_end)) - with system versioning - engine ', engine); -prepare stmt from @str; execute stmt; drop prepare stmt; +create or replace table t1 ( +x int unsigned, +y int unsigned +) with system versioning; insert into t1 (x, y) values (0, 100), (1, 101), @@ -87,74 +76,11 @@ insert into t1 (x, y) values (8, 108), (9, 109); set @t0= now(6); -if engine = 'innodb' then -select sys_start from t1 limit 1 into @x0; -end if; delete from t1 where x = 3; delete from t1 where x > 7; insert into t1(x, y) values(3, 33); -select sys_start from t1 where x = 3 and y = 33 into @t1; -if engine = 'innodb' then -set @x1= @t1; -select vtq_commit_ts(@x1) into @t1; -end if; +select sys_trx_start from t1 where x = 3 and y = 33 into @t1; select x, y from t1; -select x as ASOF_x, y from t1 for system_time as of timestamp @t0; -select x as FROMTO_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; -select x as BETWAND_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; -select x as FROMTO_ext_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; -select x as BETWAND_ext_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; -select x as ALL_x, y from t1 for system_time all; -if engine = 'innodb' then -select x as ASOF2_x, y from t1 for system_time as of transaction @x0; -select x as FROMTO2_x, y from t1 for system_time from transaction 0 to transaction @x1; -select x as BETWAND2_x, y from t1 for system_time between transaction 0 and transaction @x1; -select x as FROMTO2_ext_x, y from t1 for system_time transaction from 0 to @x1; -select x as BETWAND2_ext_x, y from t1 for system_time transaction between 0 and @x1; -else -select x as ASOF2_x, y from t1 for system_time as of timestamp @t0; -select x as FROMTO2_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; -select x as BETWAND2_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; -select x as FROMTO2_ext_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; -select x as BETWAND2_ext_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; -end if; -drop table t1; -end~~ -create or replace procedure test_02() -begin -declare engine varchar(255) default default_engine(); -declare sys_type varchar(255) default sys_datatype(); -declare fields varchar(255) default sys_commit_ts('sys_start'); -set @str0= concat('( - x int, - y int, - sys_start ', sys_type, ' generated always as row start, - sys_end ', sys_type, ' generated always as row end, - period for system_time (sys_start, sys_end)) - with system versioning - engine ', engine); -set @str= concat('create or replace table t1', @str0); -prepare stmt from @str; execute stmt; drop prepare stmt; -set @str= concat('create or replace table t2', @str0); -prepare stmt from @str; execute stmt; drop prepare stmt; -insert into t1 values (1, 1), (1, 2), (1, 3), (4, 4), (5, 5); -insert into t2 values (1, 2), (2, 1), (3, 1); -set @t0= now(6); -select t1.x as IJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x; -select t1.x as LJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x; -select t1.x as RJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x; -delete from t1; -delete from t2; -select t1.x as IJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x -system_time as of timestamp @t0; -select t1.x as LJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x -system_time as of timestamp @t0; -select t1.x as RJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x -system_time as of timestamp @t0; -drop table t1; -drop table t2; -end~~ -call test_01(); x y 0 100 1 101 @@ -164,6 +90,7 @@ x y 6 106 7 107 3 33 +select x as ASOF_x, y from t1 for system_time as of timestamp @t0; ASOF_x y 0 100 1 101 @@ -175,6 +102,7 @@ ASOF_x y 7 107 8 108 9 109 +select x as FROMTO_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; FROMTO_x y 0 100 1 101 @@ -186,6 +114,7 @@ FROMTO_x y 7 107 8 108 9 109 +select x as BETWAND_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; BETWAND_x y 0 100 1 101 @@ -198,6 +127,7 @@ BETWAND_x y 8 108 9 109 3 33 +select x as FROMTO_ext_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; FROMTO_ext_x y 0 100 1 101 @@ -209,6 +139,7 @@ FROMTO_ext_x y 7 107 8 108 9 109 +select x as BETWAND_ext_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; BETWAND_ext_x y 0 100 1 101 @@ -221,6 +152,7 @@ BETWAND_ext_x y 8 108 9 109 3 33 +select x as ALL_x, y from t1 for system_time all; ALL_x y 0 100 1 101 @@ -290,39 +222,62 @@ BETWAND2_ext_x y 8 108 9 109 3 33 -call test_02(); +create or replace table t1 ( +x int unsigned, +y int unsigned +) with system versioning; +create or replace table t2 ( +x int unsigned, +y int unsigned +) with system versioning; +insert into t1 values (1, 1), (1, 2), (1, 3), (4, 4), (5, 5); +insert into t2 values (1, 2), (2, 1), (3, 1); +set @t0= now(6); +select t1.x as IJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x; IJ1_x1 y1 x2 y2 1 1 1 2 1 2 1 2 1 3 1 2 +select t1.x as LJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x; LJ1_x1 y1 x2 y2 1 1 1 2 1 2 1 2 1 3 1 2 4 4 NULL NULL 5 5 NULL NULL +select t1.x as RJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x; RJ1_x1 y1 x2 y2 1 1 1 2 1 2 1 2 1 3 1 2 NULL NULL 2 1 NULL NULL 3 1 +delete from t1; +delete from t2; +select t1.x as IJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x +system_time as of timestamp @t0; IJ2_x1 y1 x2 y2 1 1 1 2 1 2 1 2 1 3 1 2 +select t1.x as LJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x +system_time as of timestamp @t0; LJ2_x1 y1 x2 y2 1 1 1 2 1 2 1 2 1 3 1 2 4 4 NULL NULL 5 5 NULL NULL +select t1.x as RJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x +system_time as of timestamp @t0; RJ2_x1 y1 x2 y2 1 1 1 2 1 2 1 2 1 3 1 2 NULL NULL 2 1 NULL NULL 3 1 +drop table t1; +drop table t2; create table t1( A int ) with system versioning; @@ -469,8 +424,6 @@ No A B C D 25 1 1 1 1 26 1 1 1 1 27 1 1 1 1 -drop procedure test_01; -drop procedure test_02; drop procedure verify_vtq; drop procedure innodb_verify_vtq; drop function default_engine; diff --git a/mysql-test/suite/versioning/r/select_sp.result b/mysql-test/suite/versioning/r/select_sp.result new file mode 100644 index 00000000000..9ced07f03e1 --- /dev/null +++ b/mysql-test/suite/versioning/r/select_sp.result @@ -0,0 +1,478 @@ +set @@session.time_zone='+00:00'; +select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; +create procedure if not exists verify_vtq() +begin +set @i= 0; +select +@i:= @i + 1 as No, +transaction_id > 0 as A, +commit_id > transaction_id as B, +begin_timestamp > '1-1-1 0:0:0' as C, +commit_timestamp >= begin_timestamp as D +from information_schema.innodb_vtq +where transaction_id > @start_trx_id; +select ifnull(max(transaction_id), 0) +into @start_trx_id +from information_schema.innodb_vtq; +end~~ +create function if not exists default_engine() +returns varchar(255) +deterministic +begin +declare e varchar(255); +select lower(engine) from information_schema.engines where support='DEFAULT' into e; +return e; +end~~ +create function if not exists sys_datatype() +returns varchar(255) +deterministic +begin +if default_engine() = 'innodb' then +return 'bigint unsigned'; +elseif default_engine() = 'myisam' then +return 'timestamp(6)'; +end if; +return NULL; +end~~ +create function if not exists sys_commit_ts(sys_field varchar(255)) +returns varchar(255) +deterministic +begin +if default_engine() = 'innodb' then +return concat('vtq_commit_ts(', sys_field, ')'); +elseif default_engine() = 'myisam' then +return sys_field; +end if; +return NULL; +end~~ +create procedure if not exists innodb_verify_vtq(recs int) +begin +declare i int default 1; +if default_engine() = 'innodb' then +call verify_vtq; +elseif default_engine() = 'myisam' then +create temporary table tmp (No int, A bool, B bool, C bool, D bool); +while i <= recs do +insert into tmp values (i, 1, 1, 1, 1); +set i= i + 1; +end while; +select * from tmp; +drop table tmp; +end if; +end~~ +create procedure test_01() +begin +declare engine varchar(255) default default_engine(); +declare sys_type varchar(255) default sys_datatype(); +declare fields varchar(255) default sys_commit_ts('sys_start'); +set @str= concat(' + create table t1( + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); +prepare stmt from @str; execute stmt; drop prepare stmt; +insert into t1 (x, y) values +(0, 100), +(1, 101), +(2, 102), +(3, 103), +(4, 104), +(5, 105), +(6, 106), +(7, 107), +(8, 108), +(9, 109); +set @t0= now(6); +if engine = 'innodb' then +select sys_start from t1 limit 1 into @x0; +end if; +delete from t1 where x = 3; +delete from t1 where x > 7; +insert into t1(x, y) values(3, 33); +select sys_start from t1 where x = 3 and y = 33 into @t1; +if engine = 'innodb' then +set @x1= @t1; +select vtq_commit_ts(@x1) into @t1; +end if; +select x, y from t1; +select x as ASOF_x, y from t1 for system_time as of timestamp @t0; +select x as FROMTO_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; +select x as BETWAND_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; +select x as FROMTO_ext_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; +select x as BETWAND_ext_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; +select x as ALL_x, y from t1 for system_time all; +if engine = 'innodb' then +select x as ASOF2_x, y from t1 for system_time as of transaction @x0; +select x as FROMTO2_x, y from t1 for system_time from transaction @x0 to transaction @x1; +select x as BETWAND2_x, y from t1 for system_time between transaction @x0 and transaction @x1; +select x as FROMTO2_ext_x, y from t1 for system_time transaction from @x0 to @x1; +select x as BETWAND2_ext_x, y from t1 for system_time transaction between @x0 and @x1; +else +select x as ASOF2_x, y from t1 for system_time as of timestamp @t0; +select x as FROMTO2_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; +select x as BETWAND2_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; +select x as FROMTO2_ext_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; +select x as BETWAND2_ext_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; +end if; +drop table t1; +end~~ +create or replace procedure test_02() +begin +declare engine varchar(255) default default_engine(); +declare sys_type varchar(255) default sys_datatype(); +declare fields varchar(255) default sys_commit_ts('sys_start'); +set @str0= concat('( + x int, + y int, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); +set @str= concat('create or replace table t1', @str0); +prepare stmt from @str; execute stmt; drop prepare stmt; +set @str= concat('create or replace table t2', @str0); +prepare stmt from @str; execute stmt; drop prepare stmt; +insert into t1 values (1, 1), (1, 2), (1, 3), (4, 4), (5, 5); +insert into t2 values (1, 2), (2, 1), (3, 1); +set @t0= now(6); +select t1.x as IJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x; +select t1.x as LJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x; +select t1.x as RJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x; +delete from t1; +delete from t2; +select t1.x as IJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x +system_time as of timestamp @t0; +select t1.x as LJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x +system_time as of timestamp @t0; +select t1.x as RJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x +system_time as of timestamp @t0; +drop table t1; +drop table t2; +end~~ +call test_01(); +x y +0 100 +1 101 +2 102 +4 104 +5 105 +6 106 +7 107 +3 33 +ASOF_x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +FROMTO_x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +BETWAND_x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +3 33 +FROMTO_ext_x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +BETWAND_ext_x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +3 33 +ALL_x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +3 33 +ASOF2_x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +FROMTO2_x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +BETWAND2_x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +3 33 +FROMTO2_ext_x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +BETWAND2_ext_x y +0 100 +1 101 +2 102 +3 103 +4 104 +5 105 +6 106 +7 107 +8 108 +9 109 +3 33 +call test_02(); +IJ1_x1 y1 x2 y2 +1 1 1 2 +1 2 1 2 +1 3 1 2 +LJ1_x1 y1 x2 y2 +1 1 1 2 +1 2 1 2 +1 3 1 2 +4 4 NULL NULL +5 5 NULL NULL +RJ1_x1 y1 x2 y2 +1 1 1 2 +1 2 1 2 +1 3 1 2 +NULL NULL 2 1 +NULL NULL 3 1 +IJ2_x1 y1 x2 y2 +1 1 1 2 +1 2 1 2 +1 3 1 2 +LJ2_x1 y1 x2 y2 +1 1 1 2 +1 2 1 2 +1 3 1 2 +4 4 NULL NULL +5 5 NULL NULL +RJ2_x1 y1 x2 y2 +1 1 1 2 +1 2 1 2 +1 3 1 2 +NULL NULL 2 1 +NULL NULL 3 1 +create table t1( +A int +) with system versioning; +insert into t1 values(1); +select * from t1; +A +1 +create or replace table t1 (x int); +insert into t1 values (1); +select * from t1 for system_time all; +ERROR HY000: System Versioning required: t1 +create or replace table t1 (x int) with system versioning; +insert into t1 values (1); +select * from t1 for system_time all for update; +ERROR HY000: Versioned SELECT write-locking of history rows +create or replace table t1 (a int not null auto_increment primary key) with system versioning; +select * from (t1 as t2 left join t1 as t3 using (a)) natural left join t1; +a +create or replace table t1 (a int) with system versioning; +create or replace table t2 (a int) with system versioning; +insert into t1 values(1); +insert into t2 values(1); +create view v1 as select * from t2 inner join t1 using (a); +select * from v1; +a +1 +drop view v1; +create or replace table t1 (a int) with system versioning; +insert into t1 values (1); +create view vt1 as select a from t1; +select * from t1 natural join vt1; +a +1 +drop view vt1; +create or replace table t1(x int) with system versioning; +select * from (t1 as r left join t1 as u using (x)), t1; +x x +create or replace table t1 (a int) with system versioning; +insert into t1 values (1); +create trigger read_end after update on t1 +for each row set @end = old.sys_trx_end; +update t1 set a=2; +select @end; +@end +MAX_RESULT +create or replace table t1 (a int) with system versioning; +create or replace table t2 (b int) with system versioning; +insert into t1 values (1); +insert into t2 values (2); +select * from (select * from t1 cross join t2) as tmp; +a b +1 2 +select * from (select * from (select * from t1 cross join t2) as tmp1) as tmp2; +a b +1 2 +select * from (select * from t1 cross join t2 for system_time as of timestamp '0-0-0') as tmp; +a b +create or replace table t1(a1 int) with system versioning; +create or replace table t2(a2 int) with system versioning; +insert into t1 values(1),(2); +insert into t2 values(1),(2); +select * from t1 for system_time all natural left join t2 for system_time all; +a1 a2 +1 1 +2 1 +1 2 +2 2 +create or replace table t1(a1 int) with system versioning; +create or replace table t2(a2 int) with system versioning; +insert into t1 values(1),(2); +insert into t2 values(1),(2); +create or replace view v1 as select a1 from t1; +select * from v1 natural join t2; +a1 a2 +1 1 +2 1 +1 2 +2 2 +select * from v1 natural left join t2; +a1 a2 +1 1 +2 1 +1 2 +2 2 +select * from v1 natural right join t2; +a2 a1 +1 1 +2 1 +1 2 +2 2 +create or replace table t1 (a int) with system versioning; +insert into t1 values (1); +insert into t1 values (2); +insert into t1 values (3); +select * from t1 left outer join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; +a a +2 1 +3 1 +2 2 +3 2 +2 3 +3 3 +1 NULL +create or replace table t1 (x int) with system versioning; +create or replace table t2 (y int) with system versioning; +insert into t1 values (1), (2), (3); +delete from t1 where x = 3; +insert into t2 values (1); +select * from t1, t2 system_time all; +x y +1 1 +2 1 +3 1 +select * from t1 for system_time all, t2 for system_time all system_time all; +ERROR HY000: Unused clause: 'SYSTEM_TIME' +drop view v1; +drop table t1, t2; +call innodb_verify_vtq(27); +No A B C D +1 1 1 1 1 +2 1 1 1 1 +3 1 1 1 1 +4 1 1 1 1 +5 1 1 1 1 +6 1 1 1 1 +7 1 1 1 1 +8 1 1 1 1 +9 1 1 1 1 +10 1 1 1 1 +11 1 1 1 1 +12 1 1 1 1 +13 1 1 1 1 +14 1 1 1 1 +15 1 1 1 1 +16 1 1 1 1 +17 1 1 1 1 +18 1 1 1 1 +19 1 1 1 1 +20 1 1 1 1 +21 1 1 1 1 +22 1 1 1 1 +23 1 1 1 1 +24 1 1 1 1 +25 1 1 1 1 +26 1 1 1 1 +27 1 1 1 1 +drop procedure test_01; +drop procedure test_02; +drop procedure verify_vtq; +drop procedure innodb_verify_vtq; +drop function default_engine; +drop function sys_commit_ts; +drop function sys_datatype; diff --git a/mysql-test/suite/versioning/r/truncate.result b/mysql-test/suite/versioning/r/truncate.result index 9d8b92d6254..5651cffb179 100644 --- a/mysql-test/suite/versioning/r/truncate.result +++ b/mysql-test/suite/versioning/r/truncate.result @@ -151,7 +151,7 @@ select * from t for system_time before timestamp @ts1; a 1 insert into t values (33); -select max(sys_trx_start) from t into @tx; +select max(sys_trx_start + 0) from t into @tx; select * from t for system_time before transaction @tx; a 1 diff --git a/mysql-test/suite/versioning/r/view.result b/mysql-test/suite/versioning/r/view.result index 08c67cfa693..96ff29bd73b 100644 --- a/mysql-test/suite/versioning/r/view.result +++ b/mysql-test/suite/versioning/r/view.result @@ -1,3 +1,65 @@ +set @@session.time_zone='+00:00'; +select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; +create procedure if not exists verify_vtq() +begin +set @i= 0; +select +@i:= @i + 1 as No, +transaction_id > 0 as A, +commit_id > transaction_id as B, +begin_timestamp > '1-1-1 0:0:0' as C, +commit_timestamp >= begin_timestamp as D +from information_schema.innodb_vtq +where transaction_id > @start_trx_id; +select ifnull(max(transaction_id), 0) +into @start_trx_id +from information_schema.innodb_vtq; +end~~ +create function if not exists default_engine() +returns varchar(255) +deterministic +begin +declare e varchar(255); +select lower(engine) from information_schema.engines where support='DEFAULT' into e; +return e; +end~~ +create function if not exists sys_datatype() +returns varchar(255) +deterministic +begin +if default_engine() = 'innodb' then +return 'bigint unsigned'; +elseif default_engine() = 'myisam' then +return 'timestamp(6)'; +end if; +return NULL; +end~~ +create function if not exists sys_commit_ts(sys_field varchar(255)) +returns varchar(255) +deterministic +begin +if default_engine() = 'innodb' then +return concat('vtq_commit_ts(', sys_field, ')'); +elseif default_engine() = 'myisam' then +return sys_field; +end if; +return NULL; +end~~ +create procedure if not exists innodb_verify_vtq(recs int) +begin +declare i int default 1; +if default_engine() = 'innodb' then +call verify_vtq; +elseif default_engine() = 'myisam' then +create temporary table tmp (No int, A bool, B bool, C bool, D bool); +while i <= recs do +insert into tmp values (i, 1, 1, 1, 1); +set i= i + 1; +end while; +select * from tmp; +drop table tmp; +end if; +end~~ create table t1 (x int) with system versioning engine innodb; insert into t1 values (1); select now(6) into @t1; @@ -23,7 +85,7 @@ x create or replace view vt1 as select * from t1; show create view vt1; View Create View character_set_client collation_connection -vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`x` AS `x`,`t1`.`sys_trx_start` AS `sys_trx_start`,`t1`.`sys_trx_end` AS `sys_trx_end` from `t1` FOR SYSTEM_TIME ALL where `t1`.`sys_trx_end` = 18446744073709551615 latin1 latin1_swedish_ci +vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`x` AS `x`,`t1`.`sys_trx_start` AS `sys_trx_start`,`t1`.`sys_trx_end` AS `sys_trx_end` from `t1` FOR SYSTEM_TIME ALL where `t1`.`sys_trx_end` = TIMESTAMP'2038-01-19 03:14:07' latin1 latin1_swedish_ci drop view vt1; drop view vt2; create view vt1 as select * from t1 for system_time all; @@ -116,16 +178,21 @@ create or replace table t3 (x int); create or replace view vt1 as select * from t1, t2, t3; show create view vt1; View Create View character_set_client collation_connection -vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`a` AS `a`,`t2`.`b` AS `b`,`t3`.`x` AS `x`,`t1`.`sys_trx_start` AS `sys_trx_start`,`t1`.`sys_trx_end` AS `sys_trx_end` from ((`t1` FOR SYSTEM_TIME ALL join `t2` FOR SYSTEM_TIME ALL) join `t3`) where `t1`.`sys_trx_end` = 18446744073709551615 and `t2`.`sys_trx_end` = 18446744073709551615 latin1 latin1_swedish_ci +vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`a` AS `a`,`t2`.`b` AS `b`,`t3`.`x` AS `x`,`t1`.`sys_trx_start` AS `sys_trx_start`,`t1`.`sys_trx_end` AS `sys_trx_end` from ((`t1` FOR SYSTEM_TIME ALL join `t2` FOR SYSTEM_TIME ALL) join `t3`) where `t1`.`sys_trx_end` = TIMESTAMP'2038-01-19 03:14:07' and `t2`.`sys_trx_end` = TIMESTAMP'2038-01-19 03:14:07' latin1 latin1_swedish_ci create or replace view vt1 as select * from t3, t2, t1; show create view vt1; View Create View character_set_client collation_connection -vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t3`.`x` AS `x`,`t2`.`b` AS `b`,`t1`.`a` AS `a`,`t2`.`sys_trx_start` AS `sys_trx_start`,`t2`.`sys_trx_end` AS `sys_trx_end` from ((`t3` join `t2` FOR SYSTEM_TIME ALL) join `t1` FOR SYSTEM_TIME ALL) where `t2`.`sys_trx_end` = 18446744073709551615 and `t1`.`sys_trx_end` = 18446744073709551615 latin1 latin1_swedish_ci +vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t3`.`x` AS `x`,`t2`.`b` AS `b`,`t1`.`a` AS `a`,`t2`.`sys_trx_start` AS `sys_trx_start`,`t2`.`sys_trx_end` AS `sys_trx_end` from ((`t3` join `t2` FOR SYSTEM_TIME ALL) join `t1` FOR SYSTEM_TIME ALL) where `t2`.`sys_trx_end` = TIMESTAMP'2038-01-19 03:14:07' and `t1`.`sys_trx_end` = TIMESTAMP'2038-01-19 03:14:07' latin1 latin1_swedish_ci create or replace view vt1 as select a, t2.sys_trx_end as endo from t3, t1, t2; show create view vt1; View Create View character_set_client collation_connection -vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`a` AS `a`,`t2`.`sys_trx_end` AS `endo`,`t2`.`sys_trx_start` AS `sys_trx_start` from ((`t3` join `t1` FOR SYSTEM_TIME ALL) join `t2` FOR SYSTEM_TIME ALL) where `t1`.`sys_trx_end` = 18446744073709551615 and `t2`.`sys_trx_end` = 18446744073709551615 latin1 latin1_swedish_ci +vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`a` AS `a`,`t2`.`sys_trx_end` AS `endo`,`t2`.`sys_trx_start` AS `sys_trx_start` from ((`t3` join `t1` FOR SYSTEM_TIME ALL) join `t2` FOR SYSTEM_TIME ALL) where `t1`.`sys_trx_end` = TIMESTAMP'2038-01-19 03:14:07' and `t2`.`sys_trx_end` = TIMESTAMP'2038-01-19 03:14:07' latin1 latin1_swedish_ci create or replace view vvt1 as select * from t1, t2, vt1; ERROR HY000: Creating VIEW `vvt1` is prohibited: versioned VIEW `vt1` in query! drop view vt1, vt12; drop table t1, t2, t3; +drop procedure verify_vtq; +drop procedure innodb_verify_vtq; +drop function default_engine; +drop function sys_commit_ts; +drop function sys_datatype; diff --git a/mysql-test/suite/versioning/r/vtmd.result b/mysql-test/suite/versioning/r/vtmd.result index d2cb726ac6f..264795c668e 100644 --- a/mysql-test/suite/versioning/r/vtmd.result +++ b/mysql-test/suite/versioning/r/vtmd.result @@ -37,7 +37,7 @@ set @start= null; select start from tmp_vtmd for system_time all order by start limit 1 into @start; select @start > 0 and @start < @inf; select -start = @start as A_start, +start + 0 = @start as A_start, (@start:= end) and end = @inf as B_end, name, substr(archive_name, 1, instr(archive_name, '_')) as C_archive_name diff --git a/mysql-test/suite/versioning/t/cte.test b/mysql-test/suite/versioning/t/cte.test index 7a35352f7c8..50680f2f375 100644 --- a/mysql-test/suite/versioning/t/cte.test +++ b/mysql-test/suite/versioning/t/cte.test @@ -28,7 +28,7 @@ insert into emp (emp_id, name, salary, dept_id, mgr) values (20, "john", 500, 10, 1), (30, "jane", 750, 10,1 ); -select vtq_commit_ts(max(sys_trx_start)) into @ts_1 from emp; +select vtq_commit_ts(max(sys_trx_start + 0)) into @ts_1 from emp; update emp set mgr=30 where name ="john"; select vtq_commit_ts(sys_trx_start) into @ts_2 from emp where name="john"; diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index ef8dcb85664..5dc5f603d54 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -1,119 +1,106 @@ -- source suite/versioning/common.inc -delimiter ~~; -create procedure test_01() -begin - declare engine varchar(255) default default_engine(); - declare sys_type varchar(255) default sys_datatype(); - declare fields varchar(255) default sys_commit_ts('sys_start'); - - set @str= concat(' - create table t1( - x int unsigned, - y int unsigned, - sys_start ', sys_type, ' generated always as row start, - sys_end ', sys_type, ' generated always as row end, - period for system_time (sys_start, sys_end)) - with system versioning - engine ', engine); - prepare stmt from @str; execute stmt; drop prepare stmt; - insert into t1 (x, y) values - (0, 100), - (1, 101), - (2, 102), - (3, 103), - (4, 104), - (5, 105), - (6, 106), - (7, 107), - (8, 108), - (9, 109); - set @t0= now(6); - if engine = 'innodb' then - select sys_start from t1 limit 1 into @x0; - end if; - - delete from t1 where x = 3; - delete from t1 where x > 7; - - insert into t1(x, y) values(3, 33); - select sys_start from t1 where x = 3 and y = 33 into @t1; - if engine = 'innodb' then - set @x1= @t1; - select vtq_commit_ts(@x1) into @t1; - end if; - - select x, y from t1; - select x as ASOF_x, y from t1 for system_time as of timestamp @t0; - select x as FROMTO_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; - select x as BETWAND_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; - select x as FROMTO_ext_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; - select x as BETWAND_ext_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; - select x as ALL_x, y from t1 for system_time all; - - if engine = 'innodb' then - select x as ASOF2_x, y from t1 for system_time as of transaction @x0; - select x as FROMTO2_x, y from t1 for system_time from transaction 0 to transaction @x1; - select x as BETWAND2_x, y from t1 for system_time between transaction 0 and transaction @x1; - select x as FROMTO2_ext_x, y from t1 for system_time transaction from 0 to @x1; - select x as BETWAND2_ext_x, y from t1 for system_time transaction between 0 and @x1; - else - select x as ASOF2_x, y from t1 for system_time as of timestamp @t0; - select x as FROMTO2_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; - select x as BETWAND2_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; - select x as FROMTO2_ext_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; - select x as BETWAND2_ext_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; - end if; - - drop table t1; -end~~ - -create or replace procedure test_02() -begin - declare engine varchar(255) default default_engine(); - declare sys_type varchar(255) default sys_datatype(); - declare fields varchar(255) default sys_commit_ts('sys_start'); - - set @str0= concat('( - x int, - y int, - sys_start ', sys_type, ' generated always as row start, - sys_end ', sys_type, ' generated always as row end, - period for system_time (sys_start, sys_end)) - with system versioning - engine ', engine); - set @str= concat('create or replace table t1', @str0); - prepare stmt from @str; execute stmt; drop prepare stmt; - set @str= concat('create or replace table t2', @str0); - prepare stmt from @str; execute stmt; drop prepare stmt; - - insert into t1 values (1, 1), (1, 2), (1, 3), (4, 4), (5, 5); - insert into t2 values (1, 2), (2, 1), (3, 1); - set @t0= now(6); - - select t1.x as IJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x; - select t1.x as LJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x; - select t1.x as RJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x; - - delete from t1; - delete from t2; - - select t1.x as IJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x - system_time as of timestamp @t0; - select t1.x as LJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x - system_time as of timestamp @t0; - select t1.x as RJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x - system_time as of timestamp @t0; - - drop table t1; - drop table t2; -end~~ -delimiter ;~~ - -call test_01(); -call test_02(); - -# wildcard expansion on hidden fields. +# test_01 + +create or replace table t1 ( + x int unsigned, + y int unsigned +) with system versioning; + +insert into t1 (x, y) values + (0, 100), + (1, 101), + (2, 102), + (3, 103), + (4, 104), + (5, 105), + (6, 106), + (7, 107), + (8, 108), + (9, 109); + +set @t0= now(6); +if ($default_engine == 'innodb') +{ +--disable_query_log + select sys_trx_start from t1 limit 1 into @x0; +--enable_query_log +} + +delete from t1 where x = 3; +delete from t1 where x > 7; + +insert into t1(x, y) values(3, 33); +select sys_trx_start from t1 where x = 3 and y = 33 into @t1; +if ($default_engine == 'innodb') +{ +--disable_query_log + set @x1= @t1; + select vtq_commit_ts(@x1) into @t1; +--enable_query_log +} + +select x, y from t1; +select x as ASOF_x, y from t1 for system_time as of timestamp @t0; +select x as FROMTO_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; +select x as BETWAND_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; +select x as FROMTO_ext_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; +select x as BETWAND_ext_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; +select x as ALL_x, y from t1 for system_time all; + +--disable_query_log +if ($default_engine == 'innodb') +{ + select x as ASOF2_x, y from t1 for system_time as of transaction @x0; + select x as FROMTO2_x, y from t1 for system_time from transaction @x0 to transaction @x1; + select x as BETWAND2_x, y from t1 for system_time between transaction @x0 and transaction @x1; + select x as FROMTO2_ext_x, y from t1 for system_time transaction from @x0 to @x1; + select x as BETWAND2_ext_x, y from t1 for system_time transaction between @x0 and @x1; +} +if ($default_engine != 'innodb') +{ + select x as ASOF2_x, y from t1 for system_time as of timestamp @t0; + select x as FROMTO2_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; + select x as BETWAND2_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; + select x as FROMTO2_ext_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; + select x as BETWAND2_ext_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; +} +--enable_query_log + +# test_02 + +create or replace table t1 ( + x int unsigned, + y int unsigned +) with system versioning; +create or replace table t2 ( + x int unsigned, + y int unsigned +) with system versioning; + +insert into t1 values (1, 1), (1, 2), (1, 3), (4, 4), (5, 5); +insert into t2 values (1, 2), (2, 1), (3, 1); +set @t0= now(6); + +select t1.x as IJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x; +select t1.x as LJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x; +select t1.x as RJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x; + +delete from t1; +delete from t2; + +select t1.x as IJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x +system_time as of timestamp @t0; +select t1.x as LJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x +system_time as of timestamp @t0; +select t1.x as RJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x +system_time as of timestamp @t0; + +drop table t1; +drop table t2; + +# Wildcard expansion on hidden fields + create table t1( A int ) with system versioning; @@ -205,7 +192,4 @@ drop table t1, t2; call innodb_verify_vtq(27); -drop procedure test_01; -drop procedure test_02; - -- source suite/versioning/common_finish.inc diff --git a/mysql-test/suite/versioning/t/select_sp.combinations b/mysql-test/suite/versioning/t/select_sp.combinations new file mode 100644 index 00000000000..75fb20d9f5e --- /dev/null +++ b/mysql-test/suite/versioning/t/select_sp.combinations @@ -0,0 +1,5 @@ +[innodb] +default-storage-engine=innodb + +[myisam] +default-storage-engine=myisam diff --git a/mysql-test/suite/versioning/t/select_sp.test b/mysql-test/suite/versioning/t/select_sp.test new file mode 100644 index 00000000000..23921e9580d --- /dev/null +++ b/mysql-test/suite/versioning/t/select_sp.test @@ -0,0 +1,211 @@ +-- source suite/versioning/common.inc + +delimiter ~~; +create procedure test_01() +begin + declare engine varchar(255) default default_engine(); + declare sys_type varchar(255) default sys_datatype(); + declare fields varchar(255) default sys_commit_ts('sys_start'); + + set @str= concat(' + create table t1( + x int unsigned, + y int unsigned, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); + prepare stmt from @str; execute stmt; drop prepare stmt; + insert into t1 (x, y) values + (0, 100), + (1, 101), + (2, 102), + (3, 103), + (4, 104), + (5, 105), + (6, 106), + (7, 107), + (8, 108), + (9, 109); + set @t0= now(6); + if engine = 'innodb' then + select sys_start from t1 limit 1 into @x0; + end if; + + delete from t1 where x = 3; + delete from t1 where x > 7; + + insert into t1(x, y) values(3, 33); + select sys_start from t1 where x = 3 and y = 33 into @t1; + if engine = 'innodb' then + set @x1= @t1; + select vtq_commit_ts(@x1) into @t1; + end if; + + select x, y from t1; + select x as ASOF_x, y from t1 for system_time as of timestamp @t0; + select x as FROMTO_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; + select x as BETWAND_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; + select x as FROMTO_ext_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; + select x as BETWAND_ext_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; + select x as ALL_x, y from t1 for system_time all; + + if engine = 'innodb' then + select x as ASOF2_x, y from t1 for system_time as of transaction @x0; + select x as FROMTO2_x, y from t1 for system_time from transaction @x0 to transaction @x1; + select x as BETWAND2_x, y from t1 for system_time between transaction @x0 and transaction @x1; + select x as FROMTO2_ext_x, y from t1 for system_time transaction from @x0 to @x1; + select x as BETWAND2_ext_x, y from t1 for system_time transaction between @x0 and @x1; + else + select x as ASOF2_x, y from t1 for system_time as of timestamp @t0; + select x as FROMTO2_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; + select x as BETWAND2_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; + select x as FROMTO2_ext_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; + select x as BETWAND2_ext_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; + end if; + + drop table t1; +end~~ + +create or replace procedure test_02() +begin + declare engine varchar(255) default default_engine(); + declare sys_type varchar(255) default sys_datatype(); + declare fields varchar(255) default sys_commit_ts('sys_start'); + + set @str0= concat('( + x int, + y int, + sys_start ', sys_type, ' generated always as row start, + sys_end ', sys_type, ' generated always as row end, + period for system_time (sys_start, sys_end)) + with system versioning + engine ', engine); + set @str= concat('create or replace table t1', @str0); + prepare stmt from @str; execute stmt; drop prepare stmt; + set @str= concat('create or replace table t2', @str0); + prepare stmt from @str; execute stmt; drop prepare stmt; + + insert into t1 values (1, 1), (1, 2), (1, 3), (4, 4), (5, 5); + insert into t2 values (1, 2), (2, 1), (3, 1); + set @t0= now(6); + + select t1.x as IJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x; + select t1.x as LJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x; + select t1.x as RJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x; + + delete from t1; + delete from t2; + + select t1.x as IJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x + system_time as of timestamp @t0; + select t1.x as LJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x + system_time as of timestamp @t0; + select t1.x as RJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x + system_time as of timestamp @t0; + + drop table t1; + drop table t2; +end~~ +delimiter ;~~ + +call test_01(); +call test_02(); + +# wildcard expansion on hidden fields. +create table t1( + A int +) with system versioning; +insert into t1 values(1); +select * from t1; + +create or replace table t1 (x int); +insert into t1 values (1); +--error ER_VERSIONING_REQUIRED +select * from t1 for system_time all; + +create or replace table t1 (x int) with system versioning; +insert into t1 values (1); +--error ER_VERS_HISTORY_LOCK +select * from t1 for system_time all for update; + +create or replace table t1 (a int not null auto_increment primary key) with system versioning; +select * from (t1 as t2 left join t1 as t3 using (a)) natural left join t1; + +create or replace table t1 (a int) with system versioning; +create or replace table t2 (a int) with system versioning; +insert into t1 values(1); +insert into t2 values(1); +create view v1 as select * from t2 inner join t1 using (a); +select * from v1; +drop view v1; + +create or replace table t1 (a int) with system versioning; +insert into t1 values (1); +create view vt1 as select a from t1; +select * from t1 natural join vt1; +drop view vt1; + +create or replace table t1(x int) with system versioning; +select * from (t1 as r left join t1 as u using (x)), t1; + +# @end should be max +create or replace table t1 (a int) with system versioning; +insert into t1 values (1); +create trigger read_end after update on t1 + for each row set @end = old.sys_trx_end; +update t1 set a=2; +--replace_result 18446744073709551615 MAX_RESULT "2038-01-19 03:14:07.000000" MAX_RESULT +select @end; + +create or replace table t1 (a int) with system versioning; +create or replace table t2 (b int) with system versioning; +insert into t1 values (1); +insert into t2 values (2); +select * from (select * from t1 cross join t2) as tmp; +select * from (select * from (select * from t1 cross join t2) as tmp1) as tmp2; +select * from (select * from t1 cross join t2 for system_time as of timestamp '0-0-0') as tmp; + +create or replace table t1(a1 int) with system versioning; +create or replace table t2(a2 int) with system versioning; +insert into t1 values(1),(2); +insert into t2 values(1),(2); +select * from t1 for system_time all natural left join t2 for system_time all; + +# natural join of a view and table +create or replace table t1(a1 int) with system versioning; +create or replace table t2(a2 int) with system versioning; +insert into t1 values(1),(2); +insert into t2 values(1),(2); +create or replace view v1 as select a1 from t1; + +select * from v1 natural join t2; +select * from v1 natural left join t2; +select * from v1 natural right join t2; + +create or replace table t1 (a int) with system versioning; +insert into t1 values (1); +insert into t1 values (2); +insert into t1 values (3); +select * from t1 left outer join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; + +create or replace table t1 (x int) with system versioning; +create or replace table t2 (y int) with system versioning; +insert into t1 values (1), (2), (3); +delete from t1 where x = 3; +insert into t2 values (1); +select * from t1, t2 system_time all; + +--error ER_VERS_UNUSED_CLAUSE +select * from t1 for system_time all, t2 for system_time all system_time all; + +drop view v1; +drop table t1, t2; + +call innodb_verify_vtq(27); + +drop procedure test_01; +drop procedure test_02; + +-- source suite/versioning/common_finish.inc diff --git a/mysql-test/suite/versioning/t/truncate.test b/mysql-test/suite/versioning/t/truncate.test index b51e2ad9311..97362c7423b 100644 --- a/mysql-test/suite/versioning/t/truncate.test +++ b/mysql-test/suite/versioning/t/truncate.test @@ -110,7 +110,7 @@ update t set a=22 where a=2; select * from t for system_time all; select * from t for system_time before timestamp @ts1; insert into t values (33); -select max(sys_trx_start) from t into @tx; +select max(sys_trx_start + 0) from t into @tx; select * from t for system_time before transaction @tx; truncate t for system_time before timestamp @ts1; select * from t for system_time all; diff --git a/mysql-test/suite/versioning/t/view.test b/mysql-test/suite/versioning/t/view.test index 64be35f70c0..5b7b267ff38 100644 --- a/mysql-test/suite/versioning/t/view.test +++ b/mysql-test/suite/versioning/t/view.test @@ -1,4 +1,5 @@ -- source include/have_innodb.inc +-- source suite/versioning/common.inc create table t1 (x int) with system versioning engine innodb; insert into t1 values (1); @@ -89,3 +90,5 @@ create or replace view vvt1 as select * from t1, t2, vt1; drop view vt1, vt12; drop table t1, t2, t3; + +-- source suite/versioning/common_finish.inc diff --git a/mysql-test/suite/versioning/t/vtmd.test b/mysql-test/suite/versioning/t/vtmd.test index b81674f675e..5d6b09a56e0 100644 --- a/mysql-test/suite/versioning/t/vtmd.test +++ b/mysql-test/suite/versioning/t/vtmd.test @@ -46,7 +46,7 @@ begin select start from tmp_vtmd for system_time all order by start limit 1 into @start; select @start > 0 and @start < @inf; select - start = @start as A_start, + start + 0 = @start as A_start, (@start:= end) and end = @inf as B_end, name, substr(archive_name, 1, instr(archive_name, '_')) as C_archive_name diff --git a/sql/field.cc b/sql/field.cc index ac0e59773be..cd83e61ba43 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1999,6 +1999,40 @@ bool Field_num::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate) } +bool Field_vers_system::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate, ulonglong trx_id) +{ + ASSERT_COLUMN_MARKED_FOR_READ; + DBUG_ASSERT(ltime); + if (!table || !table->s) + return true; + DBUG_ASSERT(table->versioned_by_engine() || + (table->versioned() && table->s->table_category == TABLE_CATEGORY_TEMPORARY)); + if (!trx_id) + return true; + if (trx_id == ULONGLONG_MAX) + { + get_thd()->variables.time_zone->gmt_sec_to_TIME(ltime, TIMESTAMP_MAX_VALUE); + return false; + } + if (cached == trx_id) + { + *ltime= cache; + return false; + } + handlerton *hton= table->file->partition_ht(); + DBUG_ASSERT(hton); + DBUG_ASSERT(hton->vers_query_trx_id); + bool found= hton->vers_query_trx_id(get_thd(), &cache, trx_id, VTQ_COMMIT_TS); + if (found) + { + *ltime= cache; + cached= trx_id; + return false; + } + return true; +} + + Field_str::Field_str(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, const char *field_name_arg, CHARSET_INFO *charset_arg) @@ -10373,7 +10407,8 @@ Field *make_field(TABLE_SHARE *share, Field::geometry_type geom_type, uint srid, Field::utype unireg_check, TYPELIB *interval, - const char *field_name) + const char *field_name, + uint32 flags) { uchar *UNINIT_VAR(bit_ptr); uchar UNINIT_VAR(bit_offset); @@ -10527,11 +10562,22 @@ Field *make_field(TABLE_SHARE *share, f_is_zerofill(pack_flag) != 0, f_is_dec(pack_flag) == 0); case MYSQL_TYPE_LONGLONG: - return new (mem_root) - Field_longlong(ptr,field_length,null_pos,null_bit, - unireg_check, field_name, - f_is_zerofill(pack_flag) != 0, - f_is_dec(pack_flag) == 0); + if (flags & (VERS_SYS_START_FLAG|VERS_SYS_END_FLAG)) + { + return new (mem_root) + Field_vers_system(ptr, field_length, null_pos, null_bit, + unireg_check, field_name, + f_is_zerofill(pack_flag) != 0, + f_is_dec(pack_flag) == 0); + } + else + { + return new (mem_root) + Field_longlong(ptr,field_length,null_pos,null_bit, + unireg_check, field_name, + f_is_zerofill(pack_flag) != 0, + f_is_dec(pack_flag) == 0); + } case MYSQL_TYPE_TIMESTAMP: { uint dec= field_length > MAX_DATETIME_WIDTH ? diff --git a/sql/field.h b/sql/field.h index 28d47b337a7..efd3fe18e6f 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1402,7 +1402,7 @@ public: FIELD_FLAGS_COLUMN_FORMAT; } - bool vers_sys_field() + bool vers_sys_field() const { return flags & (VERS_SYS_START_FLAG | VERS_SYS_END_FLAG); } @@ -2130,6 +2130,29 @@ public: }; +class Field_vers_system :public Field_longlong { + MYSQL_TIME cache; + ulonglong cached; +public: + Field_vers_system(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + bool zero_arg, bool unsigned_arg) + :Field_longlong(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, zero_arg,unsigned_arg), + cached(0) + {} + enum_field_types real_type() const { return MYSQL_TYPE_LONGLONG; } + enum_field_types type() const { return MYSQL_TYPE_DATETIME;} + uint size_of() const { return sizeof(*this); } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate, ulonglong trx_id); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return get_date(ltime, fuzzydate, (ulonglong) val_int()); + } +}; + + class Field_float :public Field_real { public: Field_float(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, @@ -3778,7 +3801,8 @@ Field *make_field(TABLE_SHARE *share, MEM_ROOT *mem_root, CHARSET_INFO *cs, Field::geometry_type geom_type, uint srid, Field::utype unireg_check, - TYPELIB *interval, const char *field_name); + TYPELIB *interval, const char *field_name, + uint32 flags); /* Create field class for CREATE TABLE @@ -3965,7 +3989,7 @@ public: (uint32)length, null_pos, null_bit, pack_flag, sql_type, charset, geom_type, srid, unireg_check, interval, - field_name_arg); + field_name_arg, flags); } Field *make_field(TABLE_SHARE *share, MEM_ROOT *mem_root, const char *field_name_arg) diff --git a/sql/item.cc b/sql/item.cc index 0df22234f88..117662d9c79 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -6325,9 +6325,18 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table, break; #ifdef HAVE_LONG_LONG case MYSQL_TYPE_LONGLONG: - field= new (mem_root) - Field_longlong((uchar*) 0, max_length, null_ptr, 0, Field::NONE, - name, 0, unsigned_flag); + if (field_flags() & (VERS_SYS_START_FLAG|VERS_SYS_END_FLAG)) + { + field= new (mem_root) + Field_vers_system((uchar*) 0, max_length, null_ptr, 0, Field::NONE, + name, 0, unsigned_flag); + } + else + { + field= new (mem_root) + Field_longlong((uchar*) 0, max_length, null_ptr, 0, Field::NONE, + name, 0, unsigned_flag); + } break; #endif case MYSQL_TYPE_FLOAT: diff --git a/sql/item.h b/sql/item.h index ab2c9dd65a9..130ad688593 100644 --- a/sql/item.h +++ b/sql/item.h @@ -747,6 +747,10 @@ public: virtual bool send(Protocol *protocol, String *str); virtual bool eq(const Item *, bool binary_cmp) const; virtual enum_field_types field_type() const= 0; + virtual uint field_flags() const + { + return 0; + } virtual const Type_handler *type_handler() const { return Type_handler::get_handler_by_field_type(field_type()); @@ -2669,6 +2673,10 @@ public: { return field->type(); } + uint32 field_flags() const + { + return field->flags; + } const Type_handler *real_type_handler() const; enum_monotonicity_info get_monotonicity_info() const { @@ -5898,6 +5906,10 @@ public: Item* get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; } uint flags; + uint32 field_flags() const + { + return flags; + } }; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index f5ba6f206c2..147bb270e37 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -5218,6 +5218,58 @@ bool fix_escape_item(THD *thd, Item *escape_item, String *tmp_str, return FALSE; } +bool Item_bool_func2::fix_fields(THD* thd, Item** ref) +{ + if (Item_bool_func::fix_fields(thd, ref)) + return true; + + // System Versioning: convert TRX_ID to DATETIME + Item *trx_id= NULL; + int arg_idx= -1; + Field_vers_system *sys_field= NULL; + DBUG_ASSERT(arg_count == 2); + // find trx_id and sys_field + for (int i= 0; i < 2; ++i) + { + Item *arg= args[i]; + if (arg->result_type() != INT_RESULT) + continue; + DBUG_ASSERT(arg); + if (arg->type() == Item::FIELD_ITEM) + { + Field *f= static_cast(arg)->field; + DBUG_ASSERT(f); + if (f->vers_sys_field() && f->real_type() == MYSQL_TYPE_LONGLONG) + { + if (sys_field) + return false; + sys_field= static_cast(f); + continue; + } + } + if (trx_id) + return false; + trx_id= arg; + arg_idx= i; + } + if (!trx_id || !sys_field) + return false; + MYSQL_TIME ltime; + ulonglong trx_id_val= (ulonglong) trx_id->val_int(); + if (sys_field->get_date(<ime, false, trx_id_val)) + { + my_error(ER_VERS_NO_TRX_ID, MYF(0), trx_id_val); + return true; + } + Query_arena_stmt on_stmt_arena(thd); + Item *datetime= new (thd->mem_root) Item_datetime_literal(thd, <ime, 6); + if (!datetime) + return true; + DBUG_ASSERT(arg_idx > -1); + args[arg_idx]= datetime; + return false; +} + bool Item_func_like::fix_fields(THD *thd, Item **ref) { diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index a94105b352d..6eb1b34e568 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -410,6 +410,7 @@ public: ftree= Item_func::get_mm_tree(param, cond_ptr); DBUG_RETURN(ftree); } + bool fix_fields(THD *thd, Item **ref); }; diff --git a/sql/item_vers.cc b/sql/item_vers.cc index 3562cc7fbc9..47e62d9ebf0 100644 --- a/sql/item_vers.cc +++ b/sql/item_vers.cc @@ -54,6 +54,14 @@ Item_func_vtq_ts::get_date(MYSQL_TIME *res, ulonglong fuzzy_date) { THD *thd= current_thd; // can it differ from constructor's? DBUG_ASSERT(thd); + DBUG_ASSERT(args[0]); + if (args[0]->result_type() != INT_RESULT) + { + my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0), + args[0]->type_handler()->name().ptr(), + func_name()); + return true; + } ulonglong trx_id= args[0]->val_uint(); if (trx_id == ULONGLONG_MAX) { @@ -62,13 +70,14 @@ Item_func_vtq_ts::get_date(MYSQL_TIME *res, ulonglong fuzzy_date) return false; } - if (!hton) - return true; - - DBUG_ASSERT(hton->vers_query_trx_id); + DBUG_ASSERT(hton && hton->vers_query_trx_id); null_value= !hton->vers_query_trx_id(thd, res, trx_id, vtq_field); + if (null_value) + { + my_error(ER_VERS_NO_TRX_ID, MYF(0), trx_id); + } - return false; + return null_value; } diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 1a386c4f16c..bae32e4d247 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7589,6 +7589,9 @@ ER_VERS_WRONG_PARTS ER_VERS_HISTORY_LOCK eng "Versioned SELECT write-locking of history rows" +ER_VERS_NO_TRX_ID + eng "TRX_ID %lu not found in VTQ" + ER_WRONG_TABLESPACE_NAME 42000 eng "Incorrect tablespace name `%-.192s`" diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 238fa3a0fa4..0a7ad7aef55 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -5704,6 +5704,7 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list, if (field_to_set) { TABLE *table= field_to_set->table; + DBUG_ASSERT(table); if (thd->mark_used_columns == MARK_COLUMNS_READ) bitmap_set_bit(table->read_set, field_to_set->field_index); else diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a1fc9f16b21..8575755c267 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -877,24 +877,6 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, DBUG_RETURN(-1); } } - else if (thd->variables.vers_innodb_algorithm_simple && - vers_conditions.unit == UNIT_TIMESTAMP && - vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED) - { - DBUG_ASSERT(table->table->s && table->table->s->db_plugin); - handlerton *hton= plugin_hton(table->table->s->db_plugin); - DBUG_ASSERT(hton); - row_start= newx Item_func_vtq_ts( - thd, - hton, - row_start, - VTQ_COMMIT_TS); - row_end= newx Item_func_vtq_ts( - thd, - hton, - row_end, - VTQ_COMMIT_TS); - } Item *cond1= 0, *cond2= 0, *curr= 0; // Temporary tables of can be created from INNODB tables and thus will @@ -907,7 +889,7 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, switch (vers_conditions.type) { case FOR_SYSTEM_TIME_UNSPECIFIED: - if (table->table->versioned_by_sql() && !tmp_from_ib) + if (!tmp_from_ib) { MYSQL_TIME max_time; thd->variables.time_zone->gmt_sec_to_TIME(&max_time, TIMESTAMP_MAX_VALUE); diff --git a/sql/table.cc b/sql/table.cc index b2a511d89f4..2dcec49d46d 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1769,6 +1769,27 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, strpos, vcol_screen_pos); } + /* Set system versioning information. */ + if (system_period == NULL) + { + versioned= false; + row_start_field = 0; + row_end_field = 0; + } + else + { + DBUG_PRINT("info", ("Setting system versioning informations")); + uint16 row_start= uint2korr(system_period); + uint16 row_end= uint2korr(system_period + sizeof(uint16)); + if (row_start >= share->fields || row_end >= share->fields) + goto err; + DBUG_PRINT("info", ("Columns with system versioning: [%d, %d]", row_start, row_end)); + versioned= true; + vers_init(); + row_start_field= row_start; + row_end_field= row_end; + } // if (system_period == NULL) + for (i=0 ; i < share->fields; i++, strpos+=field_pack_length, field_ptr++) { uint pack_flag, interval_nr, unireg_type, recpos, field_length; @@ -1781,6 +1802,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, Virtual_column_info *vcol_info= 0; uint gis_length, gis_decimals, srid= 0; Field::utype unireg_check; + uint32 flags= 0; if (new_frm_ver >= 3) { @@ -1988,6 +2010,14 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, swap_variables(uint, null_bit_pos, mysql57_vcol_null_bit_pos); } + if (versioned) + { + if (i == row_start_field) + flags|= VERS_SYS_START_FLAG; + else if (i == row_end_field) + flags|= VERS_SYS_END_FLAG; + } + /* Convert pre-10.2.2 timestamps to use Field::default_value */ unireg_check= (Field::utype) MTYP_TYPENR(unireg_type); *field_ptr= reg_field= @@ -1995,7 +2025,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, null_pos, null_bit_pos, pack_flag, field_type, charset, geom_type, srid, unireg_check, (interval_nr ? share->intervals+interval_nr-1 : NULL), - share->fieldnames.type_names[i]); + share->fieldnames.type_names[i], flags); if (!reg_field) // Not supported field type goto err; @@ -2010,6 +2040,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, reg_field->field_index= i; reg_field->comment=comment; reg_field->vcol_info= vcol_info; + reg_field->flags|= flags; if (extra2_field_flags) { uchar flags= *extra2_field_flags++; @@ -2555,30 +2586,6 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, #endif share->db_plugin= se_plugin; - - /* Set system versioning information. */ - if (system_period == NULL) - { - versioned= false; - row_start_field = 0; - row_end_field = 0; - } - else - { - DBUG_PRINT("info", ("Setting system versioning informations")); - uint16 row_start= uint2korr(system_period); - uint16 row_end= uint2korr(system_period + sizeof(uint16)); - if (row_start >= share->fields || row_end >= share->fields) - goto err; - DBUG_PRINT("info", ("Columns with system versioning: [%d, %d]", row_start, row_end)); - versioned= true; - vers_init(); - row_start_field= row_start; - row_end_field= row_end; - vers_start_field()->flags|= VERS_SYS_START_FLAG; - vers_end_field()->flags|= VERS_SYS_END_FLAG; - } // if (system_period == NULL) - delete handler_file; share->error= OPEN_FRM_OK; diff --git a/sql/unireg.cc b/sql/unireg.cc index b647a284b14..c4b4a784ccc 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -1050,7 +1050,8 @@ static bool make_empty_rec(THD *thd, uchar *buff, uint table_options, field->unireg_check, field->save_interval ? field->save_interval : field->interval, - field->field_name); + field->field_name, + field->flags); if (!regfield) { error= 1; -- cgit v1.2.1 From 5ce6044b1c1cd501695b4d2d6cebf3876691d751 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Thu, 3 Aug 2017 15:04:15 +0300 Subject: SQL: remove versioning only when hidden system fields [closes #211] --- mysql-test/suite/versioning/r/alter.result | 26 +++++++++++++ mysql-test/suite/versioning/t/alter.test | 23 ++++++++++++ sql/handler.cc | 60 +++++++++++++++++++++++++----- sql/share/errmsg-utf8.txt | 3 ++ 4 files changed, 102 insertions(+), 10 deletions(-) diff --git a/mysql-test/suite/versioning/r/alter.result b/mysql-test/suite/versioning/r/alter.result index a4e51b1a3e2..4e58ac8e5f8 100644 --- a/mysql-test/suite/versioning/r/alter.result +++ b/mysql-test/suite/versioning/r/alter.result @@ -57,6 +57,7 @@ t CREATE TABLE `t` ( `trx_end` timestamp(6) GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (`trx_start`, `trx_end`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +alter table t drop column trx_start, drop column trx_end; alter table t without system versioning; show create table t; Table Create Table @@ -338,6 +339,7 @@ t CREATE TABLE `t` ( `trx_end` bigint(20) unsigned GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (`trx_start`, `trx_end`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +alter table t drop column trx_start, drop column trx_end; alter table t without system versioning; alter table t with system versioning, algorithm=copy; show create table t; @@ -511,6 +513,30 @@ period for system_time(sys_trx_start, sys_trx_end) ) with system versioning engine myisam; alter table t change column sys_trx_start asdf timestamp(6); ERROR HY000: Can not change system versioning field 'sys_trx_start' +create or replace table t ( +a int, +sys_trx_start timestamp(6) generated always as row start, +sys_trx_end timestamp(6) generated always as row end, +period for system_time(sys_trx_start, sys_trx_end) +) with system versioning; +select * from t; +a sys_trx_start sys_trx_end +alter table t without system versioning; +ERROR HY000: System versioning field 'sys_trx_start' is not hidden +alter table t drop column sys_trx_start; +select * from t; +a sys_trx_end +alter table t without system versioning; +ERROR HY000: System versioning field 'sys_trx_end' is not hidden +alter table t drop column sys_trx_end; +select * from t; +a +alter table t without system versioning; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 call verify_vtq; No A B C D 1 1 1 1 1 diff --git a/mysql-test/suite/versioning/t/alter.test b/mysql-test/suite/versioning/t/alter.test index edbb107b566..30fee87f3fe 100644 --- a/mysql-test/suite/versioning/t/alter.test +++ b/mysql-test/suite/versioning/t/alter.test @@ -41,6 +41,7 @@ alter table t with system versioning; show create table t; +alter table t drop column trx_start, drop column trx_end; alter table t without system versioning; show create table t; @@ -150,6 +151,7 @@ alter table t add period for system_time(trx_start, trx_end), with system versioning; show create table t; +alter table t drop column trx_start, drop column trx_end; alter table t without system versioning; alter table t with system versioning, algorithm=copy; @@ -238,6 +240,27 @@ create or replace table t ( --error ER_VERS_ALTER_SYSTEM_FIELD alter table t change column sys_trx_start asdf timestamp(6); +create or replace table t ( + a int, + sys_trx_start timestamp(6) generated always as row start, + sys_trx_end timestamp(6) generated always as row end, + period for system_time(sys_trx_start, sys_trx_end) +) with system versioning; +select * from t; + +--error ER_VERS_SYS_FIELD_NOT_HIDDEN +alter table t without system versioning; +alter table t drop column sys_trx_start; +select * from t; + +--error ER_VERS_SYS_FIELD_NOT_HIDDEN +alter table t without system versioning; +alter table t drop column sys_trx_end; +select * from t; + +alter table t without system versioning; +show create table t; + call verify_vtq; drop table t; diff --git a/sql/handler.cc b/sql/handler.cc index 3adf4969f73..7e540b59d08 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6603,15 +6603,12 @@ bool Vers_parse_info::is_trx_end(const Create_field &f) const return f.flags & VERS_SYS_END_FLAG; } - -static bool vers_create_sys_field(THD *thd, const char *field_name, - Alter_info *alter_info, - int flags, - bool integer_fields) +static Create_field *vers_init_sys_field(THD *thd, const char *field_name, + int flags, bool integer_fields) { Create_field *f= new (thd->mem_root) Create_field(); if (!f) - return true; + return NULL; memset(f, 0, sizeof(*f)); f->field_name= field_name; @@ -6630,10 +6627,38 @@ static bool vers_create_sys_field(THD *thd, const char *field_name, } if (f->check(thd)) + return NULL; + + return f; +} + +static bool vers_create_sys_field(THD *thd, const char *field_name, + Alter_info *alter_info, int flags, + bool integer_fields) +{ + Create_field *f= vers_init_sys_field(thd, field_name, flags, integer_fields); + if (!f) return true; - alter_info->create_list.push_back(f); alter_info->flags|= Alter_info::ALTER_ADD_COLUMN; + alter_info->create_list.push_back(f); + + return false; +} + +static bool vers_change_sys_field(THD *thd, const char *field_name, + Alter_info *alter_info, int flags, + bool integer_fields, const char *change) +{ + Create_field *f= vers_init_sys_field(thd, field_name, flags, integer_fields); + if (!f) + return true; + + f->change= change; + + alter_info->flags|= Alter_info::ALTER_CHANGE_COLUMN; + alter_info->create_list.push_back(f); + return false; } @@ -6814,6 +6839,7 @@ static bool add_field_to_drop_list(THD *thd, Alter_info *alter_info, { DBUG_ASSERT(field); DBUG_ASSERT(field->field_name); + alter_info->flags|= Alter_info::ALTER_DROP_COLUMN; Alter_drop *ad= new (thd->mem_root) Alter_drop(Alter_drop::COLUMN, field->field_name, false); return !ad || alter_info->drop_list.push_back(ad, thd->mem_root); @@ -6838,11 +6864,23 @@ bool Vers_parse_info::check_and_fix_alter(THD *thd, Alter_info *alter_info, return true; } + if (!(share->vers_start_field()->flags & HIDDEN_FLAG)) + { + my_error(ER_VERS_SYS_FIELD_NOT_HIDDEN, MYF(0), + share->vers_start_field()->field_name); + return true; + } + if (!(share->vers_end_field()->flags & HIDDEN_FLAG)) + { + my_error(ER_VERS_SYS_FIELD_NOT_HIDDEN, MYF(0), + share->vers_end_field()->field_name); + return true; + } + if (add_field_to_drop_list(thd, alter_info, share->vers_start_field()) || add_field_to_drop_list(thd, alter_info, share->vers_end_field())) return true; - alter_info->flags|= Alter_info::ALTER_DROP_COLUMN; return false; } @@ -6908,14 +6946,16 @@ bool Vers_parse_info::check_and_fix_alter(THD *thd, Alter_info *alter_info, return true; } - if (vers_create_sys_field(thd, name, alter_info, + if (vers_change_sys_field(thd, name, alter_info, f->flags & (VERS_SYS_START_FLAG | VERS_SYS_END_FLAG), - integer_fields)) + integer_fields, name)) { return true; } + it.remove(); + if (done_start && done_end) break; } diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index bae32e4d247..9265362a2b4 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7597,3 +7597,6 @@ ER_WRONG_TABLESPACE_NAME 42000 ER_VERS_ALTER_SYSTEM_FIELD eng "Can not change system versioning field '%s'" + +ER_VERS_SYS_FIELD_NOT_HIDDEN + eng "System versioning field '%s' is not hidden" -- cgit v1.2.1 From 53370de103a58bff2d6c566f411e58d70bd5d446 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Fri, 4 Aug 2017 17:06:33 +0300 Subject: IB: partition-wise ha_innopart::rnd_init() [fixes #208] --- mysql-test/suite/versioning/r/partition.result | 10 ++++++++++ mysql-test/suite/versioning/t/partition.test | 10 ++++++++++ sql/partition_info.cc | 1 + sql/partitioning/partition_handler.cc | 1 + sql/partitioning/partition_handler.h | 7 +++++++ storage/innobase/handler/ha_innopart.h | 17 +++++++++++++++-- 6 files changed, 44 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/versioning/r/partition.result b/mysql-test/suite/versioning/r/partition.result index a2aab637f31..89f96b7b4e4 100644 --- a/mysql-test/suite/versioning/r/partition.result +++ b/mysql-test/suite/versioning/r/partition.result @@ -147,11 +147,21 @@ t1 CREATE TABLE `t1` ( (PARTITION p0 VERSIONING ENGINE = ${INNODB_OR_MYISAM}, PARTITION p1 VERSIONING ENGINE = ${INNODB_OR_MYISAM}, PARTITION pn AS OF NOW ENGINE = ${INNODB_OR_MYISAM}) +insert into t1 values (1), (2); alter table t1 drop partition pn; ERROR HY000: Wrong partitions consistency for `t1`: must have at least one 'VERSIONING' and exactly one last 'AS OF NOW' alter table t1 drop partition p1; alter table t1 drop partition p0; ERROR HY000: Wrong partitions consistency for `t1`: must have at least one 'VERSIONING' and exactly one last 'AS OF NOW' +select x from t1; +x +1 +2 +create or replace table t1 (x int) +with system versioning +partition by system_time ( +partition p0 versioning, +partition pn as of now); set @now= now(6); insert into t1 values (1); set @ts_start= sys_commit_ts('sys_trx_start'); diff --git a/mysql-test/suite/versioning/t/partition.test b/mysql-test/suite/versioning/t/partition.test index cbecde0be9b..d5a9643de9a 100644 --- a/mysql-test/suite/versioning/t/partition.test +++ b/mysql-test/suite/versioning/t/partition.test @@ -79,13 +79,23 @@ alter table t1 add partition ( --replace_result InnoDB ${INNODB_OR_MYISAM} MyISAM ${INNODB_OR_MYISAM} "bigint(20) unsigned" ${SYS_TRX_TYPE} timestamp(6) ${SYS_TRX_TYPE} show create table t1; +insert into t1 values (1), (2); + --error ER_VERS_WRONG_PARTS alter table t1 drop partition pn; alter table t1 drop partition p1; --error ER_VERS_WRONG_PARTS alter table t1 drop partition p0; +select x from t1; + # insert, delete, update +create or replace table t1 (x int) +with system versioning +partition by system_time ( + partition p0 versioning, + partition pn as of now); + set @now= now(6); insert into t1 values (1); set @ts_start= sys_commit_ts('sys_trx_start'); diff --git a/sql/partition_info.cc b/sql/partition_info.cc index dd4ec54673a..86fb4b5bf63 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -1024,6 +1024,7 @@ bool partition_info::vers_scan_min_max(THD *thd, partition_element *part) for (; part_id < part_id_end; ++part_id) { handler *file= table->file->part_handler(part_id); // requires update_partition() for ha_innopart + DBUG_ASSERT(file); int rc= file->ha_external_lock(thd, F_RDLCK); // requires ha_commit_trans() for ha_innobase if (rc) { diff --git a/sql/partitioning/partition_handler.cc b/sql/partitioning/partition_handler.cc index 1e04439e100..ae395a71a42 100644 --- a/sql/partitioning/partition_handler.cc +++ b/sql/partitioning/partition_handler.cc @@ -286,6 +286,7 @@ Partition_helper::Partition_helper(handler *main_handler) m_part_info(), m_tot_parts(), m_last_part(), + m_cur_part(NO_CURRENT_PART_ID), m_err_rec(), m_ordered(), m_ordered_scan_ongoing(), diff --git a/sql/partitioning/partition_handler.h b/sql/partitioning/partition_handler.h index cf4e1dcb24b..f4436be4262 100644 --- a/sql/partitioning/partition_handler.h +++ b/sql/partitioning/partition_handler.h @@ -1061,6 +1061,13 @@ protected: /** Total number of partitions. */ uint m_tot_parts; uint m_last_part; // Last accessed partition. + uint m_cur_part; // Current partition + /* In fact m_cur_part duplicates m_part_spec, but is required due to different + rnd_init() semantics between ha_innopart and ha_partition. + ha_innopart::rnd_init() is table-wise (it has separate *_in_part() methods). + ha_partition::rnd_init() is partition-wise. m_cur_part is used to imitate + partition-wise rnd_init() and should not be merged with m_part_spec because of + different usage scenarios. */ const uchar *m_err_rec; // record which gave error. bool m_auto_increment_safe_stmt_log_lock; bool m_auto_increment_lock; diff --git a/storage/innobase/handler/ha_innopart.h b/storage/innobase/handler/ha_innopart.h index 090543196c4..d7314930091 100644 --- a/storage/innobase/handler/ha_innopart.h +++ b/storage/innobase/handler/ha_innopart.h @@ -755,6 +755,7 @@ private: virtual handler* part_handler(uint32 part_id) { set_partition(part_id); + m_cur_part = part_id; return this; } @@ -1095,12 +1096,21 @@ private: rnd_init( bool scan) { - return(Partition_helper::ph_rnd_init(scan)); + if (m_cur_part != NO_CURRENT_PART_ID) + { + m_scan_value= scan; + m_part_spec.start_part = m_cur_part; + m_part_spec.end_part = m_cur_part; + return rnd_init_in_part(m_cur_part, scan); + } + else + return(Partition_helper::ph_rnd_init(scan)); } int rnd_end() { + m_cur_part = NO_CURRENT_PART_ID; return(Partition_helper::ph_rnd_end()); } @@ -1411,7 +1421,10 @@ protected: rnd_next( uchar* record) { - return(Partition_helper::ph_rnd_next(record)); + if (m_cur_part != NO_CURRENT_PART_ID) + return rnd_next_in_part(m_cur_part, record); + else + return(Partition_helper::ph_rnd_next(record)); } int -- cgit v1.2.1 From d3d2ea9fd59a836dd0b0577658c5961712a5ed9d Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 8 Aug 2017 17:12:16 +0300 Subject: SQL, Parser: system_time logic and syntax fixes [closes #237] --- mysql-test/suite/versioning/r/alter.result | 8 +- mysql-test/suite/versioning/r/create.result | 32 +---- mysql-test/suite/versioning/r/select.result | 52 +------- mysql-test/suite/versioning/r/select_sp.result | 64 +--------- mysql-test/suite/versioning/r/sysvars.result | 4 +- mysql-test/suite/versioning/r/truncate.result | 20 +-- mysql-test/suite/versioning/t/alter.test | 6 +- mysql-test/suite/versioning/t/create.test | 30 ----- mysql-test/suite/versioning/t/select.test | 18 +-- mysql-test/suite/versioning/t/select_sp.test | 18 +-- mysql-test/suite/versioning/t/sysvars.test | 4 +- mysql-test/suite/versioning/t/truncate.test | 20 +-- sql/item.cc | 5 +- sql/share/errmsg-utf8.txt | 12 -- sql/sql_base.cc | 4 +- sql/sql_delete.cc | 9 +- sql/sql_derived.cc | 16 +-- sql/sql_lex.cc | 4 +- sql/sql_lex.h | 5 +- sql/sql_select.cc | 147 ++++++++++++---------- sql/sql_truncate.cc | 13 +- sql/sql_view.cc | 8 +- sql/sql_yacc.yy | 161 +++++++++++-------------- sql/table.cc | 18 +++ sql/table.h | 19 +-- 25 files changed, 263 insertions(+), 434 deletions(-) diff --git a/mysql-test/suite/versioning/r/alter.result b/mysql-test/suite/versioning/r/alter.result index 4e58ac8e5f8..14cb242d09e 100644 --- a/mysql-test/suite/versioning/r/alter.result +++ b/mysql-test/suite/versioning/r/alter.result @@ -8,8 +8,6 @@ t CREATE TABLE `t` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 alter table t without system versioning; ERROR HY000: Wrong parameters for `t`: table is not versioned -alter table t with system versioning without system versioning; -ERROR HY000: Wrong parameters for `t`: multiple 'WITH/WITHOUT SYSTEM VERSIONING' alter table t with system versioning; show create table t; Table Create Table @@ -226,10 +224,8 @@ t CREATE TABLE `t` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 alter table t modify a int with system versioning; ERROR HY000: Wrong parameters for `t`: table is not versioned -alter table t modify a int with system versioning with system versioning; -ERROR HY000: Wrong parameters for `t`: multiple 'WITH/WITHOUT SYSTEM VERSIONING' for `a` -alter table t modify a int with system versioning without system versioning; -ERROR HY000: Wrong parameters for `t`: multiple 'WITH/WITHOUT SYSTEM VERSIONING' for `a` +alter table t modify a int without system versioning; +ERROR HY000: Wrong parameters for `t`: table is not versioned alter table t with system versioning; alter table t modify a int without system versioning; show create table t; diff --git a/mysql-test/suite/versioning/r/create.result b/mysql-test/suite/versioning/r/create.result index 32b8d1c97a7..b71e84ccc08 100644 --- a/mysql-test/suite/versioning/r/create.result +++ b/mysql-test/suite/versioning/r/create.result @@ -103,7 +103,7 @@ Sys_start2 SYS_TRX_TYPE generated always as row start, Sys_end SYS_TRX_TYPE generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning; -ERROR HY000: Wrong parameters for `t1`: multiple 'AS ROW START' (`Sys_start2`, `Sys_start`) +ERROR HY000: Wrong parameters for `t1`: mismatch 'PERIOD FOR SYSTEM_TIME' and 'AS ROW START' create or replace table t1 ( x4 int unsigned, Sys_start SYS_TRX_TYPE generated always as row start, @@ -118,7 +118,7 @@ Sys_end SYS_TRX_TYPE generated always as row end, Sys_end2 SYS_TRX_TYPE generated always as row end, period for system_time (Sys_start, Sys_end) ) with system versioning; -ERROR HY000: Wrong parameters for `t1`: multiple 'AS ROW END' (`Sys_end2`, `Sys_end`) +ERROR HY000: Wrong parameters for `t1`: mismatch 'PERIOD FOR SYSTEM_TIME' and 'AS ROW END' create or replace table t1 ( x6 int unsigned, period for system_time (Sys_start, Sys_end) @@ -131,7 +131,7 @@ Sys_end SYS_TRX_TYPE generated always as row end, Sys_end2 SYS_TRX_TYPE generated always as row end, period for system_time (Sys_start, Sys_end) ); -ERROR HY000: Wrong parameters for `t1`: multiple 'AS ROW END' (`Sys_end2`, `Sys_end`) +ERROR HY000: Wrong parameters for `t1`: missing 'WITH SYSTEM VERSIONING' create or replace table t1 ( x8 int unsigned, Sys_start SYS_TRX_TYPE generated always as row start, @@ -152,7 +152,7 @@ Sys_start SYS_TRX_TYPE generated always as row start, Sys_end SYS_TRX_TYPE generated always as row end, period for system_time (Sys_start, Sys_start) ); -ERROR HY000: Wrong parameters for `t1`: multiple `Sys_start` for 'PERIOD FOR SYSTEM_TIME' +ERROR HY000: Wrong parameters for `t1`: missing 'WITH SYSTEM VERSIONING' create or replace table t1 ( x11 int unsigned, Sys_start bigint unsigned generated always as row start, @@ -257,34 +257,10 @@ create or replace table t1 ( A8 int without system versioning ) with system versioning; ERROR HY000: Wrong parameters for `t1`: no columns defined 'WITH SYSTEM VERSIONING' -create or replace table t1 ( -A9 int without system versioning with system versioning -); -ERROR HY000: Wrong parameters for `t1`: multiple 'WITH/WITHOUT SYSTEM VERSIONING' for `A9` -create or replace table t1 ( -A10 int with system versioning without system versioning -); -ERROR HY000: Wrong parameters for `t1`: multiple 'WITH/WITHOUT SYSTEM VERSIONING' for `A10` create table t( a11 int ) without system versioning; ERROR HY000: Wrong parameters for `t`: not allowed 'WITHOUT SYSTEM VERSIONING' -create or replace table t1 ( -A12 int -) without system versioning with system versioning; -ERROR HY000: Wrong parameters for `t1`: multiple 'WITH/WITHOUT SYSTEM VERSIONING' -create or replace table t1 ( -A13 int -) with system versioning without system versioning; -ERROR HY000: Wrong parameters for `t1`: multiple 'WITH/WITHOUT SYSTEM VERSIONING' -create or replace table t1 ( -A14 int -) with system versioning with system versioning; -ERROR HY000: Wrong parameters for `t1`: multiple 'WITH/WITHOUT SYSTEM VERSIONING' -create or replace table t1 ( -A15 int -) without system versioning without system versioning; -ERROR HY000: Wrong parameters for `t1`: multiple 'WITH/WITHOUT SYSTEM VERSIONING' create or replace table t1 (a int) with system versioning; create temporary table tmp with system versioning select * from t1; create or replace table t1 (a int) with system versioning; diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index 8599cb92b52..eabeaf0d85a 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -102,7 +102,7 @@ ASOF_x y 7 107 8 108 9 109 -select x as FROMTO_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; +select x as FROMTO_x, y from t1 for system_time from '0-0-0 0:0:0' to timestamp @t1; FROMTO_x y 0 100 1 101 @@ -114,7 +114,7 @@ FROMTO_x y 7 107 8 108 9 109 -select x as BETWAND_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; +select x as BETWAND_x, y from t1 for system_time between '0-0-0 0:0:0' and timestamp @t1; BETWAND_x y 0 100 1 101 @@ -127,31 +127,6 @@ BETWAND_x y 8 108 9 109 3 33 -select x as FROMTO_ext_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; -FROMTO_ext_x y -0 100 -1 101 -2 102 -3 103 -4 104 -5 105 -6 106 -7 107 -8 108 -9 109 -select x as BETWAND_ext_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; -BETWAND_ext_x y -0 100 -1 101 -2 102 -3 103 -4 104 -5 105 -6 106 -7 107 -8 108 -9 109 -3 33 select x as ALL_x, y from t1 for system_time all; ALL_x y 0 100 @@ -199,29 +174,6 @@ BETWAND2_x y 8 108 9 109 3 33 -FROMTO2_ext_x y -0 100 -1 101 -2 102 -3 103 -4 104 -5 105 -6 106 -7 107 -8 108 -9 109 -BETWAND2_ext_x y -0 100 -1 101 -2 102 -3 103 -4 104 -5 105 -6 106 -7 107 -8 108 -9 109 -3 33 create or replace table t1 ( x int unsigned, y int unsigned diff --git a/mysql-test/suite/versioning/r/select_sp.result b/mysql-test/suite/versioning/r/select_sp.result index 9ced07f03e1..69fbc1255f1 100644 --- a/mysql-test/suite/versioning/r/select_sp.result +++ b/mysql-test/suite/versioning/r/select_sp.result @@ -100,23 +100,17 @@ select vtq_commit_ts(@x1) into @t1; end if; select x, y from t1; select x as ASOF_x, y from t1 for system_time as of timestamp @t0; -select x as FROMTO_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; -select x as BETWAND_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; -select x as FROMTO_ext_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; -select x as BETWAND_ext_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; +select x as FROMTO_x, y from t1 for system_time from '0-0-0 0:0:0' to timestamp @t1; +select x as BETWAND_x, y from t1 for system_time between '0-0-0 0:0:0' and timestamp @t1; select x as ALL_x, y from t1 for system_time all; if engine = 'innodb' then -select x as ASOF2_x, y from t1 for system_time as of transaction @x0; -select x as FROMTO2_x, y from t1 for system_time from transaction @x0 to transaction @x1; +select x as ASOF2_x, y from t1 for system_time as of @x0; +select x as FROMTO2_x, y from t1 for system_time from @x0 to @x1; select x as BETWAND2_x, y from t1 for system_time between transaction @x0 and transaction @x1; -select x as FROMTO2_ext_x, y from t1 for system_time transaction from @x0 to @x1; -select x as BETWAND2_ext_x, y from t1 for system_time transaction between @x0 and @x1; else -select x as ASOF2_x, y from t1 for system_time as of timestamp @t0; -select x as FROMTO2_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; +select x as ASOF2_x, y from t1 for system_time as of @t0; +select x as FROMTO2_x, y from t1 for system_time from '0-0-0 0:0:0' to @t1; select x as BETWAND2_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; -select x as FROMTO2_ext_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; -select x as BETWAND2_ext_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; end if; drop table t1; end~~ @@ -198,29 +192,6 @@ BETWAND_x y 8 108 9 109 3 33 -FROMTO_ext_x y -0 100 -1 101 -2 102 -3 103 -4 104 -5 105 -6 106 -7 107 -8 108 -9 109 -BETWAND_ext_x y -0 100 -1 101 -2 102 -3 103 -4 104 -5 105 -6 106 -7 107 -8 108 -9 109 -3 33 ALL_x y 0 100 1 101 @@ -267,29 +238,6 @@ BETWAND2_x y 8 108 9 109 3 33 -FROMTO2_ext_x y -0 100 -1 101 -2 102 -3 103 -4 104 -5 105 -6 106 -7 107 -8 108 -9 109 -BETWAND2_ext_x y -0 100 -1 101 -2 102 -3 103 -4 104 -5 105 -6 106 -7 107 -8 108 -9 109 -3 33 call test_02(); IJ1_x1 y1 x2 y2 1 1 1 2 diff --git a/mysql-test/suite/versioning/r/sysvars.result b/mysql-test/suite/versioning/r/sysvars.result index 56122432e6e..a9cc7d3aec3 100644 --- a/mysql-test/suite/versioning/r/sysvars.result +++ b/mysql-test/suite/versioning/r/sysvars.result @@ -115,11 +115,11 @@ select * from t for system_time all; a sys_trx_start sys_trx_end 2 TIMESTAMP TIMESTAMP 1 TIMESTAMP TIMESTAMP -select * from t for system_time timestamp from '0-0-0' to current_timestamp(6); +select * from t for system_time from '0-0-0' to current_timestamp(6); a sys_trx_start sys_trx_end 2 TIMESTAMP TIMESTAMP 1 TIMESTAMP TIMESTAMP -select * from t for system_time timestamp between '0-0-0' and current_timestamp(6); +select * from t for system_time between '0-0-0' and current_timestamp(6); a sys_trx_start sys_trx_end 2 TIMESTAMP TIMESTAMP 1 TIMESTAMP TIMESTAMP diff --git a/mysql-test/suite/versioning/r/truncate.result b/mysql-test/suite/versioning/r/truncate.result index 5651cffb179..957163286c3 100644 --- a/mysql-test/suite/versioning/r/truncate.result +++ b/mysql-test/suite/versioning/r/truncate.result @@ -1,9 +1,9 @@ create table t (a int); truncate t for system_time all; -ERROR HY000: Unused clause: 'SYSTEM_TIME' +ERROR HY000: System Versioning required: t create procedure truncate_history_of_t() begin -prepare stmt from 'truncate t for system_time timestamp between \'1-1-1\' and now(6)'; +prepare stmt from 'truncate t for system_time between \'1-1-1\' and now(6)'; execute stmt; drop prepare stmt; end~~ @@ -34,12 +34,12 @@ a 4 2 3 -truncate t for system_time timestamp between '1-1-1' and now(6); +truncate t for system_time between '1-1-1' and now(6); select * from t for system_time all; a 4 update t set a=5; -truncate t for system_time timestamp from '1-1-1' to now(6); +truncate t for system_time from '1-1-1' to now(6); select * from t for system_time all; a 5 @@ -52,13 +52,13 @@ set @ts1 = now(6); update t set a=7; set @ts2 = now(6); update t set a=8; -truncate t for system_time timestamp from '1-1-1' to @ts1; +truncate t for system_time from '1-1-1' to @ts1; select * from t for system_time all; a 8 7 update t set a=9; -truncate t for system_time timestamp between '1-1-1' and @ts2; +truncate t for system_time between '1-1-1' and @ts2; select * from t for system_time all; a 9 @@ -82,12 +82,12 @@ a 4 2 3 -truncate t for system_time timestamp between '1-1-1' and now(6); +truncate t for system_time between '1-1-1' and now(6); select * from t for system_time all; a 4 update t set a=5; -truncate t for system_time timestamp from '1-1-1' to now(6); +truncate t for system_time from '1-1-1' to now(6); select * from t for system_time all; a 5 @@ -100,13 +100,13 @@ set @ts1 = now(6); update t set a=7; set @ts2 = now(6); update t set a=8; -truncate t for system_time timestamp from '1-1-1' to @ts1; +truncate t for system_time from '1-1-1' to timestamp @ts1; select * from t for system_time all; a 8 7 update t set a=9; -truncate t for system_time timestamp between '1-1-1' and @ts2; +truncate t for system_time between '1-1-1' and timestamp @ts2; select * from t for system_time all; a 9 diff --git a/mysql-test/suite/versioning/t/alter.test b/mysql-test/suite/versioning/t/alter.test index 30fee87f3fe..6ceac987a5e 100644 --- a/mysql-test/suite/versioning/t/alter.test +++ b/mysql-test/suite/versioning/t/alter.test @@ -4,8 +4,6 @@ create table t( show create table t; --error ER_VERS_WRONG_PARAMS alter table t without system versioning; ---error ER_VERS_WRONG_PARAMS -alter table t with system versioning without system versioning; alter table t with system versioning; show create table t; @@ -118,9 +116,7 @@ show create table t; --error ER_VERS_WRONG_PARAMS alter table t modify a int with system versioning; --error ER_VERS_WRONG_PARAMS -alter table t modify a int with system versioning with system versioning; ---error ER_VERS_WRONG_PARAMS -alter table t modify a int with system versioning without system versioning; +alter table t modify a int without system versioning; alter table t with system versioning; diff --git a/mysql-test/suite/versioning/t/create.test b/mysql-test/suite/versioning/t/create.test index 9c92cc30e2c..9de6a5157b3 100644 --- a/mysql-test/suite/versioning/t/create.test +++ b/mysql-test/suite/versioning/t/create.test @@ -192,16 +192,6 @@ create or replace table t1 ( A8 int without system versioning ) with system versioning; ---error ER_VERS_WRONG_PARAMS -create or replace table t1 ( - A9 int without system versioning with system versioning -); - ---error ER_VERS_WRONG_PARAMS -create or replace table t1 ( - A10 int with system versioning without system versioning -); - # table with/without system versioning --error ER_VERS_WRONG_PARAMS @@ -209,26 +199,6 @@ create table t( a11 int ) without system versioning; ---error ER_VERS_WRONG_PARAMS -create or replace table t1 ( - A12 int -) without system versioning with system versioning; - ---error ER_VERS_WRONG_PARAMS -create or replace table t1 ( - A13 int -) with system versioning without system versioning; - ---error ER_VERS_WRONG_PARAMS -create or replace table t1 ( - A14 int -) with system versioning with system versioning; - ---error ER_VERS_WRONG_PARAMS -create or replace table t1 ( - A15 int -) without system versioning without system versioning; - create or replace table t1 (a int) with system versioning; create temporary table tmp with system versioning select * from t1; diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index 5dc5f603d54..345e28f610c 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -42,28 +42,22 @@ if ($default_engine == 'innodb') select x, y from t1; select x as ASOF_x, y from t1 for system_time as of timestamp @t0; -select x as FROMTO_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; -select x as BETWAND_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; -select x as FROMTO_ext_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; -select x as BETWAND_ext_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; +select x as FROMTO_x, y from t1 for system_time from '0-0-0 0:0:0' to timestamp @t1; +select x as BETWAND_x, y from t1 for system_time between '0-0-0 0:0:0' and timestamp @t1; select x as ALL_x, y from t1 for system_time all; --disable_query_log if ($default_engine == 'innodb') { - select x as ASOF2_x, y from t1 for system_time as of transaction @x0; - select x as FROMTO2_x, y from t1 for system_time from transaction @x0 to transaction @x1; + select x as ASOF2_x, y from t1 for system_time as of @x0; + select x as FROMTO2_x, y from t1 for system_time from @x0 to @x1; select x as BETWAND2_x, y from t1 for system_time between transaction @x0 and transaction @x1; - select x as FROMTO2_ext_x, y from t1 for system_time transaction from @x0 to @x1; - select x as BETWAND2_ext_x, y from t1 for system_time transaction between @x0 and @x1; } if ($default_engine != 'innodb') { - select x as ASOF2_x, y from t1 for system_time as of timestamp @t0; - select x as FROMTO2_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; + select x as ASOF2_x, y from t1 for system_time as of @t0; + select x as FROMTO2_x, y from t1 for system_time from '0-0-0 0:0:0' to @t1; select x as BETWAND2_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; - select x as FROMTO2_ext_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; - select x as BETWAND2_ext_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; } --enable_query_log diff --git a/mysql-test/suite/versioning/t/select_sp.test b/mysql-test/suite/versioning/t/select_sp.test index 23921e9580d..d261e1bc537 100644 --- a/mysql-test/suite/versioning/t/select_sp.test +++ b/mysql-test/suite/versioning/t/select_sp.test @@ -45,24 +45,18 @@ begin select x, y from t1; select x as ASOF_x, y from t1 for system_time as of timestamp @t0; - select x as FROMTO_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; - select x as BETWAND_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; - select x as FROMTO_ext_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; - select x as BETWAND_ext_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; + select x as FROMTO_x, y from t1 for system_time from '0-0-0 0:0:0' to timestamp @t1; + select x as BETWAND_x, y from t1 for system_time between '0-0-0 0:0:0' and timestamp @t1; select x as ALL_x, y from t1 for system_time all; if engine = 'innodb' then - select x as ASOF2_x, y from t1 for system_time as of transaction @x0; - select x as FROMTO2_x, y from t1 for system_time from transaction @x0 to transaction @x1; + select x as ASOF2_x, y from t1 for system_time as of @x0; + select x as FROMTO2_x, y from t1 for system_time from @x0 to @x1; select x as BETWAND2_x, y from t1 for system_time between transaction @x0 and transaction @x1; - select x as FROMTO2_ext_x, y from t1 for system_time transaction from @x0 to @x1; - select x as BETWAND2_ext_x, y from t1 for system_time transaction between @x0 and @x1; else - select x as ASOF2_x, y from t1 for system_time as of timestamp @t0; - select x as FROMTO2_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; + select x as ASOF2_x, y from t1 for system_time as of @t0; + select x as FROMTO2_x, y from t1 for system_time from '0-0-0 0:0:0' to @t1; select x as BETWAND2_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; - select x as FROMTO2_ext_x, y from t1 for system_time from timestamp '0-0-0 0:0:0' to timestamp @t1; - select x as BETWAND2_ext_x, y from t1 for system_time between timestamp '0-0-0 0:0:0' and timestamp @t1; end if; drop table t1; diff --git a/mysql-test/suite/versioning/t/sysvars.test b/mysql-test/suite/versioning/t/sysvars.test index 4516833d58d..6b713c29239 100644 --- a/mysql-test/suite/versioning/t/sysvars.test +++ b/mysql-test/suite/versioning/t/sysvars.test @@ -84,9 +84,9 @@ select * from t for system_time as of timestamp current_timestamp(6); --replace_regex /\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\.\d{6}/TIMESTAMP/ select * from t for system_time all; --replace_regex /\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\.\d{6}/TIMESTAMP/ -select * from t for system_time timestamp from '0-0-0' to current_timestamp(6); +select * from t for system_time from '0-0-0' to current_timestamp(6); --replace_regex /\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\.\d{6}/TIMESTAMP/ -select * from t for system_time timestamp between '0-0-0' and current_timestamp(6); +select * from t for system_time between '0-0-0' and current_timestamp(6); set versioning_hide= NEVER; --replace_regex /\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\.\d{6}/TIMESTAMP/ diff --git a/mysql-test/suite/versioning/t/truncate.test b/mysql-test/suite/versioning/t/truncate.test index 97362c7423b..ddd0db5856d 100644 --- a/mysql-test/suite/versioning/t/truncate.test +++ b/mysql-test/suite/versioning/t/truncate.test @@ -1,13 +1,13 @@ -- source include/have_innodb.inc create table t (a int); ---error ER_VERS_UNUSED_CLAUSE +--error ER_VERSIONING_REQUIRED truncate t for system_time all; delimiter ~~; create procedure truncate_history_of_t() begin - prepare stmt from 'truncate t for system_time timestamp between \'1-1-1\' and now(6)'; + prepare stmt from 'truncate t for system_time between \'1-1-1\' and now(6)'; execute stmt; drop prepare stmt; end~~ @@ -34,11 +34,11 @@ update t set a=4; truncate t for system_time as of timestamp now(6); select * from t for system_time all; -truncate t for system_time timestamp between '1-1-1' and now(6); +truncate t for system_time between '1-1-1' and now(6); select * from t for system_time all; update t set a=5; -truncate t for system_time timestamp from '1-1-1' to now(6); +truncate t for system_time from '1-1-1' to now(6); select * from t for system_time all; update t set a=6; @@ -49,10 +49,10 @@ set @ts1 = now(6); update t set a=7; set @ts2 = now(6); update t set a=8; -truncate t for system_time timestamp from '1-1-1' to @ts1; +truncate t for system_time from '1-1-1' to @ts1; select * from t for system_time all; update t set a=9; -truncate t for system_time timestamp between '1-1-1' and @ts2; +truncate t for system_time between '1-1-1' and @ts2; select * from t for system_time all; @@ -69,11 +69,11 @@ update t set a=4; truncate t for system_time as of timestamp now(6); select * from t for system_time all; -truncate t for system_time timestamp between '1-1-1' and now(6); +truncate t for system_time between '1-1-1' and now(6); select * from t for system_time all; update t set a=5; -truncate t for system_time timestamp from '1-1-1' to now(6); +truncate t for system_time from '1-1-1' to now(6); select * from t for system_time all; update t set a=6; @@ -84,10 +84,10 @@ set @ts1 = now(6); update t set a=7; set @ts2 = now(6); update t set a=8; -truncate t for system_time timestamp from '1-1-1' to @ts1; +truncate t for system_time from '1-1-1' to timestamp @ts1; select * from t for system_time all; update t set a=9; -truncate t for system_time timestamp between '1-1-1' and @ts2; +truncate t for system_time between '1-1-1' and timestamp @ts2; select * from t for system_time all; create or replace table t (a int) with system versioning; diff --git a/sql/item.cc b/sql/item.cc index 117662d9c79..4314ee036e4 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -10758,9 +10758,8 @@ Item *Item_field::vers_optimized_fields_transformer(THD *thd, uchar *) return this; if (field->flags & VERS_OPTIMIZED_UPDATE_FLAG && context && - ((field->table->pos_in_table_list && - field->table->pos_in_table_list->vers_conditions) || - (context->select_lex && context->select_lex->vers_conditions))) + field->table->pos_in_table_list && + field->table->pos_in_table_list->vers_conditions) { push_warning_printf( current_thd, Sql_condition::WARN_LEVEL_WARN, diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 9265362a2b4..c551bcef809 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7550,18 +7550,6 @@ WARN_VERS_ALIAS_TOO_LONG ER_VERS_VTMD_ERROR eng "VTMD error: %s" -ER_MULTIPLE_CLAUSE - eng "for %`s: multiple '%s'" - -ER_MULTIPLE_CLAUSE_FOR - eng "for %`s: multiple '%s' for %`s" - -ER_MULTIPLE_CLAUSE_2 - eng "for %`s: multiple '%s' (%`s, %`s)" - -ER_MULTIPLE_IDENTIFIER - eng "for %`s: multiple %`s for '%s'" - ER_NOT_ALLOWED eng "for %`s: not allowed '%s'" diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 0a7ad7aef55..27bf5ab6931 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7593,9 +7593,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, TABLE *table= f->field->table; DBUG_ASSERT(table && table->pos_in_table_list); TABLE_LIST *tl= table->pos_in_table_list; - vers_range_type_t vers_type= - tl->vers_conditions.type == FOR_SYSTEM_TIME_UNSPECIFIED ? - slex->vers_conditions.type : tl->vers_conditions.type; + vers_range_type_t vers_type= tl->vers_conditions.type; enum_sql_command sql_command= thd->lex->sql_command; unsigned int create_options= thd->lex->create_info.options; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 62171ae2423..8dc6203ed86 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -263,8 +263,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, if (open_and_lock_tables(thd, table_list, TRUE, 0)) DBUG_RETURN(TRUE); - bool truncate_history= - select_lex->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED; + bool truncate_history= table_list->vers_conditions; if (truncate_history) { TABLE *table= table_list->table; @@ -276,12 +275,12 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, // trx_sees() in InnoDB reads sys_trx_start if (!table->versioned_by_sql()) { - if (select_lex->vers_conditions.type == FOR_SYSTEM_TIME_BETWEEN || - select_lex->vers_conditions.type == FOR_SYSTEM_TIME_FROM_TO) + if (table_list->vers_conditions.type == FOR_SYSTEM_TIME_BETWEEN || + table_list->vers_conditions.type == FOR_SYSTEM_TIME_FROM_TO) { bitmap_set_bit(table->read_set, table->vers_start_field()->field_index); } - else if (select_lex->vers_conditions.type == FOR_SYSTEM_TIME_BEFORE) + else if (table_list->vers_conditions.type == FOR_SYSTEM_TIME_BEFORE) { bitmap_set_bit(table->read_set, table->vers_end_field()->field_index); } diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index d6a00827fef..cdbb01fa5aa 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -714,7 +714,7 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived) cursor->outer_join|= JOIN_TYPE_OUTER; } - // System Versioning begin + // System Versioning: fix system fields of versioned derived table #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat" #pragma GCC diagnostic ignored "-Wformat-extra-args" @@ -722,7 +722,11 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived) && sl->table_list.elements > 0) { // Similar logic as in mysql_create_view() - TABLE_LIST *impli_table= NULL, *expli_table= NULL; + // Leading versioning table detected implicitly (first one selected) + TABLE_LIST *impli_table= NULL; + // Leading versioning table specified explicitly + // (i.e. if at least one system field is selected) + TABLE_LIST *expli_table= NULL; const char *impli_start, *impli_end; Item_field *expli_start= NULL, *expli_end= NULL; @@ -826,14 +830,10 @@ expli_table_err: if (impli_table->vers_conditions) { - sl->vers_derived_conds= impli_table->vers_conditions; - if (derived->is_view() && !sl->vers_conditions) - sl->vers_conditions.import_outer= true; + sl->vers_export_outer= impli_table->vers_conditions; } - else if (sl->vers_conditions) - sl->vers_derived_conds= sl->vers_conditions; else - sl->vers_conditions.import_outer= true; + sl->vers_import_outer= true; // FIXME: is needed? } } // if (sl->table_list.elements > 0) #pragma GCC diagnostic pop diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 589d02fb55b..481ee76e0f2 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2282,8 +2282,8 @@ void st_select_lex::init_select() with_dep= 0; join= 0; lock_type= TL_READ_DEFAULT; - vers_conditions.empty(); - vers_derived_conds.empty(); + vers_import_outer= false; + vers_export_outer.empty(); } /* diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 5f6232c2c50..6756148431d 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -992,8 +992,9 @@ public: thr_lock_type lock_type; /* System Versioning */ - vers_select_conds_t vers_conditions; - vers_select_conds_t vers_derived_conds; + vers_select_conds_t vers_export_outer; + bool vers_import_outer; + /* push new Item_field into item_list */ bool vers_push_field(THD *thd, TABLE_LIST *table, const char* field_name); void init_query(); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 8575755c267..437c04c2984 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -672,7 +672,7 @@ bool vers_select_conds_t::init_from_sysvar(THD *thd) { st_vers_current_time &in= thd->variables.vers_current_time; type= in.type; - unit= UNIT_TIMESTAMP; + unit_start= UNIT_TIMESTAMP; if (type != FOR_SYSTEM_TIME_UNSPECIFIED && type != FOR_SYSTEM_TIME_ALL) { DBUG_ASSERT(type == FOR_SYSTEM_TIME_AS_OF); @@ -714,14 +714,7 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, } if (versioned_tables == 0) - { - if (slex->vers_conditions) - { - my_error(ER_VERS_UNUSED_CLAUSE, MYF(0), "SYSTEM_TIME"); - DBUG_RETURN(-1); - } DBUG_RETURN(0); - } /* For prepared statements we create items on statement arena, because they must outlive execution phase for multiple executions. */ @@ -771,53 +764,43 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, } SELECT_LEX *outer_slex= slex->next_select_in_list(); - bool force_slex_conds= false; - if (outer_slex) + // propagate derived conditions to outer SELECT_LEX + if (outer_slex && slex->vers_export_outer) { - if (slex->vers_derived_conds) + for (table= outer_slex->table_list.first; table; table= table->next_local) { - // Propagate derived conditions to outer SELECT_LEX: - if (!outer_slex->vers_conditions) + if (!table->vers_conditions) { - outer_slex->vers_conditions= slex->vers_derived_conds; - outer_slex->vers_conditions.from_inner= true; - outer_slex->vers_conditions.used= true; + table->vers_conditions= slex->vers_export_outer; + table->vers_conditions.from_inner= true; } } - if (slex->vers_conditions.import_outer) + } + + for (table= tables; table; table= table->next_local) + { + if (table->table && table->table->versioned()) { - DBUG_ASSERT(slex->master_unit()); - TABLE_LIST* derived= slex->master_unit()->derived; - DBUG_ASSERT(derived); - if (derived->vers_conditions) - { - slex->vers_conditions= derived->vers_conditions; - derived->vers_conditions.used= true; - force_slex_conds= derived->is_view(); - } - else + vers_select_conds_t &vers_conditions= table->vers_conditions; + + // propagate system_time from nearest outer SELECT_LEX + if (!vers_conditions && outer_slex && slex->vers_import_outer) { - // Propagate query conditions from nearest outer SELECT_LEX: - while (outer_slex && (!outer_slex->vers_conditions || outer_slex->vers_conditions.from_inner)) + TABLE_LIST* derived= slex->master_unit()->derived; + while (outer_slex && (!derived->vers_conditions || derived->vers_conditions.from_inner)) + { + derived= outer_slex->master_unit()->derived; outer_slex= outer_slex->next_select_in_list(); + } if (outer_slex) { - slex->vers_conditions= outer_slex->vers_conditions; - outer_slex->vers_conditions.used= true; - force_slex_conds= derived->is_view(); + DBUG_ASSERT(derived); + DBUG_ASSERT(derived->vers_conditions); + vers_conditions= derived->vers_conditions; } } - } - } - - for (table= tables; table; table= table->next_local) - { - if (table->table && table->table->versioned()) - { - vers_select_conds_t &vers_conditions= force_slex_conds || !table->vers_conditions? - (slex->vers_conditions.used= true, slex->vers_conditions) : - table->vers_conditions; + // propagate system_time from sysvar if (!vers_conditions) { if (vers_conditions.init_from_sysvar(thd)) @@ -869,12 +852,57 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, bool tmp_from_ib= table->table->s->table_category == TABLE_CATEGORY_TEMPORARY && table->table->vers_start_field()->type() == MYSQL_TYPE_LONGLONG; - if (table->table->versioned_by_sql() && !tmp_from_ib) + bool timestamps_only= table->table->versioned_by_sql() && !tmp_from_ib; + + if (vers_conditions) { - if (vers_conditions.unit == UNIT_TRX_ID) + vers_conditions.resolve_units(timestamps_only); + if (timestamps_only) { - my_error(ER_VERS_ENGINE_UNSUPPORTED, MYF(0), table->table_name); - DBUG_RETURN(-1); + if (vers_conditions.unit_start == UNIT_TRX_ID || vers_conditions.unit_end == UNIT_TRX_ID) + { + my_error(ER_VERS_ENGINE_UNSUPPORTED, MYF(0), table->table_name); + DBUG_RETURN(-1); + } + } + else if (thd->variables.vers_innodb_algorithm_simple) + { + DBUG_ASSERT(table->table->s && table->table->s->db_plugin); + handlerton *hton= plugin_hton(table->table->s->db_plugin); + DBUG_ASSERT(hton); + bool convert_start= false; + bool convert_end= false; + switch (vers_conditions.type) + { + case FOR_SYSTEM_TIME_AS_OF: + if (vers_conditions.unit_start == UNIT_TIMESTAMP) + convert_start= convert_end= true; + break; + case FOR_SYSTEM_TIME_BEFORE: + if (vers_conditions.unit_start == UNIT_TIMESTAMP) + convert_end= true; + break; + case FOR_SYSTEM_TIME_FROM_TO: + case FOR_SYSTEM_TIME_BETWEEN: + if (vers_conditions.unit_start == UNIT_TIMESTAMP) + convert_end= true; + if (vers_conditions.unit_end == UNIT_TIMESTAMP) + convert_start= true; + default: + break; + } + if (convert_start) + row_start= newx Item_func_vtq_ts( + thd, + hton, + row_start, + VTQ_COMMIT_TS); + if (convert_end) + row_end= newx Item_func_vtq_ts( + thd, + hton, + row_end, + VTQ_COMMIT_TS); } } @@ -943,7 +971,7 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, cond1= newx Item_func_eq(thd, row_end2, curr); break; case FOR_SYSTEM_TIME_AS_OF: - trx_id0= vers_conditions.unit == UNIT_TIMESTAMP ? + trx_id0= vers_conditions.unit_start == UNIT_TIMESTAMP ? newx Item_func_vtq_id(thd, hton, vers_conditions.start, VTQ_TRX_ID) : vers_conditions.start; cond1= newx Item_func_vtq_trx_sees_eq(thd, hton, trx_id0, row_start); @@ -951,24 +979,19 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, break; case FOR_SYSTEM_TIME_FROM_TO: case FOR_SYSTEM_TIME_BETWEEN: - if (vers_conditions.unit == UNIT_TIMESTAMP) - { - trx_id0= newx Item_func_vtq_id(thd, hton, vers_conditions.start, VTQ_TRX_ID, true); - trx_id1= newx Item_func_vtq_id(thd, hton, vers_conditions.end, VTQ_TRX_ID, false); - } - else - { - trx_id0= vers_conditions.start; - trx_id1= vers_conditions.end; - } - + trx_id0= vers_conditions.unit_start == UNIT_TIMESTAMP ? + newx Item_func_vtq_id(thd, hton, vers_conditions.start, VTQ_TRX_ID, true) : + vers_conditions.start; + trx_id1= vers_conditions.unit_end == UNIT_TIMESTAMP ? + newx Item_func_vtq_id(thd, hton, vers_conditions.end, VTQ_TRX_ID, false) : + vers_conditions.end; cond1= vers_conditions.type == FOR_SYSTEM_TIME_FROM_TO ? newx Item_func_vtq_trx_sees(thd, hton, trx_id1, row_start) : newx Item_func_vtq_trx_sees_eq(thd, hton, trx_id1, row_start); cond2= newx Item_func_vtq_trx_sees_eq(thd, hton, row_end, trx_id0); break; case FOR_SYSTEM_TIME_BEFORE: - trx_id0= vers_conditions.unit == UNIT_TIMESTAMP ? + trx_id0= vers_conditions.unit_start == UNIT_TIMESTAMP ? newx Item_func_vtq_id(thd, hton, vers_conditions.start, VTQ_TRX_ID) : vers_conditions.start; cond1= newx Item_func_lt(thd, row_end, trx_id0); @@ -994,12 +1017,6 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, } // if (... table->table->versioned()) } // for (table= tables; ...) - if (!slex->vers_conditions.used && slex->vers_conditions) - { - my_error(ER_VERS_UNUSED_CLAUSE, MYF(0), "SYSTEM_TIME"); - DBUG_RETURN(-1); - } - DBUG_RETURN(0); #undef newx } diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc index 4faad5b4711..b65818a2716 100644 --- a/sql/sql_truncate.cc +++ b/sql/sql_truncate.cc @@ -492,18 +492,17 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref) bool Sql_cmd_truncate_table::execute(THD *thd) { bool res= TRUE; - TABLE_LIST *first_table= thd->lex->select_lex.table_list.first; + TABLE_LIST *table= thd->lex->select_lex.table_list.first; DBUG_ENTER("Sql_cmd_truncate_table::execute"); - bool truncate_history= thd->lex->current_select->vers_conditions.type != - FOR_SYSTEM_TIME_UNSPECIFIED; - if (truncate_history) - DBUG_RETURN(mysql_delete(thd, first_table, NULL, NULL, -1, 0, NULL)); + DBUG_ASSERT(table); + if (table->vers_conditions) + DBUG_RETURN(mysql_delete(thd, table, NULL, NULL, -1, 0, NULL)); - if (check_one_table_access(thd, DROP_ACL, first_table)) + if (check_one_table_access(thd, DROP_ACL, table)) DBUG_RETURN(res); - if (! (res= truncate_table(thd, first_table))) + if (! (res= truncate_table(thd, table))) my_ok(thd); DBUG_RETURN(res); diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 46dd7570874..4626a0369fb 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -453,11 +453,15 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, goto err; } - { /* System Versioning begin */ + { /* System Versioning: fix system fields of versioned view */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat" #pragma GCC diagnostic ignored "-Wformat-extra-args" - TABLE_LIST *impli_table= NULL, *expli_table= NULL; + // Leading versioning table detected implicitly (first one selected) + TABLE_LIST *impli_table= NULL; + // Leading versioning table specified explicitly + // (i.e. if at least one system field is selected) + TABLE_LIST *expli_table= NULL; const char *impli_start, *impli_end; Item_field *expli_start= NULL, *expli_end= NULL; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 4cab239795d..c0957699602 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -863,10 +863,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %parse-param { THD *thd } %lex-param { THD *thd } /* - Currently there are 103 shift/reduce conflicts. + Currently there are 116 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 103 +%expect 116 /* Comments for TOKENS. @@ -1623,7 +1623,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); opt_constraint constraint opt_ident sp_decl_ident sp_block_label - period_for_system_time_column_id %type TEXT_STRING @@ -1972,7 +1971,7 @@ END_OF_INPUT %type opt_with_column_list -%type trans_or_timestamp +%type opt_trans_or_timestamp %type opt_for_system_time_clause %type with_or_without_system %% @@ -2510,7 +2509,7 @@ create: sequence_definition())) MYSQL_YYABORT; } - opt_sequence opt_create_table_options + opt_sequence opt_create_sequence_options { LEX *lex= thd->lex; @@ -4774,7 +4773,7 @@ create_like: opt_create_select: /* empty */ {} - | opt_duplicate opt_as create_select_query_expression + | opt_duplicate opt_as create_select_query_expression opt_versioning_option ; create_select_query_expression: @@ -5691,14 +5690,19 @@ create_or_replace: } ; -opt_create_table_options: +opt_create_sequence_options: /* empty */ | create_table_options ; -create_table_options_space_separated: - create_table_option - | create_table_option create_table_options_space_separated +opt_create_table_options: + /* empty */ + | create_table_options_versioning + ; + +alter_table_options: + create_table_option_versioning + | create_table_option_versioning alter_table_options ; create_table_options: @@ -5707,6 +5711,12 @@ create_table_options: | create_table_option ',' create_table_options ; +create_table_options_versioning: + create_table_option_versioning + | create_table_option_versioning create_table_options_versioning + | create_table_option_versioning ',' create_table_options_versioning + ; + create_table_option: ENGINE_SYM opt_equal storage_engines { @@ -5951,31 +5961,30 @@ create_table_option: Lex->create_info.used_fields|= HA_CREATE_USED_SEQUENCE; Lex->create_info.sequence= $3; } - | WITH_SYSTEM_SYM table_versioning + ; + +create_table_option_versioning: + create_table_option + | versioning_option + ; + +opt_versioning_option: + /* empty */ + | versioning_option + ; + +versioning_option: + WITH_SYSTEM_SYM VERSIONING_SYM { Lex->vers_get_info().with_system_versioning= true; Lex->create_info.options|= HA_VERSIONED_TABLE; } - | WITHOUT SYSTEM table_versioning + | WITHOUT SYSTEM VERSIONING_SYM { Lex->vers_get_info().without_system_versioning= true; } ; -table_versioning: - VERSIONING_SYM - { - Vers_parse_info &info= Lex->vers_get_info(); - if (info.with_system_versioning || info.without_system_versioning) - { - my_error_as(ER_VERS_WRONG_PARAMS, ER_MULTIPLE_CLAUSE, MYF(0), - Lex->create_last_non_select_table->table_name, - "WITH/WITHOUT SYSTEM VERSIONING"); - MYSQL_YYABORT; - } - } - ; - default_charset: opt_default charset opt_equal charset_name_or_default { @@ -6175,16 +6184,9 @@ constraint_def: period_for_system_time: // If FOR_SYM is followed by SYSTEM_TIME_SYM then they are merged to: FOR_SYSTEM_TIME_SYM . - PERIOD_SYM FOR_SYSTEM_TIME_SYM '(' period_for_system_time_column_id ',' period_for_system_time_column_id ')' + PERIOD_SYM FOR_SYSTEM_TIME_SYM '(' ident ',' ident ')' { Vers_parse_info &info= Lex->vers_get_info(); - if (!my_strcasecmp(system_charset_info, $4.str, $6.str)) - { - my_error_as(ER_VERS_WRONG_PARAMS, ER_MULTIPLE_IDENTIFIER, MYF(0), - Lex->create_last_non_select_table->table_name, $4.str, - "PERIOD FOR SYSTEM_TIME"); - MYSQL_YYABORT; - } info.set_period_for_system_time($4, $6); } ; @@ -6297,7 +6299,6 @@ field_def: LEX *lex= Lex; Vers_parse_info &info= lex->vers_get_info(); const char *field_name= lex->last_field->field_name; - const char *table_name= lex->create_last_non_select_table->table_name; LString_i *p; const char* clause; @@ -6319,12 +6320,6 @@ field_def: break; } DBUG_ASSERT(p); - if (*p) - { - my_error_as(ER_VERS_WRONG_PARAMS, ER_MULTIPLE_CLAUSE_2, MYF(0), - table_name, clause, field_name, p->ptr()); - MYSQL_YYABORT; - } *p= field_name; if (lex->last_field->implicit_not_null) { @@ -6821,13 +6816,6 @@ serial_attribute: } | with_or_without_system VERSIONING_SYM { - if (Lex->last_field->versioning != Column_definition::VERSIONING_NOT_SET) - { - my_error_as(ER_VERS_WRONG_PARAMS, ER_MULTIPLE_CLAUSE_FOR, MYF(0), - Lex->create_last_non_select_table->table_name, - "WITH/WITHOUT SYSTEM VERSIONING", Lex->last_field->field_name); - MYSQL_YYABORT; - } Lex->last_field->versioning= $1; Lex->create_info.options|= HA_VERSIONED_TABLE; } @@ -7928,7 +7916,7 @@ alter_list_item: MYSQL_YYABORT; Lex->alter_info.flags|= Alter_info::ALTER_OPTIONS; } - | create_table_options_space_separated + | alter_table_options { LEX *lex=Lex; lex->alter_info.flags|= Alter_info::ALTER_OPTIONS; @@ -8838,8 +8826,12 @@ select_options: } ; -trans_or_timestamp: - TRANSACTION_SYM +opt_trans_or_timestamp: + /* empty */ + { + $$ = UNIT_AUTO; + } + | TRANSACTION_SYM { $$ = UNIT_TRX_ID; } @@ -8855,7 +8847,22 @@ opt_system_time_clause: | SYSTEM_TIME_SYM system_time_expr { DBUG_ASSERT(Select); - Select->vers_conditions= Lex->vers_conditions; + int used= 0; + if (Lex->vers_conditions) + { + for (TABLE_LIST *table= Select->table_list.first; table; table= table->next_local) + { + if (!table->vers_conditions) + { + table->vers_conditions= Lex->vers_conditions; + used++; + } + } + if (!used) + { + my_yyabort_error((ER_VERS_UNUSED_CLAUSE, MYF(0), "SYSTEM_TIME")); + } + } } ; @@ -8871,7 +8878,7 @@ opt_for_system_time_clause: ; system_time_expr: - AS OF_SYM trans_or_timestamp simple_expr + AS OF_SYM opt_trans_or_timestamp simple_expr { Lex->vers_conditions.init(FOR_SYSTEM_TIME_AS_OF, $3, $4); } @@ -8884,42 +8891,20 @@ system_time_expr: } | ALL { - Lex->vers_conditions.init(FOR_SYSTEM_TIME_ALL, UNIT_TIMESTAMP); + Lex->vers_conditions.init(FOR_SYSTEM_TIME_ALL); } - | FROM trans_or_timestamp simple_expr - TO_SYM trans_or_timestamp simple_expr + | FROM opt_trans_or_timestamp simple_expr + TO_SYM opt_trans_or_timestamp simple_expr { - if ($2 != $5) - { - Lex->parse_error(ER_VERS_RANGE_UNITS_MISMATCH); - MYSQL_YYABORT; - } - Lex->vers_conditions.init(FOR_SYSTEM_TIME_FROM_TO, $2, $3, $6); - } - | trans_or_timestamp - FROM simple_expr - TO_SYM simple_expr - { - Lex->vers_conditions.init(FOR_SYSTEM_TIME_FROM_TO, $1, $3, $5); - } - | BETWEEN_SYM trans_or_timestamp simple_expr - AND_SYM trans_or_timestamp simple_expr - { - if ($2 != $5) - { - Lex->parse_error(ER_VERS_RANGE_UNITS_MISMATCH); - MYSQL_YYABORT; - } - Lex->vers_conditions.init(FOR_SYSTEM_TIME_BETWEEN, $2, $3, $6); + Lex->vers_conditions.init(FOR_SYSTEM_TIME_FROM_TO, $2, $3, $5, $6); } - | trans_or_timestamp - BETWEEN_SYM simple_expr - AND_SYM simple_expr + | BETWEEN_SYM opt_trans_or_timestamp simple_expr + AND_SYM opt_trans_or_timestamp simple_expr { - Lex->vers_conditions.init(FOR_SYSTEM_TIME_BETWEEN, $1, $3, $5); + Lex->vers_conditions.init(FOR_SYSTEM_TIME_BETWEEN, $2, $3, $5, $6); } | BEFORE_SYM - trans_or_timestamp + opt_trans_or_timestamp simple_expr { Lex->vers_conditions.init(FOR_SYSTEM_TIME_BEFORE, $2, $3); @@ -13047,7 +13032,6 @@ truncate: lex->select_lex.init_order(); YYPS->m_lock_type= TL_WRITE; YYPS->m_mdl_type= MDL_EXCLUSIVE; - Select->vers_conditions.empty(); } table_name opt_for_system_time_clause opt_lock_wait_timeout { @@ -13057,7 +13041,7 @@ truncate: if (lex->m_sql_cmd == NULL) MYSQL_YYABORT; if ($5) - Select->vers_conditions= Lex->vers_conditions; + Lex->last_table()->vers_conditions= Lex->vers_conditions; } ; @@ -16244,13 +16228,6 @@ column_list: | column_list_id ; -period_for_system_time_column_id: - ident - { - $$= $1; - } - ; - column_list_id: ident { diff --git a/sql/table.cc b/sql/table.cc index 2dcec49d46d..5bb8e6aa3f8 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -8423,6 +8423,24 @@ LEX_CSTRING *fk_option_name(enum_fk_option opt) return names + opt; } +void vers_select_conds_t::resolve_units(bool timestamps_only) +{ + DBUG_ASSERT(type != FOR_SYSTEM_TIME_UNSPECIFIED); + DBUG_ASSERT(start); + if (unit_start == UNIT_AUTO) + { + unit_start= (!timestamps_only && (start->result_type() == INT_RESULT || + start->result_type() == REAL_RESULT)) ? + UNIT_TRX_ID : UNIT_TIMESTAMP; + } + if (end && unit_end == UNIT_AUTO) + { + unit_end= (!timestamps_only && (end->result_type() == INT_RESULT || + end->result_type() == REAL_RESULT)) ? + UNIT_TRX_ID : UNIT_TIMESTAMP; + } +} + Field *TABLE::find_field_by_name(const char *str) const { diff --git a/sql/table.h b/sql/table.h index 8bcdb001d59..82d41ff831b 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1845,7 +1845,8 @@ class Item_in_subselect; enum vers_range_unit_t { - UNIT_TIMESTAMP = 0, + UNIT_AUTO = 0, + UNIT_TIMESTAMP, UNIT_TRX_ID }; @@ -1853,31 +1854,32 @@ enum vers_range_unit_t struct vers_select_conds_t { vers_range_type_t type; - vers_range_unit_t unit; + vers_range_unit_t unit_start, unit_end; bool import_outer:1; bool from_inner:1; - bool used:1; Item *start, *end; void empty() { type= FOR_SYSTEM_TIME_UNSPECIFIED; - unit= UNIT_TIMESTAMP; - import_outer= from_inner= used= false; + unit_start= unit_end= UNIT_AUTO; + import_outer= from_inner= false; start= end= NULL; } void init( vers_range_type_t t, - vers_range_unit_t u, + vers_range_unit_t u_start= UNIT_AUTO, Item * s= NULL, + vers_range_unit_t u_end= UNIT_AUTO, Item * e= NULL) { type= t; - unit= u; + unit_start= u_start; + unit_end= u_end; start= s; end= e; - import_outer= from_inner= used= false; + import_outer= from_inner= false; } bool init_from_sysvar(THD *thd); @@ -1894,6 +1896,7 @@ struct vers_select_conds_t { return type != FOR_SYSTEM_TIME_UNSPECIFIED; } + void resolve_units(bool timestamps_only); }; struct LEX; -- cgit v1.2.1 From 9714c4463d5867c1bd5d03086df1949f8657dfa4 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Thu, 17 Aug 2017 08:58:07 +0300 Subject: Misc: comment --- sql/log_event.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sql/log_event.cc b/sql/log_event.cc index 1bedaf152f3..2d1fc24690f 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -13023,8 +13023,13 @@ int Rows_log_event::find_row(rpl_group_info *rgi) // check whether master table is unversioned if (sys_trx_end->val_int() == 0) { + // sys_trx_start initialized with NULL when came from plain table. + // Set it notnull() because record_compare() count NULLs. table->vers_start_field()->set_notnull(); bitmap_set_bit(table->write_set, sys_trx_end->field_index); + // Plain source table may have a PRIMARY KEY. And sys_trx_end is always + // a part of PRIMARY KEY. Set it to max value for engine to find it in + // index. Needed for an UPDATE/DELETE cases. table->vers_end_field()->set_max(); m_vers_from_plain= true; } -- cgit v1.2.1 From 99baeaa951e0086e1d700c6bc6e0e153ba80c29f Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Fri, 18 Aug 2017 14:29:22 +0300 Subject: SQL: MAX microseconds for current system rows [fixes #245] --- mysql-test/suite/versioning/r/insert.result | 36 +++++++++++++------------- mysql-test/suite/versioning/r/partition.result | 2 +- mysql-test/suite/versioning/r/view.result | 8 +++--- mysql-test/suite/versioning/t/partition.test | 2 +- mysql-test/suite/versioning/t/select.test | 2 +- mysql-test/suite/versioning/t/select_sp.test | 2 +- sql/field.cc | 7 +++-- sql/item_vers.cc | 1 + sql/sql_select.cc | 7 +++-- sql/sql_table.cc | 4 +-- 10 files changed, 39 insertions(+), 32 deletions(-) diff --git a/mysql-test/suite/versioning/r/insert.result b/mysql-test/suite/versioning/r/insert.result index e6cf8954f26..f92bcdcbe19 100644 --- a/mysql-test/suite/versioning/r/insert.result +++ b/mysql-test/suite/versioning/r/insert.result @@ -194,29 +194,29 @@ drop table t2; end~~ call test_01('timestamp(6)', 'myisam', 'sys_end'); x y sys_end -3 4 2038-01-19 03:14:07.000000 -2 3 2038-01-19 03:14:07.000000 -40 33 2038-01-19 03:14:07.000000 +3 4 2038-01-19 03:14:07.999999 +2 3 2038-01-19 03:14:07.999999 +40 33 2038-01-19 03:14:07.999999 call test_01('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); x y vtq_commit_ts(sys_end) -3 4 2038-01-19 03:14:07.000000 -2 3 2038-01-19 03:14:07.000000 -40 33 2038-01-19 03:14:07.000000 +3 4 2038-01-19 03:14:07.999999 +2 3 2038-01-19 03:14:07.999999 +40 33 2038-01-19 03:14:07.999999 call test_02('timestamp(6)', 'myisam', 'sys_end'); id x y sys_end -1 33 44 2038-01-19 03:14:07.000000 -20 33 44 2038-01-19 03:14:07.000000 -40 33 44 2038-01-19 03:14:07.000000 +1 33 44 2038-01-19 03:14:07.999999 +20 33 44 2038-01-19 03:14:07.999999 +40 33 44 2038-01-19 03:14:07.999999 call test_02('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); id x y vtq_commit_ts(sys_end) -1 33 44 2038-01-19 03:14:07.000000 -20 33 44 2038-01-19 03:14:07.000000 -40 33 44 2038-01-19 03:14:07.000000 +1 33 44 2038-01-19 03:14:07.999999 +20 33 44 2038-01-19 03:14:07.999999 +40 33 44 2038-01-19 03:14:07.999999 call test_03('timestamp(6)', 'myisam', 'sys_end'); x y sys_end -8001 9001 2038-01-19 03:14:07.000000 -1001 2001 2038-01-19 03:14:07.000000 -1002 2002 2038-01-19 03:14:07.000000 +8001 9001 2038-01-19 03:14:07.999999 +1001 2001 2038-01-19 03:14:07.999999 +1002 2002 2038-01-19 03:14:07.999999 x y 8001 9001 1001 2001 @@ -225,9 +225,9 @@ drop table t1; drop view vt1_1; call test_03('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); x y vtq_commit_ts(sys_end) -8001 9001 2038-01-19 03:14:07.000000 -1001 2001 2038-01-19 03:14:07.000000 -1002 2002 2038-01-19 03:14:07.000000 +8001 9001 2038-01-19 03:14:07.999999 +1001 2001 2038-01-19 03:14:07.999999 +1002 2002 2038-01-19 03:14:07.999999 x y 8001 9001 1001 2001 diff --git a/mysql-test/suite/versioning/r/partition.result b/mysql-test/suite/versioning/r/partition.result index 89f96b7b4e4..a7c02a3f9d0 100644 --- a/mysql-test/suite/versioning/r/partition.result +++ b/mysql-test/suite/versioning/r/partition.result @@ -168,7 +168,7 @@ set @ts_start= sys_commit_ts('sys_trx_start'); set @ts_end= sys_commit_ts('sys_trx_end'); set @str= concat('select x, ', @ts_start, ' < @now as A, ', @ts_end, ' > @now as B from t1 partition (p0) for system_time all'); prepare select_p0 from @str; -set @str= concat('select x, ', @ts_start, ' > @now as C, ', @ts_end, ' = timestamp\'2038-01-19 03:14:07\' as D from t1 partition (pn) for system_time all'); +set @str= concat('select x, ', @ts_start, ' > @now as C, ', @ts_end, ' = timestamp\'2038-01-19 03:14:07.999999\' as D from t1 partition (pn) for system_time all'); prepare select_pn from @str; execute select_p0; x A B diff --git a/mysql-test/suite/versioning/r/view.result b/mysql-test/suite/versioning/r/view.result index 96ff29bd73b..22b75f5439a 100644 --- a/mysql-test/suite/versioning/r/view.result +++ b/mysql-test/suite/versioning/r/view.result @@ -85,7 +85,7 @@ x create or replace view vt1 as select * from t1; show create view vt1; View Create View character_set_client collation_connection -vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`x` AS `x`,`t1`.`sys_trx_start` AS `sys_trx_start`,`t1`.`sys_trx_end` AS `sys_trx_end` from `t1` FOR SYSTEM_TIME ALL where `t1`.`sys_trx_end` = TIMESTAMP'2038-01-19 03:14:07' latin1 latin1_swedish_ci +vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`x` AS `x`,`t1`.`sys_trx_start` AS `sys_trx_start`,`t1`.`sys_trx_end` AS `sys_trx_end` from `t1` FOR SYSTEM_TIME ALL where `t1`.`sys_trx_end` = TIMESTAMP'2038-01-19 03:14:07.999999' latin1 latin1_swedish_ci drop view vt1; drop view vt2; create view vt1 as select * from t1 for system_time all; @@ -178,15 +178,15 @@ create or replace table t3 (x int); create or replace view vt1 as select * from t1, t2, t3; show create view vt1; View Create View character_set_client collation_connection -vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`a` AS `a`,`t2`.`b` AS `b`,`t3`.`x` AS `x`,`t1`.`sys_trx_start` AS `sys_trx_start`,`t1`.`sys_trx_end` AS `sys_trx_end` from ((`t1` FOR SYSTEM_TIME ALL join `t2` FOR SYSTEM_TIME ALL) join `t3`) where `t1`.`sys_trx_end` = TIMESTAMP'2038-01-19 03:14:07' and `t2`.`sys_trx_end` = TIMESTAMP'2038-01-19 03:14:07' latin1 latin1_swedish_ci +vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`a` AS `a`,`t2`.`b` AS `b`,`t3`.`x` AS `x`,`t1`.`sys_trx_start` AS `sys_trx_start`,`t1`.`sys_trx_end` AS `sys_trx_end` from ((`t1` FOR SYSTEM_TIME ALL join `t2` FOR SYSTEM_TIME ALL) join `t3`) where `t1`.`sys_trx_end` = TIMESTAMP'2038-01-19 03:14:07.999999' and `t2`.`sys_trx_end` = TIMESTAMP'2038-01-19 03:14:07.999999' latin1 latin1_swedish_ci create or replace view vt1 as select * from t3, t2, t1; show create view vt1; View Create View character_set_client collation_connection -vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t3`.`x` AS `x`,`t2`.`b` AS `b`,`t1`.`a` AS `a`,`t2`.`sys_trx_start` AS `sys_trx_start`,`t2`.`sys_trx_end` AS `sys_trx_end` from ((`t3` join `t2` FOR SYSTEM_TIME ALL) join `t1` FOR SYSTEM_TIME ALL) where `t2`.`sys_trx_end` = TIMESTAMP'2038-01-19 03:14:07' and `t1`.`sys_trx_end` = TIMESTAMP'2038-01-19 03:14:07' latin1 latin1_swedish_ci +vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t3`.`x` AS `x`,`t2`.`b` AS `b`,`t1`.`a` AS `a`,`t2`.`sys_trx_start` AS `sys_trx_start`,`t2`.`sys_trx_end` AS `sys_trx_end` from ((`t3` join `t2` FOR SYSTEM_TIME ALL) join `t1` FOR SYSTEM_TIME ALL) where `t2`.`sys_trx_end` = TIMESTAMP'2038-01-19 03:14:07.999999' and `t1`.`sys_trx_end` = TIMESTAMP'2038-01-19 03:14:07.999999' latin1 latin1_swedish_ci create or replace view vt1 as select a, t2.sys_trx_end as endo from t3, t1, t2; show create view vt1; View Create View character_set_client collation_connection -vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`a` AS `a`,`t2`.`sys_trx_end` AS `endo`,`t2`.`sys_trx_start` AS `sys_trx_start` from ((`t3` join `t1` FOR SYSTEM_TIME ALL) join `t2` FOR SYSTEM_TIME ALL) where `t1`.`sys_trx_end` = TIMESTAMP'2038-01-19 03:14:07' and `t2`.`sys_trx_end` = TIMESTAMP'2038-01-19 03:14:07' latin1 latin1_swedish_ci +vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`a` AS `a`,`t2`.`sys_trx_end` AS `endo`,`t2`.`sys_trx_start` AS `sys_trx_start` from ((`t3` join `t1` FOR SYSTEM_TIME ALL) join `t2` FOR SYSTEM_TIME ALL) where `t1`.`sys_trx_end` = TIMESTAMP'2038-01-19 03:14:07.999999' and `t2`.`sys_trx_end` = TIMESTAMP'2038-01-19 03:14:07.999999' latin1 latin1_swedish_ci create or replace view vvt1 as select * from t1, t2, vt1; ERROR HY000: Creating VIEW `vvt1` is prohibited: versioned VIEW `vt1` in query! drop view vt1, vt12; diff --git a/mysql-test/suite/versioning/t/partition.test b/mysql-test/suite/versioning/t/partition.test index d5a9643de9a..5c97b468a1a 100644 --- a/mysql-test/suite/versioning/t/partition.test +++ b/mysql-test/suite/versioning/t/partition.test @@ -102,7 +102,7 @@ set @ts_start= sys_commit_ts('sys_trx_start'); set @ts_end= sys_commit_ts('sys_trx_end'); set @str= concat('select x, ', @ts_start, ' < @now as A, ', @ts_end, ' > @now as B from t1 partition (p0) for system_time all'); prepare select_p0 from @str; -set @str= concat('select x, ', @ts_start, ' > @now as C, ', @ts_end, ' = timestamp\'2038-01-19 03:14:07\' as D from t1 partition (pn) for system_time all'); +set @str= concat('select x, ', @ts_start, ' > @now as C, ', @ts_end, ' = timestamp\'2038-01-19 03:14:07.999999\' as D from t1 partition (pn) for system_time all'); prepare select_pn from @str; execute select_p0; diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index 345e28f610c..6ec45db6c08 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -137,7 +137,7 @@ insert into t1 values (1); create trigger read_end after update on t1 for each row set @end = old.sys_trx_end; update t1 set a=2; ---replace_result 18446744073709551615 MAX_RESULT "2038-01-19 03:14:07.000000" MAX_RESULT +--replace_result 18446744073709551615 MAX_RESULT "2038-01-19 03:14:07.999999" MAX_RESULT select @end; create or replace table t1 (a int) with system versioning; diff --git a/mysql-test/suite/versioning/t/select_sp.test b/mysql-test/suite/versioning/t/select_sp.test index d261e1bc537..bd165c3bd16 100644 --- a/mysql-test/suite/versioning/t/select_sp.test +++ b/mysql-test/suite/versioning/t/select_sp.test @@ -150,7 +150,7 @@ insert into t1 values (1); create trigger read_end after update on t1 for each row set @end = old.sys_trx_end; update t1 set a=2; ---replace_result 18446744073709551615 MAX_RESULT "2038-01-19 03:14:07.000000" MAX_RESULT +--replace_result 18446744073709551615 MAX_RESULT "2038-01-19 03:14:07.999999" MAX_RESULT select @end; create or replace table t1 (a int) with system versioning; diff --git a/sql/field.cc b/sql/field.cc index cd83e61ba43..9afe74f0808 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -2012,6 +2012,7 @@ bool Field_vers_system::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate, ulonglo if (trx_id == ULONGLONG_MAX) { get_thd()->variables.time_zone->gmt_sec_to_TIME(ltime, TIMESTAMP_MAX_VALUE); + ltime->second_part= TIME_MAX_SECOND_PART; return false; } if (cached == trx_id) @@ -5481,10 +5482,11 @@ void Field_timestampf::set_max() { DBUG_ENTER("Field_timestampf::set_max"); ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + DBUG_ASSERT(dec == TIME_SECOND_PART_DIGITS); set_notnull(); mi_int4store(ptr, TIMESTAMP_MAX_VALUE); - memset(ptr + 4, 0x0, value_length() - 4); + mi_int3store(ptr + 4, TIME_MAX_SECOND_PART); DBUG_VOID_RETURN; } @@ -5494,7 +5496,8 @@ bool Field_timestampf::is_max() DBUG_ENTER("Field_timestampf::is_max"); ASSERT_COLUMN_MARKED_FOR_READ; - DBUG_RETURN(mi_sint4korr(ptr) == 0x7fffffff); + DBUG_RETURN(mi_sint4korr(ptr) == TIMESTAMP_MAX_VALUE && + mi_sint3korr(ptr + 4) == TIME_MAX_SECOND_PART); } my_time_t Field_timestampf::get_timestamp(const uchar *pos, diff --git a/sql/item_vers.cc b/sql/item_vers.cc index 47e62d9ebf0..cbeb72810f3 100644 --- a/sql/item_vers.cc +++ b/sql/item_vers.cc @@ -67,6 +67,7 @@ Item_func_vtq_ts::get_date(MYSQL_TIME *res, ulonglong fuzzy_date) { null_value= false; thd->variables.time_zone->gmt_sec_to_TIME(res, TIMESTAMP_MAX_VALUE); + res->second_part= TIME_MAX_SECOND_PART; return false; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 437c04c2984..68fb90ae9ec 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -676,7 +676,8 @@ bool vers_select_conds_t::init_from_sysvar(THD *thd) if (type != FOR_SYSTEM_TIME_UNSPECIFIED && type != FOR_SYSTEM_TIME_ALL) { DBUG_ASSERT(type == FOR_SYSTEM_TIME_AS_OF); - start= new (thd->mem_root) Item_datetime_literal(thd, &in.ltime, 6); + start= new (thd->mem_root) + Item_datetime_literal(thd, &in.ltime, TIME_SECOND_PART_DIGITS); if (!start) return true; } @@ -921,7 +922,9 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, { MYSQL_TIME max_time; thd->variables.time_zone->gmt_sec_to_TIME(&max_time, TIMESTAMP_MAX_VALUE); - curr= newx Item_datetime_literal(thd, &max_time); + max_time.second_part= TIME_MAX_SECOND_PART; + curr= newx Item_datetime_literal(thd, &max_time, + TIME_SECOND_PART_DIGITS); cond1= newx Item_func_eq(thd, row_end, curr); } else diff --git a/sql/sql_table.cc b/sql/sql_table.cc index cb4bb052a65..abf337c9fa6 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -10017,8 +10017,8 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, // TODO: write directly to record bypassing the same checks on every call to_sys_trx_start->store_time(&query_start); - static const timeval max_tv= {0x7fffffff, 0}; - static const uint dec= 6; + static const timeval max_tv= {TIMESTAMP_MAX_VALUE, TIME_MAX_SECOND_PART}; + static const uint dec= TIME_SECOND_PART_DIGITS; to_sys_trx_end->set_notnull(to_sys_trx_end->null_offset()); my_timestamp_to_binary(&max_tv, to_sys_trx_end->ptr, dec); } -- cgit v1.2.1 From b4cd2d3c12f5085a31fa91757c14f7f411112d50 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Fri, 18 Aug 2017 15:30:55 +0300 Subject: Tests: duplicate system versioning field --- mysql-test/suite/versioning/r/create.result | 6 ++++++ mysql-test/suite/versioning/t/create.test | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/mysql-test/suite/versioning/r/create.result b/mysql-test/suite/versioning/r/create.result index b71e84ccc08..f5d1566a785 100644 --- a/mysql-test/suite/versioning/r/create.result +++ b/mysql-test/suite/versioning/r/create.result @@ -353,5 +353,11 @@ create or replace table t1 (a int, id int) with system versioning engine INNODB_ create or replace table t2 (b int, id int); create or replace table t3 as select t2.b, t1.a, t1.sys_trx_start, t1.sys_trx_end from t2 inner join t1 on t2.id=t1.id; +create or replace table t (sys_trx_start int); +alter table t with system versioning; +ERROR 42S21: Duplicate column name 'sys_trx_start' +create or replace table t (sys_trx_end int); +alter table t with system versioning; +ERROR 42S21: Duplicate column name 'sys_trx_end' drop database test; create database test; diff --git a/mysql-test/suite/versioning/t/create.test b/mysql-test/suite/versioning/t/create.test index 9de6a5157b3..815030255df 100644 --- a/mysql-test/suite/versioning/t/create.test +++ b/mysql-test/suite/versioning/t/create.test @@ -283,5 +283,13 @@ create or replace table t2 (b int, id int); create or replace table t3 as select t2.b, t1.a, t1.sys_trx_start, t1.sys_trx_end from t2 inner join t1 on t2.id=t1.id; +create or replace table t (sys_trx_start int); +--error ER_DUP_FIELDNAME +alter table t with system versioning; + +create or replace table t (sys_trx_end int); +--error ER_DUP_FIELDNAME +alter table t with system versioning; + drop database test; create database test; -- cgit v1.2.1 From ccddb4f7663769fa686be0aaa1cd3bd70d2196fa Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Fri, 18 Aug 2017 21:06:02 +0300 Subject: Misc: simplify code --- sql/sql_table.cc | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index abf337c9fa6..1da16fc289c 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -10013,14 +10013,9 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, if (make_versioned) { - to_sys_trx_start->set_notnull(to_sys_trx_start->null_offset()); - // TODO: write directly to record bypassing the same checks on every call + to_sys_trx_start->set_notnull(); to_sys_trx_start->store_time(&query_start); - - static const timeval max_tv= {TIMESTAMP_MAX_VALUE, TIME_MAX_SECOND_PART}; - static const uint dec= TIME_SECOND_PART_DIGITS; - to_sys_trx_end->set_notnull(to_sys_trx_end->null_offset()); - my_timestamp_to_binary(&max_tv, to_sys_trx_end->ptr, dec); + to_sys_trx_end->set_max(); } else if (make_unversioned) { -- cgit v1.2.1 From b231a85200b0bfe20d033e070cd2f189f4ecf9fd Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Wed, 30 Aug 2017 11:14:03 +0300 Subject: Plugins: lost terminator in versioning plugin [fixes #248] --- plugin/versioning/versioning.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugin/versioning/versioning.cc b/plugin/versioning/versioning.cc index fb8a8b8ee32..5cd6f829ec1 100644 --- a/plugin/versioning/versioning.cc +++ b/plugin/versioning/versioning.cc @@ -149,7 +149,8 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("VTQ_ISO_LEVEL") }, BUILDER(Create_func_vtq)}, { { C_STRING_WITH_LEN("VTQ_TRX_ID") }, BUILDER(Create_func_vtq)}, { { C_STRING_WITH_LEN("VTQ_TRX_SEES") }, BUILDER(Create_func_vtq_trx_sees)}, - { { C_STRING_WITH_LEN("VTQ_TRX_SEES_EQ") }, BUILDER(Create_func_vtq_trx_sees)} + { { C_STRING_WITH_LEN("VTQ_TRX_SEES_EQ") }, BUILDER(Create_func_vtq_trx_sees)}, + { {0, 0}, NULL} }; -- cgit v1.2.1 From a6aaa4fefeaa515f0d13b426d1d3cb807a56bf59 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Wed, 30 Aug 2017 15:28:43 +0300 Subject: SQL: move Vers_extended_item::vtq_cached_result() to Item [closes #250] --- sql/item.h | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/sql/item.h b/sql/item.h index 130ad688593..f73b09e2d25 100644 --- a/sql/item.h +++ b/sql/item.h @@ -480,20 +480,8 @@ public: String_copier_for_item(THD *thd): m_thd(thd) { } }; -/* System versioning */ -class Vers_extended_item -{ -public: - virtual vtq_record_t* vtq_cached_result() - { - return NULL; - } -}; - - class Item: public Value_source, - public Type_std_attributes, - public Vers_extended_item + public Type_std_attributes { void operator=(Item &); /** @@ -1845,8 +1833,10 @@ public: { marker &= ~EXTRACTION_MASK; } -}; + /* System versioning */ + virtual vtq_record_t *vtq_cached_result() { return NULL; } +}; template inline Item* get_item_copy (THD *thd, MEM_ROOT *mem_root, T* item) -- cgit v1.2.1 From c2a70c8050125f219b1942a800aa4c134cc8520d Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Fri, 1 Sep 2017 12:41:46 +0300 Subject: SQL, IB: option to drop historical rows on ALTER [closes #249] --- mysql-test/suite/versioning/r/alter.result | 26 +++++++++++++++++++ mysql-test/suite/versioning/r/ddl.result | 16 ++++++------ mysql-test/suite/versioning/r/vtmd.result | 24 ++++++++--------- mysql-test/suite/versioning/r/vtmd_show.result | 2 +- mysql-test/suite/versioning/t/alter.test | 16 ++++++++++++ mysql-test/suite/versioning/t/ddl.test | 16 ++++++------ mysql-test/suite/versioning/t/vtmd.test | 24 ++++++++--------- mysql-test/suite/versioning/t/vtmd_show.test | 2 +- scripts/mysql_system_tables.sql | 2 +- sql/handler.h | 2 ++ sql/mysqld.h | 7 +++++ sql/sql_class.h | 2 +- sql/sql_rename.cc | 4 +-- sql/sql_table.cc | 36 +++++++++++++++++++------- sql/sql_yacc.yy | 6 +++++ sql/sys_vars.cc | 9 ++++--- storage/innobase/handler/handler0alter.cc | 3 ++- storage/innobase/include/row0merge.h | 3 ++- storage/innobase/row/row0merge.cc | 20 ++++++++------ 19 files changed, 151 insertions(+), 69 deletions(-) diff --git a/mysql-test/suite/versioning/r/alter.result b/mysql-test/suite/versioning/r/alter.result index 14cb242d09e..ccf6a31f39f 100644 --- a/mysql-test/suite/versioning/r/alter.result +++ b/mysql-test/suite/versioning/r/alter.result @@ -533,6 +533,29 @@ Table Create Table t CREATE TABLE `t` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 +set versioning_alter_history = DROP; +create or replace table t (a int) with system versioning engine innodb; +insert into t values (1); +update t set a = 2; +select * from t for system_time all; +a +2 +1 +alter table t add column b int; +select * from t for system_time all; +a b +2 NULL +create or replace table t (a int) with system versioning engine myisam; +insert into t values (1); +update t set a = 2; +select * from t for system_time all; +a +2 +1 +alter table t add column b int; +select * from t for system_time all; +a b +2 NULL call verify_vtq; No A B C D 1 1 1 1 1 @@ -546,6 +569,9 @@ No A B C D 9 1 1 1 1 10 1 1 1 1 11 1 1 1 1 +12 1 1 1 1 +13 1 1 1 1 +14 1 1 1 1 drop table t; drop procedure verify_vtq; drop procedure innodb_verify_vtq; diff --git a/mysql-test/suite/versioning/r/ddl.result b/mysql-test/suite/versioning/r/ddl.result index 23e8c6d6dc5..931697aeb47 100644 --- a/mysql-test/suite/versioning/r/ddl.result +++ b/mysql-test/suite/versioning/r/ddl.result @@ -82,7 +82,7 @@ create procedure drop_last_historical(table_name_arg varchar(255)) begin call concat_exec2('drop table ', get_historical_table_name(table_name_arg)); end~~ -set versioning_ddl_survival= on; +set versioning_alter_history= survive; create or replace table t (a int) with system versioning; insert into t values (1); update t set a=2 where a=1; @@ -106,10 +106,10 @@ call concat_exec3('select @tm=sys_trx_end from ', get_historical_table_name('t') @tm=sys_trx_end 1 call drop_last_historical('t'); -set versioning_ddl_survival= off; +set versioning_alter_history= keep; drop table t_vtmd; drop table t; -set versioning_ddl_survival= on; +set versioning_alter_history= survive; create or replace table t (a int) with system versioning; insert into t values (1); update t set a=2 where a=1; @@ -133,10 +133,10 @@ call concat_exec3('select @tm=sys_trx_end from ', get_historical_table_name('t') @tm=sys_trx_end 1 call drop_last_historical('t'); -set versioning_ddl_survival= off; +set versioning_alter_history= keep; drop table t_vtmd; drop table t; -set versioning_ddl_survival= on; +set versioning_alter_history= survive; create or replace table t (a int) with system versioning engine innodb; insert into t values (1); update t set a=2 where a=1; @@ -160,15 +160,15 @@ call concat_exec3('select @tm=sys_trx_end from ', get_historical_table_name('t') @tm=sys_trx_end 1 call drop_last_historical('t'); -set versioning_ddl_survival= off; +set versioning_alter_history= keep; drop table t_vtmd; drop table t; -set versioning_ddl_survival= on; +set versioning_alter_history= survive; create or replace table t (a int) with system versioning engine innodb; insert into t values (1); update t set a=2 where a=1; alter table t add column b int, algorithm=inplace; -set versioning_ddl_survival = 0; +set versioning_alter_history = keep; drop procedure concat_exec2; drop procedure concat_exec3; drop function get_historical_table_name; diff --git a/mysql-test/suite/versioning/r/vtmd.result b/mysql-test/suite/versioning/r/vtmd.result index 264795c668e..910a937e9c5 100644 --- a/mysql-test/suite/versioning/r/vtmd.result +++ b/mysql-test/suite/versioning/r/vtmd.result @@ -44,12 +44,12 @@ substr(archive_name, 1, instr(archive_name, '_')) as C_archive_name from tmp_vtmd for system_time all; drop table tmp_vtmd; end~~ -set versioning_ddl_survival= off; +set versioning_alter_history= keep; create or replace table t0 (x int) with system versioning; show tables; Tables_in_test t0 -set versioning_ddl_survival= on; +set versioning_alter_history= survive; create or replace table t0 (x int) with system versioning; show tables; Tables_in_test @@ -72,9 +72,9 @@ call check_vtmd('t0_vtmd'); 1 A_start B_end name C_archive_name 1 1 t0 NULL -set versioning_ddl_survival= off; +set versioning_alter_history= keep; drop table t0; -set versioning_ddl_survival= on; +set versioning_alter_history= survive; create or replace table t0 (x int) with system versioning; ERROR HY000: VTMD error: `test.t0_vtmd` exists and not empty! alter table t0 add column (y int); @@ -93,19 +93,19 @@ call check_vtmd('t0_vtmd'); A_start B_end name C_archive_name 1 1 t0 t0_ call drop_archives('t0_vtmd'); -set versioning_ddl_survival= off; +set versioning_alter_history= keep; drop tables t0, t0_vtmd; -set versioning_ddl_survival= on; -set versioning_ddl_survival= off; +set versioning_alter_history= survive; +set versioning_alter_history= keep; create or replace table x0 (x int) with system versioning; -set versioning_ddl_survival= on; +set versioning_alter_history= survive; rename table x0 to d0; show tables; Tables_in_test d0 -set versioning_ddl_survival= off; +set versioning_alter_history= keep; drop table d0; -set versioning_ddl_survival= on; +set versioning_alter_history= survive; create or replace table x0 (x int) with system versioning; rename table x0 to d0; show tables; @@ -118,9 +118,9 @@ call check_vtmd('d0_vtmd'); A_start B_end name C_archive_name 1 0 x0 NULL 1 1 d0 NULL -set versioning_ddl_survival= off; +set versioning_alter_history= keep; drop table d0; -set versioning_ddl_survival= on; +set versioning_alter_history= survive; create or replace table x0 (x int) with system versioning; rename table x0 to d0; ERROR HY000: VTMD error: `test.d0_vtmd` table already exists! diff --git a/mysql-test/suite/versioning/r/vtmd_show.result b/mysql-test/suite/versioning/r/vtmd_show.result index 5bc735f0a72..b7409793677 100644 --- a/mysql-test/suite/versioning/r/vtmd_show.result +++ b/mysql-test/suite/versioning/r/vtmd_show.result @@ -52,7 +52,7 @@ end~~ create table t (a int) with system versioning; show create table t for system_time as of now; ERROR 42S02: Table 'test.t_vtmd' doesn't exist -set versioning_ddl_survival=on; +set versioning_alter_history=survive; create or replace table t (a int) with system versioning; show create table t for system_time between timestamp @tm1 and timestamp @tm1; ERROR HY000: SYSTEM_TIME range selector is prohibited diff --git a/mysql-test/suite/versioning/t/alter.test b/mysql-test/suite/versioning/t/alter.test index 6ceac987a5e..7020439d86e 100644 --- a/mysql-test/suite/versioning/t/alter.test +++ b/mysql-test/suite/versioning/t/alter.test @@ -257,6 +257,22 @@ select * from t; alter table t without system versioning; show create table t; +set versioning_alter_history = DROP; + +create or replace table t (a int) with system versioning engine innodb; +insert into t values (1); +update t set a = 2; +select * from t for system_time all; +alter table t add column b int; +select * from t for system_time all; + +create or replace table t (a int) with system versioning engine myisam; +insert into t values (1); +update t set a = 2; +select * from t for system_time all; +alter table t add column b int; +select * from t for system_time all; + call verify_vtq; drop table t; diff --git a/mysql-test/suite/versioning/t/ddl.test b/mysql-test/suite/versioning/t/ddl.test index 9ef77e9ca0b..ec014af4168 100644 --- a/mysql-test/suite/versioning/t/ddl.test +++ b/mysql-test/suite/versioning/t/ddl.test @@ -30,7 +30,7 @@ end~~ delimiter ;~~ -set versioning_ddl_survival= on; +set versioning_alter_history= survive; create or replace table t (a int) with system versioning; insert into t values (1); @@ -49,10 +49,10 @@ call concat_exec3('select @tm=sys_trx_end from ', get_historical_table_name('t') call drop_last_historical('t'); -set versioning_ddl_survival= off; +set versioning_alter_history= keep; drop table t_vtmd; drop table t; -set versioning_ddl_survival= on; +set versioning_alter_history= survive; # same for INNODB ALGORITHM=COPY create or replace table t (a int) with system versioning; @@ -72,10 +72,10 @@ call concat_exec3('select @tm=sys_trx_end from ', get_historical_table_name('t') call drop_last_historical('t'); -set versioning_ddl_survival= off; +set versioning_alter_history= keep; drop table t_vtmd; drop table t; -set versioning_ddl_survival= on; +set versioning_alter_history= survive; # same for INNODB default ALGORITHM create or replace table t (a int) with system versioning engine innodb; @@ -95,10 +95,10 @@ call concat_exec3('select @tm=sys_trx_end from ', get_historical_table_name('t') call drop_last_historical('t'); -set versioning_ddl_survival= off; +set versioning_alter_history= keep; drop table t_vtmd; drop table t; -set versioning_ddl_survival= on; +set versioning_alter_history= survive; # no DDL for INNODB explicit ALGORITHM=INPLACE create or replace table t (a int) with system versioning engine innodb; @@ -106,7 +106,7 @@ insert into t values (1); update t set a=2 where a=1; alter table t add column b int, algorithm=inplace; -set versioning_ddl_survival = 0; +set versioning_alter_history = keep; drop procedure concat_exec2; drop procedure concat_exec3; diff --git a/mysql-test/suite/versioning/t/vtmd.test b/mysql-test/suite/versioning/t/vtmd.test index 5d6b09a56e0..2826c6fd2ff 100644 --- a/mysql-test/suite/versioning/t/vtmd.test +++ b/mysql-test/suite/versioning/t/vtmd.test @@ -57,18 +57,18 @@ end~~ delimiter ;~~ # create -set versioning_ddl_survival= off; +set versioning_alter_history= keep; create or replace table t0 (x int) with system versioning; show tables; -set versioning_ddl_survival= on; +set versioning_alter_history= survive; create or replace table t0 (x int) with system versioning; show tables; show create table t0_vtmd; call check_vtmd('t0_vtmd'); -set versioning_ddl_survival= off; +set versioning_alter_history= keep; drop table t0; -set versioning_ddl_survival= on; +set versioning_alter_history= survive; --error ER_VERS_VTMD_ERROR create or replace table t0 (x int) with system versioning; @@ -82,28 +82,28 @@ alter table t0 drop column y; call check_vtmd('t0_vtmd'); call drop_archives('t0_vtmd'); -set versioning_ddl_survival= off; +set versioning_alter_history= keep; drop tables t0, t0_vtmd; -set versioning_ddl_survival= on; +set versioning_alter_history= survive; # rename -set versioning_ddl_survival= off; +set versioning_alter_history= keep; create or replace table x0 (x int) with system versioning; -set versioning_ddl_survival= on; +set versioning_alter_history= survive; rename table x0 to d0; show tables; -set versioning_ddl_survival= off; +set versioning_alter_history= keep; drop table d0; -set versioning_ddl_survival= on; +set versioning_alter_history= survive; create or replace table x0 (x int) with system versioning; rename table x0 to d0; show tables; call check_vtmd('d0_vtmd'); -set versioning_ddl_survival= off; +set versioning_alter_history= keep; drop table d0; -set versioning_ddl_survival= on; +set versioning_alter_history= survive; create or replace table x0 (x int) with system versioning; --error ER_VERS_VTMD_ERROR diff --git a/mysql-test/suite/versioning/t/vtmd_show.test b/mysql-test/suite/versioning/t/vtmd_show.test index 036c233bd9e..24125d2b76b 100644 --- a/mysql-test/suite/versioning/t/vtmd_show.test +++ b/mysql-test/suite/versioning/t/vtmd_show.test @@ -68,7 +68,7 @@ create table t (a int) with system versioning; --error ER_NO_SUCH_TABLE show create table t for system_time as of now; -set versioning_ddl_survival=on; +set versioning_alter_history=survive; create or replace table t (a int) with system versioning; --error ER_VERS_RANGE_PROHIBITED diff --git a/scripts/mysql_system_tables.sql b/scripts/mysql_system_tables.sql index 28ca9292602..539b26cd176 100644 --- a/scripts/mysql_system_tables.sql +++ b/scripts/mysql_system_tables.sql @@ -23,7 +23,7 @@ set sql_mode=''; set @orig_storage_engine=@@storage_engine; set storage_engine=myisam; -set versioning_ddl_survival=off; +set versioning_alter_history=keep; set @have_innodb= (select count(engine) from information_schema.engines where engine='INNODB' and support != 'NO'); SET @innodb_or_myisam=IF(@have_innodb <> 0, 'InnoDB', 'MyISAM'); diff --git a/sql/handler.h b/sql/handler.h index 24d1a73ec92..2ab9ed48c8f 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -2119,6 +2119,8 @@ public: static const HA_ALTER_FLAGS ALTER_DROP_CHECK_CONSTRAINT= 1ULL << 40; + static const HA_ALTER_FLAGS ALTER_DROP_HISTORICAL = 1ULL << 41; + /** Create options (like MAX_ROWS) for the new version of table. diff --git a/sql/mysqld.h b/sql/mysqld.h index 5ca5570460e..a30612067ba 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -208,6 +208,13 @@ enum vers_hide_enum VERS_HIDE_FULL, VERS_HIDE_NEVER }; + +enum vers_alter_history_enum +{ + VERS_ALTER_HISTORY_KEEP, + VERS_ALTER_HISTORY_SURVIVE, + VERS_ALTER_HISTORY_DROP +}; /* System Versioning end */ extern char *mysql_home_ptr, *pidfile_name_ptr; diff --git a/sql/sql_class.h b/sql/sql_class.h index 0c7179e5569..fb0cb3f7b0d 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -711,7 +711,7 @@ typedef struct system_variables my_bool vers_force; ulong vers_hide; my_bool vers_innodb_algorithm_simple; - my_bool vers_ddl_survival; + ulong vers_alter_history; } SV; /** diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index 9b80ef78c63..631c7664994 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -300,7 +300,7 @@ do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db, char *new_table_name, (void) rename_table_in_stat_tables(thd, &db_name, &table_name, &new_db_name, &new_table); VTMD_rename vtmd(*ren_table); - if (thd->variables.vers_ddl_survival) + if (thd->variables.vers_alter_history == VERS_ALTER_HISTORY_SURVIVE) { rc= vtmd.try_rename(thd, new_db_name, new_table); if (rc) @@ -313,7 +313,7 @@ do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db, char *new_table_name, new_alias); if (rc) { - if (thd->variables.vers_ddl_survival) + if (thd->variables.vers_alter_history == VERS_ALTER_HISTORY_SURVIVE) vtmd.revert_rename(thd, new_db_name); revert_table_name: /* diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 1da16fc289c..1831eecbd26 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2477,8 +2477,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, *(end= path + path_length - reg_ext_length)= '\0'; if (thd->lex->sql_command == SQLCOM_DROP_TABLE && - thd->variables.vers_ddl_survival && - table_type && table_type != view_pseudo_hton) + thd->variables.vers_alter_history == VERS_ALTER_HISTORY_SURVIVE && + table_type && table_type != view_pseudo_hton) { error= vtmd.check_exists(thd); if (error) @@ -5075,7 +5075,8 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, } } - if (create_info->versioned() && thd->variables.vers_ddl_survival) + if (create_info->versioned() && + thd->variables.vers_alter_history == VERS_ALTER_HISTORY_SURVIVE) { VTMD_table vtmd(*create_table); if (vtmd.update(thd)) @@ -6372,6 +6373,8 @@ static bool fill_alter_inplace_info(THD *thd, ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_ADD_CHECK_CONSTRAINT; if (alter_info->flags & Alter_info::ALTER_DROP_CHECK_CONSTRAINT) ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_DROP_CHECK_CONSTRAINT; + if (thd->variables.vers_alter_history == VERS_ALTER_HISTORY_DROP) + ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_DROP_HISTORICAL; /* If we altering table with old VARCHAR fields we will be automatically @@ -8561,8 +8564,11 @@ simple_rename_or_index_change(THD *thd, TABLE_LIST *table_list, else { VTMD_rename vtmd(*table_list); - if (thd->variables.vers_ddl_survival && vtmd.try_rename(thd, new_db_name, new_table_name)) + if (thd->variables.vers_alter_history == VERS_ALTER_HISTORY_SURVIVE && + vtmd.try_rename(thd, new_db_name, new_table_name)) + { goto revert_table_name; + } else if (Table_triggers_list::change_table_name(thd, alter_ctx->db, alter_ctx->alias, @@ -8570,7 +8576,7 @@ simple_rename_or_index_change(THD *thd, TABLE_LIST *table_list, alter_ctx->new_db, alter_ctx->new_alias)) { - if (thd->variables.vers_ddl_survival) + if (thd->variables.vers_alter_history == VERS_ALTER_HISTORY_SURVIVE) vtmd.revert_rename(thd, new_db_name); revert_table_name: (void) mysql_rename_table(old_db_type, @@ -8711,7 +8717,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, thd->open_options&= ~HA_OPEN_FOR_ALTER; bool versioned= table_list->table && table_list->table->versioned(); bool vers_data_mod= versioned && - thd->variables.vers_ddl_survival && + thd->variables.vers_alter_history == VERS_ALTER_HISTORY_SURVIVE && alter_info->vers_data_modifying(); if (vers_data_mod) @@ -9949,11 +9955,14 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, else if (keep_versioned) { to->file->vers_auto_decrement= 0xffffffffffffffff; - if (thd->variables.vers_ddl_survival) + if (thd->variables.vers_alter_history == VERS_ALTER_HISTORY_SURVIVE) { query_start= thd->query_start_TIME(); from_sys_trx_end= from->vers_end_field(); to_sys_trx_start= to->vers_start_field(); + } else if (thd->variables.vers_alter_history == VERS_ALTER_HISTORY_DROP) + { + from_sys_trx_end= from->vers_end_field(); } } @@ -10011,6 +10020,12 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, copy_ptr->do_copy(copy_ptr); } + if (thd->variables.vers_alter_history == VERS_ALTER_HISTORY_DROP && + from_sys_trx_end && !from_sys_trx_end->is_max()) + { + continue; + } + if (make_versioned) { to_sys_trx_start->set_notnull(); @@ -10022,7 +10037,8 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, if (!from_sys_trx_end->is_max()) continue; // Drop history rows. } - else if (keep_versioned && thd->variables.vers_ddl_survival) + else if (keep_versioned && + thd->variables.vers_alter_history == VERS_ALTER_HISTORY_SURVIVE) { if (!from_sys_trx_end->is_max()) continue; // Do not copy history rows. @@ -10048,13 +10064,13 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, break; } if (keep_versioned && to->versioned_by_engine() && - !thd->variables.vers_ddl_survival) + thd->variables.vers_alter_history != VERS_ALTER_HISTORY_SURVIVE) { to->s->versioned= false; } error= to->file->ha_write_row(to->record[0]); if (keep_versioned && to->versioned_by_engine() && - !thd->variables.vers_ddl_survival) + thd->variables.vers_alter_history != VERS_ALTER_HISTORY_SURVIVE) { to->s->versioned= true; } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c0957699602..20674ef5d27 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -15660,6 +15660,12 @@ set_expr_or_default: if ($$ == NULL) MYSQL_YYABORT; } + | DROP + { + $$=new (thd->mem_root) Item_string_sys(thd, "DROP", 4); + if ($$ == NULL) + MYSQL_YYABORT; + } ; /* Lock function */ diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index c618a4f4bc2..25437f7b3b4 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -406,9 +406,12 @@ static Sys_var_mybool Sys_vers_innodb_algorithm_simple( SESSION_VAR(vers_innodb_algorithm_simple), CMD_LINE(OPT_ARG), DEFAULT(TRUE)); -static Sys_var_mybool Sys_vers_ddl_survival( - "versioning_ddl_survival", "Use system versioning DDL survival feature", - SESSION_VAR(vers_ddl_survival), CMD_LINE(OPT_ARG), DEFAULT(FALSE)); +static const char *vers_alter_history_keywords[]= {"KEEP", "SURVIVE", "DROP", + NULL}; +static Sys_var_enum Sys_vers_alter_history( + "versioning_alter_history", "Versioning ALTER TABLE mode", + SESSION_VAR(vers_alter_history), CMD_LINE(OPT_ARG), + vers_alter_history_keywords, DEFAULT(VERS_ALTER_HISTORY_KEEP)); static Sys_var_ulonglong Sys_binlog_cache_size( "binlog_cache_size", "The size of the transactional cache for " diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index a2af99f2369..7b99f499850 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -6450,7 +6450,8 @@ ok_exit: ctx->add_index, ctx->add_key_numbers, ctx->num_to_add_index, altered_table, ctx->add_cols, ctx->col_map, ctx->add_autoinc, ctx->sequence, ctx->skip_pk_sort, - ctx->m_stage, add_v, eval_table); + ctx->m_stage, add_v, eval_table, + ha_alter_info->handler_flags & Alter_inplace_info::ALTER_DROP_HISTORICAL); if (s_templ) { ut_ad(ctx->need_rebuild() || ctx->num_to_add_vcol > 0 diff --git a/storage/innobase/include/row0merge.h b/storage/innobase/include/row0merge.h index 1b61c475c6f..0a7a2cc8c78 100644 --- a/storage/innobase/include/row0merge.h +++ b/storage/innobase/include/row0merge.h @@ -349,7 +349,8 @@ row_merge_build_indexes( bool skip_pk_sort, ut_stage_alter_t* stage, const dict_add_v_col_t* add_v, - struct TABLE* eval_table) + struct TABLE* eval_table, + bool drop_historical) MY_ATTRIBUTE((warn_unused_result)); /********************************************************************//** diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index 5f2ca6838e2..c7a740a0c1d 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -1797,7 +1797,8 @@ row_merge_read_clustered_index( double pct_cost, fil_space_crypt_t* crypt_data, row_merge_block_t* crypt_block, - struct TABLE* eval_table) + struct TABLE* eval_table, + bool drop_historical) { dict_index_t* clust_index; /* Clustered index */ @@ -2237,7 +2238,7 @@ end_of_index: ut_ad(add_autoinc < dict_table_get_n_user_cols(new_table)); - bool row_is_historic = false; + bool historical_row = false; if (DICT_TF2_FLAG_IS_SET( new_table, DICT_TF2_VERSIONED)) { const dfield_t *dfield = dtuple_get_nth_field( @@ -2245,7 +2246,7 @@ end_of_index: const byte *data = static_cast( dfield_get_data(dfield)); ut_ad(dfield_get_len(dfield) == 8); - row_is_historic = + historical_row = mach_read_from_8(data) != TRX_ID_MAX; } @@ -2270,7 +2271,7 @@ end_of_index: } ulonglong value; - if (likely(!row_is_historic)) + if (likely(!historical_row)) value = sequence++; else value = historic_auto_decrement--; @@ -2302,8 +2303,9 @@ end_of_index: } if (DICT_TF2_FLAG_IS_SET(old_table, DICT_TF2_VERSIONED)) { - if (DICT_TF2_FLAG_IS_SET( - new_table, DICT_TF2_VERSIONED)) { + if (DICT_TF2_FLAG_IS_SET(new_table, + DICT_TF2_VERSIONED) && + !drop_historical) { dfield_t *end = dtuple_get_nth_field( row, new_table->vers_row_end); byte *data = static_cast( @@ -4674,7 +4676,8 @@ row_merge_build_indexes( bool skip_pk_sort, ut_stage_alter_t* stage, const dict_add_v_col_t* add_v, - struct TABLE* eval_table) + struct TABLE* eval_table, + bool drop_historical) { merge_file_t* merge_files; row_merge_block_t* block; @@ -4848,7 +4851,8 @@ row_merge_build_indexes( fts_sort_idx, psort_info, merge_files, key_numbers, n_indexes, add_cols, add_v, col_map, add_autoinc, sequence, block, skip_pk_sort, &tmpfd, stage, - pct_cost, crypt_data, crypt_block, eval_table); + pct_cost, crypt_data, crypt_block, eval_table, + drop_historical); stage->end_phase_read_pk(); -- cgit v1.2.1 From 88ccf759c1fce8f8e521475daf789083c8911600 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Fri, 1 Sep 2017 19:05:20 +0300 Subject: SQL: pruning, derived, view fixes [fixes #244] --- mysql-test/suite/versioning/r/partition.result | 3 ++ mysql-test/suite/versioning/r/view.result | 8 ++-- mysql-test/suite/versioning/t/partition.test | 4 ++ sql/field.cc | 9 +++- sql/field.h | 35 ++++++++++++++-- sql/item.cc | 10 ++++- sql/item.h | 8 ++++ sql/item_cmpfunc.cc | 58 ++------------------------ sql/item_cmpfunc.h | 1 - sql/sql_select.cc | 12 +++--- sql/sql_type.cc | 4 +- sql/sql_type.h | 7 ++-- sql/sql_yacc.yy | 16 ++++--- sql/table.cc | 5 ++- 14 files changed, 97 insertions(+), 83 deletions(-) diff --git a/mysql-test/suite/versioning/r/partition.result b/mysql-test/suite/versioning/r/partition.result index a7c02a3f9d0..7cf1822c2c9 100644 --- a/mysql-test/suite/versioning/r/partition.result +++ b/mysql-test/suite/versioning/r/partition.result @@ -175,6 +175,9 @@ x A B execute select_pn; x C D 1 1 1 +explain partitions select * from t1; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 pn system NULL NULL NULL NULL 1 set @str= concat('select ', @ts_start, ' from t1 partition (pn) into @ts0'); prepare stmt from @str; execute stmt; diff --git a/mysql-test/suite/versioning/r/view.result b/mysql-test/suite/versioning/r/view.result index 22b75f5439a..7d43df2a914 100644 --- a/mysql-test/suite/versioning/r/view.result +++ b/mysql-test/suite/versioning/r/view.result @@ -85,7 +85,7 @@ x create or replace view vt1 as select * from t1; show create view vt1; View Create View character_set_client collation_connection -vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`x` AS `x`,`t1`.`sys_trx_start` AS `sys_trx_start`,`t1`.`sys_trx_end` AS `sys_trx_end` from `t1` FOR SYSTEM_TIME ALL where `t1`.`sys_trx_end` = TIMESTAMP'2038-01-19 03:14:07.999999' latin1 latin1_swedish_ci +vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`x` AS `x`,`t1`.`sys_trx_start` AS `sys_trx_start`,`t1`.`sys_trx_end` AS `sys_trx_end` from `t1` FOR SYSTEM_TIME ALL where `t1`.`sys_trx_end` = 18446744073709551615 latin1 latin1_swedish_ci drop view vt1; drop view vt2; create view vt1 as select * from t1 for system_time all; @@ -178,15 +178,15 @@ create or replace table t3 (x int); create or replace view vt1 as select * from t1, t2, t3; show create view vt1; View Create View character_set_client collation_connection -vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`a` AS `a`,`t2`.`b` AS `b`,`t3`.`x` AS `x`,`t1`.`sys_trx_start` AS `sys_trx_start`,`t1`.`sys_trx_end` AS `sys_trx_end` from ((`t1` FOR SYSTEM_TIME ALL join `t2` FOR SYSTEM_TIME ALL) join `t3`) where `t1`.`sys_trx_end` = TIMESTAMP'2038-01-19 03:14:07.999999' and `t2`.`sys_trx_end` = TIMESTAMP'2038-01-19 03:14:07.999999' latin1 latin1_swedish_ci +vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`a` AS `a`,`t2`.`b` AS `b`,`t3`.`x` AS `x`,`t1`.`sys_trx_start` AS `sys_trx_start`,`t1`.`sys_trx_end` AS `sys_trx_end` from ((`t1` FOR SYSTEM_TIME ALL join `t2` FOR SYSTEM_TIME ALL) join `t3`) where `t1`.`sys_trx_end` = 18446744073709551615 and `t2`.`sys_trx_end` = 18446744073709551615 latin1 latin1_swedish_ci create or replace view vt1 as select * from t3, t2, t1; show create view vt1; View Create View character_set_client collation_connection -vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t3`.`x` AS `x`,`t2`.`b` AS `b`,`t1`.`a` AS `a`,`t2`.`sys_trx_start` AS `sys_trx_start`,`t2`.`sys_trx_end` AS `sys_trx_end` from ((`t3` join `t2` FOR SYSTEM_TIME ALL) join `t1` FOR SYSTEM_TIME ALL) where `t2`.`sys_trx_end` = TIMESTAMP'2038-01-19 03:14:07.999999' and `t1`.`sys_trx_end` = TIMESTAMP'2038-01-19 03:14:07.999999' latin1 latin1_swedish_ci +vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t3`.`x` AS `x`,`t2`.`b` AS `b`,`t1`.`a` AS `a`,`t2`.`sys_trx_start` AS `sys_trx_start`,`t2`.`sys_trx_end` AS `sys_trx_end` from ((`t3` join `t2` FOR SYSTEM_TIME ALL) join `t1` FOR SYSTEM_TIME ALL) where `t2`.`sys_trx_end` = 18446744073709551615 and `t1`.`sys_trx_end` = 18446744073709551615 latin1 latin1_swedish_ci create or replace view vt1 as select a, t2.sys_trx_end as endo from t3, t1, t2; show create view vt1; View Create View character_set_client collation_connection -vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`a` AS `a`,`t2`.`sys_trx_end` AS `endo`,`t2`.`sys_trx_start` AS `sys_trx_start` from ((`t3` join `t1` FOR SYSTEM_TIME ALL) join `t2` FOR SYSTEM_TIME ALL) where `t1`.`sys_trx_end` = TIMESTAMP'2038-01-19 03:14:07.999999' and `t2`.`sys_trx_end` = TIMESTAMP'2038-01-19 03:14:07.999999' latin1 latin1_swedish_ci +vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`a` AS `a`,`t2`.`sys_trx_end` AS `endo`,`t2`.`sys_trx_start` AS `sys_trx_start` from ((`t3` join `t1` FOR SYSTEM_TIME ALL) join `t2` FOR SYSTEM_TIME ALL) where `t1`.`sys_trx_end` = 18446744073709551615 and `t2`.`sys_trx_end` = 18446744073709551615 latin1 latin1_swedish_ci create or replace view vvt1 as select * from t1, t2, vt1; ERROR HY000: Creating VIEW `vvt1` is prohibited: versioned VIEW `vt1` in query! drop view vt1, vt12; diff --git a/mysql-test/suite/versioning/t/partition.test b/mysql-test/suite/versioning/t/partition.test index 5c97b468a1a..38b406d7f9b 100644 --- a/mysql-test/suite/versioning/t/partition.test +++ b/mysql-test/suite/versioning/t/partition.test @@ -108,6 +108,10 @@ prepare select_pn from @str; execute select_p0; execute select_pn; +# pruning check +--replace_result ALL system "Using where" "" +explain partitions select * from t1; + set @str= concat('select ', @ts_start, ' from t1 partition (pn) into @ts0'); prepare stmt from @str; execute stmt; drop prepare stmt; diff --git a/sql/field.cc b/sql/field.cc index 9afe74f0808..c1497c3ddf6 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1999,7 +1999,7 @@ bool Field_num::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate) } -bool Field_vers_system::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate, ulonglong trx_id) +bool Field_vers_trx_id::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate, ulonglong trx_id) { ASSERT_COLUMN_MARKED_FOR_READ; DBUG_ASSERT(ltime); @@ -10568,7 +10568,7 @@ Field *make_field(TABLE_SHARE *share, if (flags & (VERS_SYS_START_FLAG|VERS_SYS_END_FLAG)) { return new (mem_root) - Field_vers_system(ptr, field_length, null_pos, null_bit, + Field_vers_trx_id(ptr, field_length, null_pos, null_bit, unireg_check, field_name, f_is_zerofill(pack_flag) != 0, f_is_dec(pack_flag) == 0); @@ -10657,6 +10657,11 @@ Field *make_field(TABLE_SHARE *share, return 0; } +bool Field_vers_trx_id::test_if_equality_guarantees_uniqueness(const Item* item) const +{ + return item->type() == Item::DATE_ITEM; +} + /** Create a field suitable for create of table. */ diff --git a/sql/field.h b/sql/field.h index efd3fe18e6f..219f88ced0a 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1407,6 +1407,11 @@ public: return flags & (VERS_SYS_START_FLAG | VERS_SYS_END_FLAG); } + virtual bool vers_trx_id() const + { + return false; + } + /* Validate a non-null field value stored in the given record according to the current thread settings, e.g. sql_mode. @@ -2130,11 +2135,11 @@ public: }; -class Field_vers_system :public Field_longlong { +class Field_vers_trx_id :public Field_longlong { MYSQL_TIME cache; ulonglong cached; public: - Field_vers_system(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + Field_vers_trx_id(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, bool zero_arg, bool unsigned_arg) @@ -2143,13 +2148,37 @@ public: cached(0) {} enum_field_types real_type() const { return MYSQL_TYPE_LONGLONG; } - enum_field_types type() const { return MYSQL_TYPE_DATETIME;} + enum_field_types type() const { return MYSQL_TYPE_LONGLONG;} uint size_of() const { return sizeof(*this); } bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate, ulonglong trx_id); bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) { return get_date(ltime, fuzzydate, (ulonglong) val_int()); } + bool test_if_equality_guarantees_uniqueness(const Item *item) const; + bool can_optimize_keypart_ref(const Item_bool_func *cond, + const Item *item) const + { + return true; + } + + bool can_optimize_group_min_max(const Item_bool_func *cond, + const Item *const_item) const + { + return true; + } + bool can_optimize_range(const Item_bool_func *cond, + const Item *item, + bool is_eq_func) const + { + return true; + } + /* cmp_type() cannot be TIME_RESULT, because we want to compare this field against + integers. But in all other cases we treat it as TIME_RESULT! */ + bool vers_trx_id() const + { + return true; + } }; diff --git a/sql/item.cc b/sql/item.cc index 4314ee036e4..67e59016864 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -6328,7 +6328,7 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table, if (field_flags() & (VERS_SYS_START_FLAG|VERS_SYS_END_FLAG)) { field= new (mem_root) - Field_vers_system((uchar*) 0, max_length, null_ptr, 0, Field::NONE, + Field_vers_trx_id((uchar*) 0, max_length, null_ptr, 0, Field::NONE, name, 0, unsigned_flag); } else @@ -6671,7 +6671,7 @@ int Item_int::save_in_field(Field *field, bool no_conversions) Item *Item_int::clone_item(THD *thd) { - return new (thd->mem_root) Item_int(thd, name, value, max_length); + return new (thd->mem_root) Item_int(thd, name, value, max_length, unsigned_flag); } @@ -10775,6 +10775,12 @@ Item *Item_field::vers_optimized_fields_transformer(THD *thd, uchar *) return this; } +bool Item_field::vers_trx_id() const +{ + DBUG_ASSERT(field); + return field->vers_trx_id(); +} + void Item::register_in(THD *thd) { next= thd->free_list; diff --git a/sql/item.h b/sql/item.h index f73b09e2d25..6e74329eb86 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1337,6 +1337,8 @@ public: { if (other->cmp_type() == TIME_RESULT) return other->field_type(); + if (vers_trx_id() || other->vers_trx_id()) + return MYSQL_TYPE_DATETIME; DBUG_ASSERT(0); // Two non-temporal data types, we should not get to here return MYSQL_TYPE_DATETIME; } @@ -1649,6 +1651,8 @@ public: virtual Item *vers_optimized_fields_transformer(THD *thd, uchar *) { return this; } + virtual bool vers_trx_id() const + { return false; } virtual Item *neg_transformer(THD *thd) { return NULL; } virtual Item *update_value_transformer(THD *thd, uchar *select_arg) { return this; } @@ -2751,6 +2755,7 @@ public: Item_field *field_for_view_update() { return this; } int fix_outer_field(THD *thd, Field **field, Item **reference); virtual Item *vers_optimized_fields_transformer(THD *thd, uchar *); + virtual bool vers_trx_id() const; virtual Item *update_value_transformer(THD *thd, uchar *select_arg); Item *derived_field_transformer_for_having(THD *thd, uchar *arg); Item *derived_field_transformer_for_where(THD *thd, uchar *arg); @@ -3188,6 +3193,9 @@ public: Item_int(THD *thd, const char *str_arg,longlong i,uint length): Item_num(thd), value(i) { max_length=length; name=(char*) str_arg; fixed= 1; } + Item_int(THD *thd, const char *str_arg,longlong i,uint length, bool flag): + Item_num(thd), value(i) + { max_length=length; name=(char*) str_arg; fixed= 1; unsigned_flag= flag; } Item_int(THD *thd, const char *str_arg, uint length=64); enum Type type() const { return INT_ITEM; } enum Item_result result_type () const { return INT_RESULT; } diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 147bb270e37..b390f709fb4 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -127,9 +127,12 @@ Type_handler_hybrid_field_type::aggregate_for_comparison(const char *funcname, many cases. */ set_handler(items[0]->type_handler()->type_handler_for_comparison()); + m_vers_trx_id= items[0]->vers_trx_id(); for (uint i= 1 ; i < nitems ; i++) { unsigned_count+= items[i]->unsigned_flag; + if (!m_vers_trx_id) + m_vers_trx_id= items[i]->vers_trx_id(); if (aggregate_for_comparison(items[i]->type_handler()-> type_handler_for_comparison())) { @@ -421,7 +424,7 @@ void Item_func::convert_const_compared_to_int_field(THD *thd) args[field= 1]->real_item()->type() == FIELD_ITEM) { Item_field *field_item= (Item_field*) (args[field]->real_item()); - if ((field_item->field_type() == MYSQL_TYPE_LONGLONG || + if (((field_item->field_type() == MYSQL_TYPE_LONGLONG && !field_item->vers_trx_id()) || field_item->field_type() == MYSQL_TYPE_YEAR)) convert_const_to_int(thd, field_item, &args[!field]); } @@ -5218,59 +5221,6 @@ bool fix_escape_item(THD *thd, Item *escape_item, String *tmp_str, return FALSE; } -bool Item_bool_func2::fix_fields(THD* thd, Item** ref) -{ - if (Item_bool_func::fix_fields(thd, ref)) - return true; - - // System Versioning: convert TRX_ID to DATETIME - Item *trx_id= NULL; - int arg_idx= -1; - Field_vers_system *sys_field= NULL; - DBUG_ASSERT(arg_count == 2); - // find trx_id and sys_field - for (int i= 0; i < 2; ++i) - { - Item *arg= args[i]; - if (arg->result_type() != INT_RESULT) - continue; - DBUG_ASSERT(arg); - if (arg->type() == Item::FIELD_ITEM) - { - Field *f= static_cast(arg)->field; - DBUG_ASSERT(f); - if (f->vers_sys_field() && f->real_type() == MYSQL_TYPE_LONGLONG) - { - if (sys_field) - return false; - sys_field= static_cast(f); - continue; - } - } - if (trx_id) - return false; - trx_id= arg; - arg_idx= i; - } - if (!trx_id || !sys_field) - return false; - MYSQL_TIME ltime; - ulonglong trx_id_val= (ulonglong) trx_id->val_int(); - if (sys_field->get_date(<ime, false, trx_id_val)) - { - my_error(ER_VERS_NO_TRX_ID, MYF(0), trx_id_val); - return true; - } - Query_arena_stmt on_stmt_arena(thd); - Item *datetime= new (thd->mem_root) Item_datetime_literal(thd, <ime, 6); - if (!datetime) - return true; - DBUG_ASSERT(arg_idx > -1); - args[arg_idx]= datetime; - return false; -} - - bool Item_func_like::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 6eb1b34e568..a94105b352d 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -410,7 +410,6 @@ public: ftree= Item_func::get_mm_tree(param, cond_ptr); DBUG_RETURN(ftree); } - bool fix_fields(THD *thd, Item **ref); }; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 68fb90ae9ec..a5f1e3c9626 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -918,7 +918,7 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, switch (vers_conditions.type) { case FOR_SYSTEM_TIME_UNSPECIFIED: - if (!tmp_from_ib) + if (t->vers_start_field()->real_type() != MYSQL_TYPE_LONGLONG) { MYSQL_TIME max_time; thd->variables.time_zone->gmt_sec_to_TIME(&max_time, TIMESTAMP_MAX_VALUE); @@ -25555,6 +25555,11 @@ void TABLE_LIST::print(THD *thd, table_map eliminated_tables, String *str, } #endif /* WITH_PARTITION_STORAGE_ENGINE */ } + if (table && table->versioned()) + { + // versioning conditions are already unwrapped to WHERE clause + str->append(" FOR SYSTEM_TIME ALL"); + } if (my_strcasecmp(table_alias_charset, cmp_name, alias)) { char t_alias_buff[MAX_ALIAS_NAME]; @@ -25573,11 +25578,6 @@ void TABLE_LIST::print(THD *thd, table_map eliminated_tables, String *str, append_identifier(thd, str, t_alias, strlen(t_alias)); } - if (table && table->versioned()) - { - // versioning conditions are already unwrapped to WHERE clause - str->append(" FOR SYSTEM_TIME ALL"); - } if (index_hints) { diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 055a8969787..b61cadd0ea6 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -428,7 +428,9 @@ Type_handler_hybrid_field_type::aggregate_for_comparison(const Type_handler *h) Item_result a= cmp_type(); Item_result b= h->cmp_type(); - if (a == STRING_RESULT && b == STRING_RESULT) + if (m_vers_trx_id && (a == STRING_RESULT || b == STRING_RESULT)) + m_type_handler= &type_handler_datetime; + else if (a == STRING_RESULT && b == STRING_RESULT) m_type_handler= &type_handler_long_blob; else if (a == INT_RESULT && b == INT_RESULT) m_type_handler= &type_handler_longlong; diff --git a/sql/sql_type.h b/sql/sql_type.h index 053132626a3..49056a7d0de 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -1473,16 +1473,17 @@ public: class Type_handler_hybrid_field_type { const Type_handler *m_type_handler; + bool m_vers_trx_id; public: Type_handler_hybrid_field_type(); Type_handler_hybrid_field_type(const Type_handler *handler) - :m_type_handler(handler) + :m_type_handler(handler), m_vers_trx_id(false) { } Type_handler_hybrid_field_type(enum_field_types type) - :m_type_handler(Type_handler::get_handler_by_field_type(type)) + :m_type_handler(Type_handler::get_handler_by_field_type(type)), m_vers_trx_id(false) { } Type_handler_hybrid_field_type(const Type_handler_hybrid_field_type *other) - :m_type_handler(other->m_type_handler) + :m_type_handler(other->m_type_handler), m_vers_trx_id(other->m_vers_trx_id) { } const Type_handler *type_handler() const { return m_type_handler; } enum_field_types field_type() const { return m_type_handler->field_type(); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 20674ef5d27..ea7eb443896 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -11353,11 +11353,11 @@ table_primary_ident: */ table_primary_derived: - '(' get_select_lex select_derived_union ')' opt_table_alias + '(' get_select_lex select_derived_union ')' opt_for_system_time_clause opt_table_alias { /* Use $2 instead of Lex->current_select as derived table will alter value of Lex->current_select. */ - if (!($3 || $5) && $2->embedding && + if (!($3 || $6) && $2->embedding && !$2->embedding->nested_join->join_list.elements) { /* we have a derived table ($3 == NULL) but no alias, @@ -11380,7 +11380,7 @@ table_primary_derived: if (ti == NULL) MYSQL_YYABORT; if (!($$= sel->add_table_to_list(thd, - ti, $5, 0, + ti, $6, 0, TL_READ, MDL_SHARED_READ))) MYSQL_YYABORT; @@ -11388,7 +11388,7 @@ table_primary_derived: lex->pop_context(); lex->nest_level--; } - else if ($5 != NULL) + else if ($6 != NULL) { /* Tables with or without joins within parentheses cannot @@ -11412,11 +11412,13 @@ table_primary_derived: if ($$ && $$->derived && !$$->derived->first_select()->next_select()) $$->select_lex->add_where_field($$->derived->first_select()); + if ($5) + $$->vers_conditions= Lex->vers_conditions; } /* Represents derived table with WITH clause */ | '(' get_select_lex subselect_start with_clause query_expression_body - subselect_end ')' opt_table_alias + subselect_end ')' opt_for_system_time_clause opt_table_alias { LEX *lex=Lex; SELECT_LEX *sel= $2; @@ -11427,10 +11429,12 @@ table_primary_derived: $5->set_with_clause($4); lex->current_select= sel; if (!($$= sel->add_table_to_list(lex->thd, - ti, $8, 0, + ti, $9, 0, TL_READ, MDL_SHARED_READ))) MYSQL_YYABORT; sel->add_joined_table($$); + if ($8) + $$->vers_conditions= Lex->vers_conditions; } ; diff --git a/sql/table.cc b/sql/table.cc index 5bb8e6aa3f8..902e6ea0224 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -4730,16 +4730,19 @@ bool TABLE_LIST::create_field_translation(THD *thd) */ if (is_view() && get_unit()->prepared && !field_translation_updated) { + field_translation_updated= TRUE; + if (field_translation_end - field_translation < select->item_list.elements) + goto allocate; while ((item= it++)) { field_translation[field_count++].item= item; } - field_translation_updated= TRUE; } DBUG_RETURN(FALSE); } +allocate: arena= thd->activate_stmt_arena_if_needed(&backup); /* Create view fields translation table */ -- cgit v1.2.1 From 40e3922ac2b0b0eb1547a399a1834d9a9d48b8cf Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Mon, 4 Sep 2017 19:16:22 +0300 Subject: Tests: results update in sys_vars, funcs_1 suites --- mysql-test/suite/funcs_1/r/is_columns_mysql.result | 6 ++--- .../suite/funcs_1/r/is_statistics_mysql.result | 1 + .../sys_vars/r/sysvars_server_notembedded.result | 28 +++++++++++----------- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/mysql-test/suite/funcs_1/r/is_columns_mysql.result b/mysql-test/suite/funcs_1/r/is_columns_mysql.result index f51c4bfb089..6bff05c05ae 100644 --- a/mysql-test/suite/funcs_1/r/is_columns_mysql.result +++ b/mysql-test/suite/funcs_1/r/is_columns_mysql.result @@ -265,9 +265,9 @@ def mysql user Update_priv 6 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci e def mysql user User 2 NO char 80 240 NULL NULL NULL utf8 utf8_bin char(80) PRI select,insert,update,references NEVER NULL def mysql user x509_issuer 35 NULL NO blob 65535 65535 NULL NULL NULL NULL NULL blob select,insert,update,references NEVER NULL def mysql user x509_subject 36 NULL NO blob 65535 65535 NULL NULL NULL NULL NULL blob select,insert,update,references NEVER NULL -def mysql vtmd_template col_renames 5 NULL YES blob 65535 65535 NULL NULL NULL NULL NULL blob select,insert,update,references Column name mapping from previous lifetime NEVER NULL +def mysql vtmd_template archive_name 4 NULL YES varchar 64 192 NULL NULL NULL utf8 utf8_bin varchar(64) MUL select,insert,update,references Name of archive table NEVER NULL +def mysql vtmd_template col_renames 5 NULL YES blob 65535 65535 NULL NULL NULL NULL NULL blob select,insert,update,references Column name mappings from previous lifetime NEVER NULL def mysql vtmd_template end 2 NULL NO bigint NULL NULL 20 0 NULL NULL NULL bigint(20) unsigned PRI select,insert,update,references TRX_ID of table lifetime end NEVER NULL -def mysql vtmd_template frm_image 4 NULL NO blob 65535 65535 NULL NULL NULL NULL NULL blob select,insert,update,references Table structure during period [start, end) NEVER NULL def mysql vtmd_template name 3 NULL NO varchar 64 192 NULL NULL NULL utf8 utf8_bin varchar(64) select,insert,update,references Table name during period [start, end) NEVER NULL def mysql vtmd_template start 1 NULL YES bigint NULL NULL 20 0 NULL NULL NULL bigint(20) unsigned select,insert,update,references TRX_ID of table lifetime start NEVER NULL ########################################################################## @@ -608,5 +608,5 @@ NULL mysql user max_statement_time decimal NULL NULL NULL NULL decimal(12,6) NULL mysql vtmd_template start bigint NULL NULL NULL NULL bigint(20) unsigned NULL mysql vtmd_template end bigint NULL NULL NULL NULL bigint(20) unsigned 3.0000 mysql vtmd_template name varchar 64 192 utf8 utf8_bin varchar(64) -1.0000 mysql vtmd_template frm_image blob 65535 65535 NULL NULL blob +3.0000 mysql vtmd_template archive_name varchar 64 192 utf8 utf8_bin varchar(64) 1.0000 mysql vtmd_template col_renames blob 65535 65535 NULL NULL blob diff --git a/mysql-test/suite/funcs_1/r/is_statistics_mysql.result b/mysql-test/suite/funcs_1/r/is_statistics_mysql.result index 332d85ffbcd..b5f9096aa47 100644 --- a/mysql-test/suite/funcs_1/r/is_statistics_mysql.result +++ b/mysql-test/suite/funcs_1/r/is_statistics_mysql.result @@ -79,6 +79,7 @@ def mysql time_zone_transition_type 0 mysql PRIMARY 1 Time_zone_id A #CARD# NULL def mysql time_zone_transition_type 0 mysql PRIMARY 2 Transition_type_id A #CARD# NULL NULL BTREE def mysql user 0 mysql PRIMARY 1 Host A #CARD# NULL NULL BTREE def mysql user 0 mysql PRIMARY 2 User A #CARD# NULL NULL BTREE +def mysql vtmd_template 1 mysql archive_name 1 archive_name A #CARD# NULL NULL YES BTREE def mysql vtmd_template 0 mysql PRIMARY 1 end A #CARD# NULL NULL BTREE connect testuser1,localhost,testuser1,,db_datadict; SELECT * FROM information_schema.statistics diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result index c9f4e76da69..d5c045b0a5e 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result @@ -5119,6 +5119,20 @@ NUMERIC_BLOCK_SIZE NULL ENUM_VALUE_LIST NEVER,COMPLEMENTARY,PREFERABLY READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED +VARIABLE_NAME VERSIONING_ALTER_HISTORY +SESSION_VALUE KEEP +GLOBAL_VALUE KEEP +GLOBAL_VALUE_ORIGIN COMPILE-TIME +DEFAULT_VALUE KEEP +VARIABLE_SCOPE SESSION +VARIABLE_TYPE ENUM +VARIABLE_COMMENT Versioning ALTER TABLE mode +NUMERIC_MIN_VALUE NULL +NUMERIC_MAX_VALUE NULL +NUMERIC_BLOCK_SIZE NULL +ENUM_VALUE_LIST KEEP,SURVIVE,DROP +READ_ONLY NO +COMMAND_LINE_ARGUMENT OPTIONAL VARIABLE_NAME VERSIONING_CURRENT_TIMESTAMP SESSION_VALUE NOW GLOBAL_VALUE NOW @@ -5133,20 +5147,6 @@ NUMERIC_BLOCK_SIZE NULL ENUM_VALUE_LIST NULL READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED -VARIABLE_NAME VERSIONING_DDL_SURVIVAL -SESSION_VALUE OFF -GLOBAL_VALUE OFF -GLOBAL_VALUE_ORIGIN COMPILE-TIME -DEFAULT_VALUE OFF -VARIABLE_SCOPE SESSION -VARIABLE_TYPE BOOLEAN -VARIABLE_COMMENT Use system versioning DDL survival feature -NUMERIC_MIN_VALUE NULL -NUMERIC_MAX_VALUE NULL -NUMERIC_BLOCK_SIZE NULL -ENUM_VALUE_LIST OFF,ON -READ_ONLY NO -COMMAND_LINE_ARGUMENT OPTIONAL VARIABLE_NAME VERSIONING_FORCE SESSION_VALUE OFF GLOBAL_VALUE OFF -- cgit v1.2.1 From a734c2f0fb44b777866d8b0bc9ec46a08e4e6505 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 5 Sep 2017 16:49:08 +0300 Subject: Style: partitioning, sysvars, handler fixes * Sys_var_vers_asof formatting * Vers_field_stats renamed to Vers_min_max_stats * Item_temporal_literal::set_lower()/set_higher() replaced by operator>()/operator<() * handler API comments --- sql/handler.h | 36 +++++++++++++++++++++++++++++++++-- sql/item.cc | 20 ++++++++++---------- sql/item.h | 5 +++-- sql/partition_element.h | 8 +++++--- sql/partition_info.cc | 26 +++++++++++++++---------- sql/partition_info.h | 6 +++--- sql/sys_vars.ic | 50 ++++++++----------------------------------------- sql/table.h | 4 ++-- 8 files changed, 81 insertions(+), 74 deletions(-) diff --git a/sql/handler.h b/sql/handler.h index 2ab9ed48c8f..a0c40d2765a 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1392,9 +1392,41 @@ struct handlerton /* System Versioning */ + /** + Query VTQ by TRX_ID. + @param[in] thd MySQL thread + @param[out] out field value or whole record returned by query (selected by `field`) + @param[in] in_trx_id query parameter TRX_ID + @param[in] field field to get in `out` or VTQ_ALL for whole record (vtq_record_t) + @return TRUE if record is found, FALSE otherwise */ bool (*vers_query_trx_id)(THD* thd, void *out, ulonglong trx_id, vtq_field_t field); - bool (*vers_query_commit_ts)(THD* thd, void *out, const MYSQL_TIME &commit_ts, vtq_field_t field, bool backwards); - bool (*vers_trx_sees)(THD *thd, bool &result, ulonglong trx_id1, ulonglong trx_id0, ulonglong commit_id1, uchar iso_level1, ulonglong commit_id0); + + /** Query VTQ by COMMIT_TS. + @param[in] thd MySQL thread + @param[out] out field value or whole record returned by query (selected by `field`) + @param[in] commit_ts query parameter COMMIT_TS + @param[in] field field to get in `out` or VTQ_ALL for whole record (vtq_record_t) + @param[in] backwards direction of VTQ search + @return TRUE if record is found, FALSE otherwise */ + bool (*vers_query_commit_ts)(THD* thd, void *out, const MYSQL_TIME &commit_ts, + vtq_field_t field, bool backwards); + + /** Check if transaction TX1 sees transaction TX0. + @param[in] thd MySQL thread + @param[out] result true if TX1 sees TX0 + @param[in] trx_id1 TX1 TRX_ID + @param[in] trx_id0 TX0 TRX_ID + @param[in] commit_id1 TX1 COMMIT_ID + @param[in] iso_level1 TX1 isolation level + @param[in] commit_id0 TX0 COMMIT_ID + @return FALSE if there is no trx_id1 in VTQ, otherwise TRUE */ + bool (*vers_trx_sees)(THD *thd, bool &result, ulonglong trx_id1, ulonglong trx_id0, + ulonglong commit_id1, uchar iso_level1, ulonglong commit_id0); + + /** Upgrade InnoDB table handler to InnoDB partitioning handler. + @param[in] hnd InnoDB table handler + @param[in] mem_root mem_root for resulting handler + @return InnoDB partitioning handler or NULL on error */ handler *(*vers_upgrade_handler)(handler *hnd, MEM_ROOT *mem_root); }; diff --git a/sql/item.cc b/sql/item.cc index 67e59016864..5743c742900 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -6983,26 +6983,26 @@ bool Item_temporal_literal::eq(const Item *item, bool binary_cmp) const &((Item_temporal_literal *) item)->cached_time); } -bool Item_temporal_literal::set_lower(MYSQL_TIME * ltime) +bool Item_temporal_literal::operator<(const MYSQL_TIME <ime) const { - if (my_time_compare(ltime, &cached_time) < 0) - { - cached_time= *ltime; + if (my_time_compare(&cached_time, <ime) < 0) return true; - } return false; } -bool Item_temporal_literal::set_higher(MYSQL_TIME * ltime) +bool Item_temporal_literal::operator>(const MYSQL_TIME <ime) const { - if (my_time_compare(ltime, &cached_time) > 0) - { - cached_time= *ltime; + if (my_time_compare(&cached_time, <ime) > 0) return true; - } return false; } +bool Item_temporal_literal::operator==(const MYSQL_TIME <ime) const +{ + if (my_time_compare(&cached_time, <ime) == 0) + return true; + return false; +} void Item_date_literal::print(String *str, enum_query_type query_type) { diff --git a/sql/item.h b/sql/item.h index 6e74329eb86..ceb73c18264 100644 --- a/sql/item.h +++ b/sql/item.h @@ -3878,8 +3878,9 @@ public: { cached_time= *ltime; } - bool set_lower(MYSQL_TIME *ltime); - bool set_higher(MYSQL_TIME *ltime); + bool operator>(const MYSQL_TIME <ime) const; + bool operator<(const MYSQL_TIME <ime) const; + bool operator==(const MYSQL_TIME <ime) const; }; diff --git a/sql/partition_element.h b/sql/partition_element.h index 18276ef713e..723d2f21a46 100644 --- a/sql/partition_element.h +++ b/sql/partition_element.h @@ -90,7 +90,9 @@ typedef struct p_elem_val struct st_ddl_log_memory_entry; -class Vers_field_stats : public Sql_alloc +/* Used for collecting MIN/MAX stats on sys_trx_end for doing pruning + in SYSTEM_TIME partitiong. */ +class Vers_min_max_stats : public Sql_alloc { static const uint buf_size= 4 + (TIME_SECOND_PART_DIGITS + 1) / 2; uchar min_buf[buf_size]; @@ -100,7 +102,7 @@ class Vers_field_stats : public Sql_alloc mysql_rwlock_t lock; public: - Vers_field_stats(const char *field_name, TABLE_SHARE *share) : + Vers_min_max_stats(const char *field_name, TABLE_SHARE *share) : min_value(min_buf, NULL, 0, Field::NONE, field_name, share, 6), max_value(max_buf, NULL, 0, Field::NONE, field_name, share, 6) { @@ -108,7 +110,7 @@ public: memset(max_buf, 0, buf_size); mysql_rwlock_init(key_rwlock_LOCK_vers_stats, &lock); } - ~Vers_field_stats() + ~Vers_min_max_stats() { mysql_rwlock_destroy(&lock); } diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 86fb4b5bf63..8bf2e2cd72d 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -926,8 +926,8 @@ bool partition_info::vers_setup_1(THD * thd, uint32 added) if (added) { DBUG_ASSERT(partitions.elements > added + 1); - Vers_field_stats** old_array= table->s->stat_trx; - table->s->stat_trx= static_cast( + Vers_min_max_stats** old_array= table->s->stat_trx; + table->s->stat_trx= static_cast( alloc_root(&table->s->mem_root, sizeof(void *) * partitions.elements * num_columns)); memcpy(table->s->stat_trx, old_array, sizeof(void *) * (partitions.elements - added) * num_columns); } @@ -961,8 +961,8 @@ bool partition_info::vers_setup_1(THD * thd, uint32 added) if (el->id == UINT32_MAX || el->type == partition_element::AS_OF_NOW) { DBUG_ASSERT(table && table->s); - Vers_field_stats *stat_trx_end= new (&table->s->mem_root) - Vers_field_stats(table->s->vers_end_field()->field_name, table->s); + Vers_min_max_stats *stat_trx_end= new (&table->s->mem_root) + Vers_min_max_stats(table->s->vers_end_field()->field_name, table->s); table->s->stat_trx[id * num_columns + STAT_TRX_END]= stat_trx_end; el->id= id++; if (el->type == partition_element::AS_OF_NOW) @@ -1107,7 +1107,7 @@ void partition_info::vers_update_col_vals(THD *thd, partition_element *el0, part my_time_t ts; part_column_list_val *col_val; Item_datetime_literal *val_item; - Vers_field_stats *stat_trx_x; + Vers_min_max_stats *stat_trx_x; for (uint i= 0; i < num_columns; ++i) { stat_trx_x= table->s->stat_trx[idx + i]; @@ -1118,8 +1118,11 @@ void partition_info::vers_update_col_vals(THD *thd, partition_element *el0, part col_val= &el0->get_col_val(i); val_item= static_cast(col_val->item_expression); DBUG_ASSERT(val_item); - if (val_item->set_lower(&t)) + if (*val_item > t) + { + val_item->set_time(&t); col_val->fixed= 0; + } } col_val= &el1->get_col_val(i); if (!col_val->max_value) @@ -1128,8 +1131,11 @@ void partition_info::vers_update_col_vals(THD *thd, partition_element *el0, part thd->variables.time_zone->gmt_sec_to_TIME(&t, ts); val_item= static_cast(col_val->item_expression); DBUG_ASSERT(val_item); - if (val_item->set_higher(&t)) + if (*val_item < t) + { + val_item->set_time(&t); col_val->fixed= 0; + } } } } @@ -1162,7 +1168,7 @@ bool partition_info::vers_setup_2(THD * thd, bool is_create_table_ind) if (!table->s->stat_trx) { DBUG_ASSERT(partitions.elements > 1); - table->s->stat_trx= static_cast( + table->s->stat_trx= static_cast( alloc_root(&table->s->mem_root, sizeof(void *) * partitions.elements * num_columns)); dont_stat= false; } @@ -1183,8 +1189,8 @@ bool partition_info::vers_setup_2(THD * thd, bool is_create_table_ind) } { - Vers_field_stats *stat_trx_end= new (&table->s->mem_root) - Vers_field_stats(table->s->vers_end_field()->field_name, table->s); + Vers_min_max_stats *stat_trx_end= new (&table->s->mem_root) + Vers_min_max_stats(table->s->vers_end_field()->field_name, table->s); table->s->stat_trx[el->id * num_columns + STAT_TRX_END]= stat_trx_end; } diff --git a/sql/partition_info.h b/sql/partition_info.h index 9dff7a41a4a..d69774e0841 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -478,14 +478,14 @@ public: // TODO: cache thread-shared part_recs and increment on INSERT return table->file->part_records(part) >= vers_info->limit; } - Vers_field_stats& vers_stat_trx(stat_trx_field fld, uint32 part_element_id) + Vers_min_max_stats& vers_stat_trx(stat_trx_field fld, uint32 part_element_id) { DBUG_ASSERT(table && table->s && table->s->stat_trx); - Vers_field_stats* res= table->s->stat_trx[part_element_id * num_columns + fld]; + Vers_min_max_stats* res= table->s->stat_trx[part_element_id * num_columns + fld]; DBUG_ASSERT(res); return *res; } - Vers_field_stats& vers_stat_trx(stat_trx_field fld, partition_element *part) + Vers_min_max_stats& vers_stat_trx(stat_trx_field fld, partition_element *part) { DBUG_ASSERT(part); return vers_stat_trx(fld, part->id); diff --git a/sql/sys_vars.ic b/sql/sys_vars.ic index 27987a8d8b8..4f075c3436e 100644 --- a/sql/sys_vars.ic +++ b/sql/sys_vars.ic @@ -2495,32 +2495,11 @@ public: class Sys_var_vers_asof: public sys_var { public: - Sys_var_vers_asof( - const char *name_arg, - const char *comment, - int flag_args, - ptrdiff_t off, - size_t size, - CMD_LINE getopt, - enum charset_enum is_os_charset_arg, - const char *def_val, - on_check_function on_check_func=0, - on_update_function on_update_func=0) : - sys_var( - &all_sys_vars, - name_arg, - comment, - flag_args, - off, - getopt.id, - getopt.arg_type, - SHOW_CHAR, - (intptr) def_val, - 0, - VARIABLE_NOT_IN_BINLOG, - on_check_func, - on_update_func, - 0) + Sys_var_vers_asof(const char *name_arg, const char *comment, int flag_args, + ptrdiff_t off, size_t size, CMD_LINE getopt, enum charset_enum is_os_charset_arg, + const char *def_val, on_check_function on_check_func=0, on_update_function on_update_func=0) : + sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, getopt.arg_type, + SHOW_CHAR, (intptr) def_val, 0, VARIABLE_NOT_IN_BINLOG, on_check_func, on_update_func, 0) { option.var_type|= GET_STR; if (global_update(def_val)) @@ -2534,31 +2513,18 @@ public: bool update(String &in, st_vers_current_time &out) { - if (in.length() == 3 && - 0 == my_strcasecmp( - in.charset(), - "ALL", - in.ptr())) + if (in.length() == 3 && 0 == my_strcasecmp(in.charset(), "ALL", in.ptr())) { out.type= FOR_SYSTEM_TIME_ALL; } - else if (in.length() == 3 && - 0 == my_strcasecmp( - in.charset(), - "NOW", - in.ptr())) + else if (in.length() == 3 && 0 == my_strcasecmp(in.charset(), "NOW", in.ptr())) { out.type= FOR_SYSTEM_TIME_UNSPECIFIED; } else { MYSQL_TIME_STATUS status; - if (str_to_datetime( - in.ptr(), - in.length(), - &out.ltime, - flags, - &status) || + if (str_to_datetime(in.ptr(), in.length(), &out.ltime, flags, &status) || out.ltime.time_type != MYSQL_TIMESTAMP_DATETIME || (status.warnings & ~MYSQL_TIME_NOTE_TRUNCATED) != 0) { diff --git a/sql/table.h b/sql/table.h index 82d41ff831b..a2ede121064 100644 --- a/sql/table.h +++ b/sql/table.h @@ -561,7 +561,7 @@ struct TABLE_STATISTICS_CB bool histograms_are_read; }; -class Vers_field_stats; +class Vers_min_max_stats; #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) @@ -755,7 +755,7 @@ struct TABLE_SHARE uint16 row_start_field; uint16 row_end_field; uint32 hist_part_id; - Vers_field_stats** stat_trx; + Vers_min_max_stats** stat_trx; ulonglong stat_serial; // guards check_range_constants() updates bool busy_rotation; -- cgit v1.2.1 From 904b69cd9ed15b0d605b9923439e9a66b5057084 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Thu, 7 Sep 2017 15:49:11 +0300 Subject: SQL: partitioning misc fixes [closes #242] * cleanup: *never* use assert(A && B) * vers_setup_1() revisited * vers_setup_2() renamed * partition_element::type removed * Copy ctor instead of memcpy() * Handle return value from check_range_constants() * Malloc error fix * error, style, misc fixes --- mysql-test/suite/versioning/r/partition.result | 4 +- mysql-test/suite/versioning/t/partition.test | 2 +- sql/ha_partition.cc | 7 +- sql/ha_partition.h | 5 -- sql/handler.h | 2 +- sql/opt_range.cc | 7 +- sql/partition_element.h | 37 +++++--- sql/partition_info.cc | 114 ++++++++++++++----------- sql/partition_info.h | 32 +++---- sql/sql_partition.cc | 10 +-- sql/sql_yacc.yy | 4 +- sql/table.cc | 2 +- sql/table.h | 4 +- 13 files changed, 124 insertions(+), 106 deletions(-) diff --git a/mysql-test/suite/versioning/r/partition.result b/mysql-test/suite/versioning/r/partition.result index 7cf1822c2c9..2a42545755b 100644 --- a/mysql-test/suite/versioning/r/partition.result +++ b/mysql-test/suite/versioning/r/partition.result @@ -93,13 +93,13 @@ create or replace table t1 (x int) partition by system_time ( partition p0 versioning, partition pn as of now); -ERROR HY000: System Versioning required: `BY SYSTEM_TIME` partitioning +ERROR HY000: System Versioning required: t1 create or replace table t1 (x int); alter table t1 partition by system_time ( partition p0 versioning, partition pn as of now); -ERROR HY000: System Versioning required: `BY SYSTEM_TIME` partitioning +Got one of the listed errors create or replace table t1 (x int) with system versioning partition by system_time ( diff --git a/mysql-test/suite/versioning/t/partition.test b/mysql-test/suite/versioning/t/partition.test index 38b406d7f9b..cbc02d44e31 100644 --- a/mysql-test/suite/versioning/t/partition.test +++ b/mysql-test/suite/versioning/t/partition.test @@ -29,7 +29,7 @@ partition by system_time ( partition pn as of now); create or replace table t1 (x int); ---error ER_VERSIONING_REQUIRED +--error ER_VERSIONING_REQUIRED,ER_VERSIONING_REQUIRED alter table t1 partition by system_time ( partition p0 versioning, diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 747b9a8871f..68fffa24a02 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -2022,15 +2022,12 @@ int ha_partition::copy_partitions(ulonglong * const copied, else { THD *thd= ha_thd(); - handler *new_file= m_new_file[new_part]; /* Copy record to new handler */ (*copied)++; - if (new_file->ha_external_lock(thd, F_UNLCK) || new_file->ha_external_lock(thd, F_WRLCK)) - goto error; tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */ - result= new_file->ha_write_row(m_rec0); + result= m_new_file[new_part]->ha_write_row(m_rec0); reenable_binlog(thd); - if (new_file->ha_external_lock(thd, F_UNLCK) || new_file->ha_external_lock(thd, F_RDLCK) || result) + if (result) goto error; } } diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 98e0c1baafe..0eb96aa2d00 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -1355,11 +1355,6 @@ public: return h; } - virtual bool versioned() const - { - return m_innodb; - } - virtual ha_rows part_records(void *_part_elem) { partition_element *part_elem= reinterpret_cast(_part_elem); diff --git a/sql/handler.h b/sql/handler.h index a0c40d2765a..911eb25ba0e 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -4404,7 +4404,7 @@ public: virtual int find_unique_row(uchar *record, uint unique_ref) { return -1; /*unsupported */} - virtual bool versioned() const + bool native_versioned() const { DBUG_ASSERT(ht); return partition_ht()->flags & HTON_NATIVE_SYS_VERSIONING; } virtual ha_rows part_records(void *_part_elem) { DBUG_ASSERT(0); return false; } diff --git a/sql/opt_range.cc b/sql/opt_range.cc index fcf038a212b..53208571ee2 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -3455,9 +3455,11 @@ bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond) DBUG_RETURN(FALSE); } - if (part_info->part_type == VERSIONING_PARTITION) + if (part_info->part_type == VERSIONING_PARTITION && + part_info->vers_update_range_constants(thd)) { - part_info->vers_update_range_constants(thd); + retval= TRUE; + goto end2; } dbug_tmp_use_all_columns(table, old_sets, @@ -3559,6 +3561,7 @@ all_used: mark_all_partitions_as_used(prune_param.part_info); end: dbug_tmp_restore_column_maps(table->read_set, table->write_set, old_sets); +end2: thd->no_errors=0; thd->mem_root= range_par->old_root; free_root(&alloc,MYF(0)); // Return memory & allocator diff --git a/sql/partition_element.h b/sql/partition_element.h index 723d2f21a46..b8b716e5273 100644 --- a/sql/partition_element.h +++ b/sql/partition_element.h @@ -151,6 +151,13 @@ enum stat_trx_field class partition_element :public Sql_alloc { public: + enum elem_type + { + CONVENTIONAL= 0, + AS_OF_NOW, + VERSIONING + }; + List subpartitions; List list_val_list; ha_rows part_max_rows; @@ -172,14 +179,18 @@ public: uint32 id; bool empty; - enum elem_type + // TODO: subclass partition_element by partitioning type to avoid such semantic + // mixup + elem_type type() { - CONVENTIONAL= 0, - AS_OF_NOW, - VERSIONING - }; + return (elem_type)(signed_flag << 1 | max_value); + } - elem_type type; + void type(elem_type val) + { + max_value= val & 1; + signed_flag= val & 2; + } partition_element() : part_max_rows(0), part_min_rows(0), range_value(0), @@ -190,8 +201,7 @@ public: nodegroup_id(UNDEF_NODEGROUP), has_null_value(FALSE), signed_flag(FALSE), max_value(FALSE), id(UINT32_MAX), - empty(true), - type(CONVENTIONAL) + empty(true) {} partition_element(partition_element *part_elem) : part_max_rows(part_elem->part_max_rows), @@ -207,17 +217,16 @@ public: nodegroup_id(part_elem->nodegroup_id), has_null_value(FALSE), id(part_elem->id), - empty(part_elem->empty), - type(part_elem->type) + empty(part_elem->empty) {} ~partition_element() {} part_column_list_val& get_col_val(uint idx) { - DBUG_ASSERT(type != CONVENTIONAL); - DBUG_ASSERT(list_val_list.elements == 1); - part_elem_value *ev= static_cast(list_val_list.first_node()->info); - DBUG_ASSERT(ev && ev->col_val_array); + DBUG_ASSERT(type() == CONVENTIONAL || list_val_list.elements == 1); + part_elem_value *ev= list_val_list.head(); + DBUG_ASSERT(ev); + DBUG_ASSERT(ev->col_val_array); return ev->col_val_array[idx]; } }; diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 8bf2e2cd72d..af97791ab80 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -44,13 +44,12 @@ partition_info *partition_info::get_clone(THD *thd) List_iterator part_it(partitions); partition_element *part; - partition_info *clone= new (mem_root) partition_info(); + partition_info *clone= new (mem_root) partition_info(*this); if (!clone) { mem_alloc_error(sizeof(partition_info)); DBUG_RETURN(NULL); } - memcpy(clone, this, sizeof(partition_info)); memset(&(clone->read_partitions), 0, sizeof(clone->read_partitions)); memset(&(clone->lock_partitions), 0, sizeof(clone->lock_partitions)); clone->bitmaps_are_initialized= FALSE; @@ -913,28 +912,59 @@ partition_info::vers_part_rotate(THD * thd) return vers_info->hist_part; } -bool partition_info::vers_setup_1(THD * thd, uint32 added) +bool partition_info::vers_set_expression(THD *thd, partition_element *el, MYSQL_TIME& t) +{ + curr_part_elem= el; + init_column_part(thd); + el->list_val_list.empty(); + el->list_val_list.push_back(curr_list_val, thd->mem_root); + for (uint i= 0; i < num_columns; ++i) + { + part_column_list_val *col_val= add_column_value(thd); + if (el->type() == partition_element::AS_OF_NOW) + { + col_val->max_value= true; + col_val->item_expression= NULL; + col_val->column_value= NULL; + col_val->part_info= this; + col_val->fixed= 1; + continue; + } + Item *item_expression= new (thd->mem_root) Item_datetime_literal(thd, &t); + if (!item_expression) + return true; + /* We initialize col_val with bogus max value to make fix_partition_func() and check_range_constants() happy. + Later in vers_setup_stats() it is initialized with real stat value if there will be any. */ + /* FIXME: TIME_RESULT in col_val is expensive. It should be INT_RESULT + (got to be fixed when InnoDB is supported). */ + init_col_val(col_val, item_expression); + DBUG_ASSERT(item_expression == el->get_col_val(i).item_expression); + } // for (num_columns) + return false; +} + +bool partition_info::vers_setup_expression(THD * thd, uint32 alter_add) { DBUG_ASSERT(part_type == VERSIONING_PARTITION); if (!table->versioned()) { - my_error(ER_VERSIONING_REQUIRED, MYF(0), "`BY SYSTEM_TIME` partitioning"); + my_error(ER_VERSIONING_REQUIRED, MYF(0), table->s->table_name); return true; } - if (added) + if (alter_add) { - DBUG_ASSERT(partitions.elements > added + 1); + DBUG_ASSERT(partitions.elements > alter_add + 1); Vers_min_max_stats** old_array= table->s->stat_trx; table->s->stat_trx= static_cast( alloc_root(&table->s->mem_root, sizeof(void *) * partitions.elements * num_columns)); - memcpy(table->s->stat_trx, old_array, sizeof(void *) * (partitions.elements - added) * num_columns); + memcpy(table->s->stat_trx, old_array, sizeof(void *) * (partitions.elements - alter_add) * num_columns); } else { + /* Prepare part_field_list */ Field *sys_trx_end= table->vers_end_field(); - part_field_list.empty(); part_field_list.push_back(const_cast(sys_trx_end->field_name), thd->mem_root); DBUG_ASSERT(part_field_list.elements == num_columns); // needed in handle_list_of_fields() @@ -949,26 +979,29 @@ bool partition_info::vers_setup_1(THD * thd, uint32 added) uint32 id= 0; while ((el= it++)) { - DBUG_ASSERT(el->type != partition_element::CONVENTIONAL); + DBUG_ASSERT(el->type() != partition_element::CONVENTIONAL); ++ts; - if (added) + if (alter_add) { - if (el->type == partition_element::VERSIONING && !el->empty) + /* Non-empty historical partitions are left as is. */ + if (el->type() == partition_element::VERSIONING && !el->empty) { ++id; continue; } - if (el->id == UINT32_MAX || el->type == partition_element::AS_OF_NOW) + /* Newly added element is inserted before AS_OF_NOW. */ + if (el->id == UINT32_MAX || el->type() == partition_element::AS_OF_NOW) { DBUG_ASSERT(table && table->s); Vers_min_max_stats *stat_trx_end= new (&table->s->mem_root) Vers_min_max_stats(table->s->vers_end_field()->field_name, table->s); table->s->stat_trx[id * num_columns + STAT_TRX_END]= stat_trx_end; el->id= id++; - if (el->type == partition_element::AS_OF_NOW) + if (el->type() == partition_element::AS_OF_NOW) break; - goto create_col_val; + goto set_expression; } + /* Existing element expression is recalculated. */ thd->variables.time_zone->gmt_sec_to_TIME(&t, ts); for (uint i= 0; i < num_columns; ++i) { @@ -980,32 +1013,10 @@ bool partition_info::vers_setup_1(THD * thd, uint32 added) continue; } - create_col_val: - curr_part_elem= el; - init_column_part(thd); - el->list_val_list.empty(); - el->list_val_list.push_back(curr_list_val, thd->mem_root); + set_expression: thd->variables.time_zone->gmt_sec_to_TIME(&t, ts); - for (uint i= 0; i < num_columns; ++i) - { - part_column_list_val *col_val= add_column_value(thd); - if (el->type == partition_element::AS_OF_NOW) - { - col_val->max_value= true; - col_val->item_expression= NULL; - col_val->column_value= NULL; - col_val->part_info= this; - col_val->fixed= 1; - continue; - } - Item *item_expression= new (thd->mem_root) Item_datetime_literal(thd, &t); - /* We initialize col_val with bogus max value to make fix_partition_func() and check_range_constants() happy. - Later in vers_setup_2() it is initialized with real stat value if there will be any. */ - /* FIXME: TIME_RESULT in col_val is expensive. It should be INT_RESULT - (got to be fixed when InnoDB is supported). */ - init_col_val(col_val, item_expression); - DBUG_ASSERT(item_expression == el->get_col_val(i).item_expression); - } + if (vers_set_expression(thd, el, t)) + return true; } return false; } @@ -1019,7 +1030,7 @@ bool partition_info::vers_scan_min_max(THD *thd, partition_element *part) uint32 part_id= part->id * sub_factor; uint32 part_id_end= part_id + sub_factor; DBUG_ASSERT(part->empty); - DBUG_ASSERT(part->type == partition_element::VERSIONING); + DBUG_ASSERT(part->type() == partition_element::VERSIONING); DBUG_ASSERT(table->s->stat_trx); for (; part_id < part_id_end; ++part_id) { @@ -1141,8 +1152,8 @@ void partition_info::vers_update_col_vals(THD *thd, partition_element *el0, part } -// setup at open stage (TABLE_SHARE is initialized) -bool partition_info::vers_setup_2(THD * thd, bool is_create_table_ind) +// setup at open() phase (TABLE_SHARE is initialized) +bool partition_info::vers_setup_stats(THD * thd, bool is_create_table_ind) { DBUG_ASSERT(part_type == VERSIONING_PARTITION); DBUG_ASSERT(vers_info && vers_info->initialized(false)); @@ -1165,6 +1176,7 @@ bool partition_info::vers_setup_2(THD * thd, bool is_create_table_ind) bool dont_stat= true; bool col_val_updated= false; + // initialize stat_trx if (!table->s->stat_trx) { DBUG_ASSERT(partitions.elements > 1); @@ -1178,7 +1190,7 @@ bool partition_info::vers_setup_2(THD * thd, bool is_create_table_ind) partition_element *el= NULL, *prev; while ((prev= el, el= it++)) { - if (el->type == partition_element::VERSIONING && dont_stat) + if (el->type() == partition_element::VERSIONING && dont_stat) { if (el->id == table->s->hist_part_id) { @@ -1196,7 +1208,7 @@ bool partition_info::vers_setup_2(THD * thd, bool is_create_table_ind) if (!is_create_table_ind) { - if (el->type == partition_element::AS_OF_NOW) + if (el->type() == partition_element::AS_OF_NOW) { uchar buf[8]; Field_timestampf fld(buf, NULL, 0, Field::NONE, table->vers_end_field()->field_name, NULL, 6); @@ -1217,10 +1229,10 @@ bool partition_info::vers_setup_2(THD * thd, bool is_create_table_ind) } } - if (el->type == partition_element::AS_OF_NOW) + if (el->type() == partition_element::AS_OF_NOW) break; - DBUG_ASSERT(el->type == partition_element::VERSIONING); + DBUG_ASSERT(el->type() == partition_element::VERSIONING); if (vers_info->hist_part) { @@ -1435,7 +1447,7 @@ error: called for RANGE PARTITIONed tables. */ -bool partition_info::check_range_constants(THD *thd, bool init) +bool partition_info::check_range_constants(THD *thd, bool alloc) { partition_element* part_def; bool first= TRUE; @@ -1452,7 +1464,7 @@ bool partition_info::check_range_constants(THD *thd, bool init) part_column_list_val *UNINIT_VAR(current_largest_col_val); uint num_column_values= part_field_list.elements; uint size_entries= sizeof(part_column_list_val) * num_column_values; - if (init) + if (alloc) { range_col_array= (part_column_list_val*) thd->calloc(num_parts * size_entries); @@ -1493,7 +1505,7 @@ bool partition_info::check_range_constants(THD *thd, bool init) longlong part_range_value; bool signed_flag= !part_expr->unsigned_flag; - if (init) + if (alloc) { range_int_array= (longlong*) thd->alloc(num_parts * sizeof(longlong)); if (unlikely(range_int_array == NULL)) @@ -2065,13 +2077,13 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, } if (part_type == VERSIONING_PARTITION) { - if (part_elem->type == partition_element::VERSIONING) + if (part_elem->type() == partition_element::VERSIONING) { hist_parts++; } else { - DBUG_ASSERT(part_elem->type == partition_element::AS_OF_NOW); + DBUG_ASSERT(part_elem->type() == partition_element::AS_OF_NOW); now_parts++; } } diff --git a/sql/partition_info.h b/sql/partition_info.h index d69774e0841..99772f29891 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -57,13 +57,12 @@ struct Vers_part_info : public Sql_alloc { if (now_part) { - DBUG_ASSERT( - now_part->id != UINT32_MAX && - now_part->type == partition_element::AS_OF_NOW && - (fully ? (bool) hist_part : true) && - (!hist_part || ( + DBUG_ASSERT(now_part->id != UINT32_MAX); + DBUG_ASSERT(now_part->type() == partition_element::AS_OF_NOW); + DBUG_ASSERT(!fully || (bool) hist_part); + DBUG_ASSERT(!hist_part || ( hist_part->id != UINT32_MAX && - hist_part->type == partition_element::VERSIONING))); + hist_part->type() == partition_element::VERSIONING)); return true; } return false; @@ -352,7 +351,7 @@ public: char *find_duplicate_field(); char *find_duplicate_name(); bool check_engine_mix(handlerton *engine_type, bool default_engine); - bool check_range_constants(THD *thd, bool init= true); + bool check_range_constants(THD *thd, bool alloc= true); bool check_list_constants(THD *thd); bool check_partition_info(THD *thd, handlerton **eng_type, handler *file, HA_CREATE_INFO *info, @@ -426,8 +425,9 @@ public: bool vers_set_interval(const INTERVAL &i); bool vers_set_limit(ulonglong limit); partition_element* vers_part_rotate(THD *thd); - bool vers_setup_1(THD *thd, uint32 added= 0); - bool vers_setup_2(THD *thd, bool is_create_table_ind); + bool vers_set_expression(THD *thd, partition_element *el, MYSQL_TIME &t); + bool vers_setup_expression(THD *thd, uint32 alter_add= 0); /* Stage 1. */ + bool vers_setup_stats(THD *thd, bool is_create_table_ind); /* Stage 2. */ bool vers_scan_min_max(THD *thd, partition_element *part); void vers_update_col_vals(THD *thd, partition_element *el0, partition_element *el1); @@ -443,8 +443,8 @@ public: partition_element *el; while ((el= it++)) { - DBUG_ASSERT(el->type != partition_element::CONVENTIONAL); - if (el->type == partition_element::VERSIONING && + DBUG_ASSERT(el->type() != partition_element::CONVENTIONAL); + if (el->type() == partition_element::VERSIONING && el->id == table->s->hist_part_id) { vers_info->hist_part= el; @@ -516,7 +516,7 @@ public: { DBUG_ASSERT(vers_info && vers_info->initialized()); DBUG_ASSERT(table && table->s); - DBUG_ASSERT(el && el->type == partition_element::VERSIONING); + DBUG_ASSERT(el && el->type() == partition_element::VERSIONING); bool updated; mysql_rwlock_wrlock(&table->s->LOCK_stat_serial); el->empty= false; @@ -552,7 +552,7 @@ public: if (part_id < vers_info->now_part->id) vers_update_stats(thd, get_partition(part_id)); } - void vers_update_range_constants(THD *thd) + bool vers_update_range_constants(THD *thd) { DBUG_ASSERT(vers_info && vers_info->initialized()); DBUG_ASSERT(table && table->s); @@ -561,17 +561,19 @@ public: if (vers_info->stat_serial == table->s->stat_serial) { mysql_rwlock_unlock(&table->s->LOCK_stat_serial); - return; + return false; } + bool result= false; for (uint i= 0; i < num_columns; ++i) { Field *f= part_field_array[i]; bitmap_set_bit(f->table->write_set, f->field_index); } - check_range_constants(thd, false); + result= check_range_constants(thd, false); vers_info->stat_serial= table->s->stat_serial; mysql_rwlock_unlock(&table->s->LOCK_stat_serial); + return result; } }; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 7278b56a017..08ba4d84d9b 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -1689,7 +1689,7 @@ bool fix_partition_func(THD *thd, TABLE *table, if (part_info->column_list) { if (part_info->part_type == VERSIONING_PARTITION && - part_info->vers_setup_1(thd)) + part_info->vers_setup_expression(thd)) goto end; List_iterator it(part_info->part_field_list); if (unlikely(handle_list_of_fields(thd, it, table, part_info, FALSE))) @@ -2392,7 +2392,7 @@ static int add_partition_values(File fptr, partition_info *part_info, } else if (part_info->part_type == VERSIONING_PARTITION) { - switch (p_elem->type) + switch (p_elem->type()) { case partition_element::AS_OF_NOW: err+= add_string(fptr, " AS OF NOW"); @@ -5300,7 +5300,7 @@ that are reorganised. partition_element *el; while ((el= it++)) { - if (el->type == partition_element::AS_OF_NOW) + if (el->type() == partition_element::AS_OF_NOW) { DBUG_ASSERT(tab_part_info->vers_info && el == tab_part_info->vers_info->now_part); it.remove(); @@ -5393,7 +5393,7 @@ that are reorganised. if (is_name_in_list(part_elem->partition_name, alter_info->partition_names)) { - if (part_elem->type == partition_element::AS_OF_NOW) + if (part_elem->type() == partition_element::AS_OF_NOW) { DBUG_ASSERT(table && table->s && table->s->table_name.str); my_error(ER_VERS_WRONG_PARTS, MYF(0), table->s->table_name.str); @@ -5724,7 +5724,7 @@ the generated partition syntax in a correct manner. if (alter_info->flags & Alter_info::ALTER_ADD_PARTITION && tab_part_info->part_type == VERSIONING_PARTITION && - tab_part_info->vers_setup_1(thd, alt_part_info->partitions.elements)) + tab_part_info->vers_setup_expression(thd, alt_part_info->partitions.elements)) goto err; if (tab_part_info->check_partition_info(thd, (handlerton**)NULL, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index ea7eb443896..1f0ce5fd6a0 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5212,7 +5212,7 @@ opt_part_values: my_yyabort_error((ER_VERS_WRONG_PARTS, MYF(0), Lex->create_last_non_select_table->table_name)); } - elem->type= partition_element::AS_OF_NOW; + elem->type(partition_element::AS_OF_NOW); DBUG_ASSERT(part_info->vers_info); part_info->vers_info->now_part= elem; if (part_info->init_column_part(thd)) @@ -5243,7 +5243,7 @@ opt_part_values: DBUG_ASSERT(Lex->create_last_non_select_table->table_name); my_yyabort_error((ER_VERS_WRONG_PARTS, MYF(0), Lex->create_last_non_select_table->table_name)); } - elem->type= partition_element::VERSIONING; + elem->type(partition_element::VERSIONING); if (part_info->init_column_part(thd)) { MYSQL_YYABORT; diff --git a/sql/table.cc b/sql/table.cc index 902e6ea0224..07d912c4045 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -3455,7 +3455,7 @@ partititon_err: thd->stmt_arena= &part_func_arena; } - bool err= outparam->part_info->vers_setup_2(thd, is_create_table); + bool err= outparam->part_info->vers_setup_stats(thd, is_create_table); if (!work_part_info_used) { diff --git a/sql/table.h b/sql/table.h index a2ede121064..d857ba4752b 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1521,13 +1521,13 @@ public: bool versioned_by_sql() const { DBUG_ASSERT(s && file); - return s->versioned && !file->versioned(); + return s->versioned && !file->native_versioned(); } bool versioned_by_engine() const { DBUG_ASSERT(s && file); - return s->versioned && file->versioned(); + return s->versioned && file->native_versioned(); } Field *vers_start_field() const -- cgit v1.2.1 From a49239b57a5e46f118a7ab46b8f298b4f596d6ec Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Fri, 8 Sep 2017 10:22:24 +0300 Subject: SQL: truncate syntax and privilege [closes #229] --- mysql-test/r/alter_user.result | 56 ++++---- mysql-test/r/create_user.result | 48 +++---- mysql-test/r/events_grant.result | 2 +- mysql-test/r/grant.result | 18 ++- mysql-test/r/information_schema.result | 2 + mysql-test/r/lowercase_table_grant.result | 8 +- mysql-test/r/no_password_column-mdev-11170.result | 1 + mysql-test/r/ps.result | 6 +- mysql-test/r/sql_mode.result | 2 +- mysql-test/r/system_mysql_db.result | 4 +- mysql-test/r/system_mysql_db_fix40123.result | 4 +- mysql-test/r/system_mysql_db_fix50030.result | 4 +- mysql-test/r/system_mysql_db_fix50117.result | 4 +- mysql-test/suite/funcs_1/r/innodb_trig_03.result | 22 +-- mysql-test/suite/funcs_1/r/innodb_trig_03e.result | 6 +- .../suite/funcs_1/r/is_column_privileges.result | 1 + mysql-test/suite/funcs_1/r/is_columns_mysql.result | 36 ++--- .../suite/funcs_1/r/is_schema_privileges.result | 2 + .../r/is_schema_privileges_is_mysql_test.result | 1 + .../suite/funcs_1/r/is_table_privileges.result | 4 + mysql-test/suite/funcs_1/r/is_triggers.result | 2 +- .../suite/funcs_1/r/is_user_privileges.result | 33 +++++ mysql-test/suite/funcs_1/r/memory_trig_03.result | 22 +-- mysql-test/suite/funcs_1/r/memory_trig_03e.result | 6 +- mysql-test/suite/funcs_1/r/myisam_trig_03.result | 22 +-- mysql-test/suite/funcs_1/r/myisam_trig_03e.result | 6 +- .../create_and_drop_role_invalid_user_table.result | 4 +- mysql-test/suite/roles/set_role-recursive.result | 8 +- mysql-test/suite/roles/set_role-simple.result | 4 +- mysql-test/suite/versioning/r/truncate.result | 148 +-------------------- .../suite/versioning/r/truncate_privilege.result | 33 +++++ mysql-test/suite/versioning/r/vtmd_show.result | 2 - .../suite/versioning/t/truncate.combinations | 5 + mysql-test/suite/versioning/t/truncate.test | 106 +-------------- .../suite/versioning/t/truncate_privilege.test | 41 ++++++ mysql-test/suite/versioning/t/vtmd_show.test | 2 - scripts/mysql_system_tables.sql | 6 +- scripts/mysql_system_tables_data.sql | 14 +- scripts/mysql_system_tables_fix.sql | 8 +- sql/sql_acl.cc | 19 ++- sql/sql_acl.h | 27 ++-- sql/sql_delete.cc | 11 +- sql/sql_show.cc | 1 + sql/sql_truncate.cc | 5 +- sql/sql_yacc.yy | 22 +-- sql/vtq.h | 0 46 files changed, 359 insertions(+), 429 deletions(-) create mode 100644 mysql-test/suite/versioning/r/truncate_privilege.result create mode 100644 mysql-test/suite/versioning/t/truncate.combinations create mode 100644 mysql-test/suite/versioning/t/truncate_privilege.test mode change 100755 => 100644 sql/vtq.h diff --git a/mysql-test/r/alter_user.result b/mysql-test/r/alter_user.result index ac668bba8fa..6bbe8185cdd 100644 --- a/mysql-test/r/alter_user.result +++ b/mysql-test/r/alter_user.result @@ -1,25 +1,25 @@ select * from mysql.user where user = 'root' and host = 'localhost'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -localhost root Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y 0 0 0 0 N N 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +localhost root Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y 0 0 0 0 N N 0.000000 # Test syntax # # These 2 selects should have no changes from the first one. alter user CURRENT_USER; select * from mysql.user where user = 'root' and host = 'localhost'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -localhost root Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y 0 0 0 0 N N 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +localhost root Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y 0 0 0 0 N N 0.000000 alter user CURRENT_USER(); select * from mysql.user where user = 'root' and host = 'localhost'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -localhost root Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y 0 0 0 0 N N 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +localhost root Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y 0 0 0 0 N N 0.000000 create user foo; select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo N N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0 N N 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0 N N 0.000000 alter user foo; select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo N N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0 N N 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0 N N 0.000000 # Test super privilege works correctly with a read only database. SET @start_read_only = @@global.read_only; SET GLOBAL read_only=1; @@ -50,44 +50,44 @@ Note 1396 Operation ALTER USER failed for 'boo' # Test password related altering. alter user foo identified by 'something'; select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *88C89BE093D4ECF72D039F62EBB7477EA1FD4D63 N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N 0 0 0 0 N N 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *88C89BE093D4ECF72D039F62EBB7477EA1FD4D63 N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N N 0 0 0 0 N N 0.000000 alter user foo identified by 'something2'; select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *9CD58369E930E28C8996A89DB18B63294E6DC10C N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N 0 0 0 0 N N 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *9CD58369E930E28C8996A89DB18B63294E6DC10C N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N N 0 0 0 0 N N 0.000000 alter user foo identified by password '*88C89BE093D4ECF72D039F62EBB7477EA1FD4D63'; select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *88C89BE093D4ECF72D039F62EBB7477EA1FD4D63 N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N 0 0 0 0 N N 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *88C89BE093D4ECF72D039F62EBB7477EA1FD4D63 N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N N 0 0 0 0 N N 0.000000 alter user foo identified with 'somecoolplugin'; select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N 0 0 0 0 somecoolplugin N N 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N N 0 0 0 0 somecoolplugin N N 0.000000 alter user foo identified with 'somecoolplugin' using 'somecoolpassphrase'; select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N 0 0 0 0 somecoolplugin somecoolpassphrase N N 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N N 0 0 0 0 somecoolplugin somecoolpassphrase N N 0.000000 # Test ssl related altering. alter user foo identified by 'something' require SSL; select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *88C89BE093D4ECF72D039F62EBB7477EA1FD4D63 N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N ANY 0 0 0 0 N N 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *88C89BE093D4ECF72D039F62EBB7477EA1FD4D63 N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N N ANY 0 0 0 0 N N 0.000000 alter user foo identified by 'something' require X509; select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *88C89BE093D4ECF72D039F62EBB7477EA1FD4D63 N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N X509 0 0 0 0 N N 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *88C89BE093D4ECF72D039F62EBB7477EA1FD4D63 N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N N X509 0 0 0 0 N N 0.000000 alter user foo identified by 'something' require cipher 'text' issuer 'foo_issuer' subject 'foo_subject'; select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *88C89BE093D4ECF72D039F62EBB7477EA1FD4D63 N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N SPECIFIED text foo_issuer foo_subject 0 0 0 0 N N 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *88C89BE093D4ECF72D039F62EBB7477EA1FD4D63 N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N N SPECIFIED text foo_issuer foo_subject 0 0 0 0 N N 0.000000 # Test resource limits altering. alter user foo with MAX_QUERIES_PER_HOUR 10 MAX_UPDATES_PER_HOUR 20 MAX_CONNECTIONS_PER_HOUR 30 MAX_USER_CONNECTIONS 40; select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *88C89BE093D4ECF72D039F62EBB7477EA1FD4D63 N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N SPECIFIED text foo_issuer foo_subject 10 20 30 40 N N 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *88C89BE093D4ECF72D039F62EBB7477EA1FD4D63 N N N N N N N N N N N N N N N Y N N N N N N N N N Y N N N N SPECIFIED text foo_issuer foo_subject 10 20 30 40 N N 0.000000 drop user foo; diff --git a/mysql-test/r/create_user.result b/mysql-test/r/create_user.result index 1411f2e8792..6bc09a91f17 100644 --- a/mysql-test/r/create_user.result +++ b/mysql-test/r/create_user.result @@ -1,57 +1,57 @@ create user foo; select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo N N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0 N N 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0 N N 0.000000 drop user foo; create user foo identified by 'password'; select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0 N N 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0 N N 0.000000 drop user foo; create user foo identified by 'password' require SSL; select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N ANY 0 0 0 0 N N 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N ANY 0 0 0 0 N N 0.000000 drop user foo; create user foo identified by 'password' require X509; select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N X509 0 0 0 0 N N 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N X509 0 0 0 0 N N 0.000000 drop user foo; create user foo identified by 'password' require CIPHER 'cipher'; select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N SPECIFIED cipher 0 0 0 0 N N 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N SPECIFIED cipher 0 0 0 0 N N 0.000000 drop user foo; create user foo identified by 'password' require ISSUER 'issuer'; select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N SPECIFIED issuer 0 0 0 0 N N 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N SPECIFIED issuer 0 0 0 0 N N 0.000000 drop user foo; create user foo identified by 'password' require SUBJECT 'subject'; select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N SPECIFIED subject 0 0 0 0 N N 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N SPECIFIED subject 0 0 0 0 N N 0.000000 drop user foo; create user foo identified by 'password' require CIPHER 'cipher' SUBJECT 'subject'; select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N SPECIFIED cipher subject 0 0 0 0 N N 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N SPECIFIED cipher subject 0 0 0 0 N N 0.000000 drop user foo; create user foo identified by 'password' require CIPHER 'cipher' AND SUBJECT 'subject' AND ISSUER 'issuer'; select * from mysql.user where user = 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N SPECIFIED cipher issuer subject 0 0 0 0 N N 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N SPECIFIED cipher issuer subject 0 0 0 0 N N 0.000000 drop user foo; create user foo, foo2 identified by 'password' require CIPHER 'cipher' AND SUBJECT 'subject' AND ISSUER 'issuer'; select * from mysql.user where user like 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo N N N N N N N N N N N N N N N N N N N N N N N N N N N N N SPECIFIED cipher issuer subject 0 0 0 0 N N 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N SPECIFIED cipher issuer subject 0 0 0 0 N N 0.000000 #--warning ER_USER_CREATE_EXISTS create user if not exists foo, foo2 identified by 'password2' require CIPHER 'cipher2' AND SUBJECT 'subject2' AND ISSUER 'issuer2'; @@ -59,14 +59,14 @@ Warnings: Note 1973 Can't create user 'foo'@'%'; it already exists Note 1973 Can't create user 'foo2'@'%'; it already exists select * from mysql.user where user like 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo N N N N N N N N N N N N N N N N N N N N N N N N N N N N N SPECIFIED cipher issuer subject 0 0 0 0 N N 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N SPECIFIED cipher issuer subject 0 0 0 0 N N 0.000000 drop user foo, foo2; create user foo with MAX_QUERIES_PER_HOUR 10 MAX_UPDATES_PER_HOUR 20 MAX_CONNECTIONS_PER_HOUR 30 MAX_USER_CONNECTIONS 40; select * from mysql.user where user like 'foo'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time -% foo N N N N N N N N N N N N N N N N N N N N N N N N N N N N N 10 20 30 40 N N 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time +% foo N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N 10 20 30 40 N N 0.000000 drop user foo; diff --git a/mysql-test/r/events_grant.result b/mysql-test/r/events_grant.result index a054e58494b..51b80742737 100644 --- a/mysql-test/r/events_grant.result +++ b/mysql-test/r/events_grant.result @@ -23,7 +23,7 @@ SHOW GRANTS; Grants for ev_test@localhost GRANT USAGE ON *.* TO 'ev_test'@'localhost' GRANT ALL PRIVILEGES ON `events_test`.* TO 'ev_test'@'localhost' -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, TRIGGER ON `events_test2`.* TO 'ev_test'@'localhost' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, TRIGGER, DELETE VERSIONING ROWS ON `events_test2`.* TO 'ev_test'@'localhost' "Here comes an error:"; SHOW EVENTS; ERROR 42000: Access denied for user 'ev_test'@'localhost' to database 'events_test2' diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index 593d998754a..11488bcc630 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -49,6 +49,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type SPECIFIED ssl_cipher EDH-RSA-DES-CBC3-SHA x509_issuer @@ -124,6 +125,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -175,6 +177,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -223,7 +226,7 @@ revoke LOCK TABLES, ALTER on mysqltest.* from mysqltest_1@localhost; show grants for mysqltest_1@localhost; Grants for mysqltest_1@localhost GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, CREATE TEMPORARY TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER ON `mysqltest`.* TO 'mysqltest_1'@'localhost' WITH GRANT OPTION +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, CREATE TEMPORARY TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE VERSIONING ROWS ON `mysqltest`.* TO 'mysqltest_1'@'localhost' WITH GRANT OPTION revoke all privileges on mysqltest.* from mysqltest_1@localhost; delete from mysql.user where user='mysqltest_1'; flush privileges; @@ -609,6 +612,7 @@ Create temporary tables Databases To use CREATE TEMPORARY TABLE Create view Tables To create new views Create user Server Admin To create new users Delete Tables To delete existing rows +Delete versioning rows Tables To delete versioning table historical rows Drop Databases,Tables To drop databases, tables, and views Event Server Admin To create, alter, drop and execute events Execute Functions,Procedures To execute stored routines @@ -664,8 +668,8 @@ SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE = '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME; TABLE_SCHEMA TABLE_NAME PRIVILEGES -mysqltest dummytable ALTER, CREATE, CREATE VIEW, DELETE, DROP, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, TRIGGER, UPDATE -mysqltest dummyview ALTER, CREATE, CREATE VIEW, DELETE, DROP, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, TRIGGER, UPDATE +mysqltest dummytable ALTER, CREATE, CREATE VIEW, DELETE, DELETE VERSIONING ROWS, DROP, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, TRIGGER, UPDATE +mysqltest dummyview ALTER, CREATE, CREATE VIEW, DELETE, DELETE VERSIONING ROWS, DROP, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, TRIGGER, UPDATE FLUSH PRIVILEGES; SHOW GRANTS FOR dummy@localhost; Grants for dummy@localhost @@ -676,8 +680,8 @@ SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE = '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME; TABLE_SCHEMA TABLE_NAME PRIVILEGES -mysqltest dummytable ALTER, CREATE, CREATE VIEW, DELETE, DROP, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, TRIGGER, UPDATE -mysqltest dummyview ALTER, CREATE, CREATE VIEW, DELETE, DROP, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, TRIGGER, UPDATE +mysqltest dummytable ALTER, CREATE, CREATE VIEW, DELETE, DELETE VERSIONING ROWS, DROP, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, TRIGGER, UPDATE +mysqltest dummyview ALTER, CREATE, CREATE VIEW, DELETE, DELETE VERSIONING ROWS, DROP, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, TRIGGER, UPDATE SHOW FIELDS FROM mysql.tables_priv; Field Type Null Key Default Extra Host char(60) NO PRI @@ -686,7 +690,7 @@ User char(80) NO PRI Table_name char(64) NO PRI Grantor char(141) NO MUL Timestamp timestamp NO current_timestamp() on update current_timestamp() -Table_priv set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view','Trigger') NO +Table_priv set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view','Trigger','Delete versioning rows') NO Column_priv set('Select','Insert','Update','References') NO use test; REVOKE ALL PRIVILEGES, GRANT OPTION FROM dummy@localhost; @@ -769,7 +773,7 @@ flush privileges; use test; set @user123="non-existent"; select * from mysql.db where user=@user123; -Host Db User Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Grant_priv References_priv Index_priv Alter_priv Create_tmp_table_priv Lock_tables_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Execute_priv Event_priv Trigger_priv +Host Db User Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Grant_priv References_priv Index_priv Alter_priv Create_tmp_table_priv Lock_tables_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Execute_priv Event_priv Trigger_priv Delete_versioning_rows_priv set names koi8r; create database ÂÄ; grant select on ÂÄ.* to root@localhost; diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 6a6b5e0616a..4e1b8c1adff 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -488,6 +488,7 @@ GRANTEE TABLE_CATALOG TABLE_SCHEMA PRIVILEGE_TYPE IS_GRANTABLE 'mysqltest_1'@'localhost' def test ALTER ROUTINE YES 'mysqltest_1'@'localhost' def test EVENT YES 'mysqltest_1'@'localhost' def test TRIGGER YES +'mysqltest_1'@'localhost' def test DELETE VERSIONING ROWS YES select * from information_schema.TABLE_PRIVILEGES where grantee like '%mysqltest_1%'; GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PRIVILEGE_TYPE IS_GRANTABLE 'mysqltest_1'@'localhost' def test t1 SELECT NO @@ -744,6 +745,7 @@ Lock_tables_priv select,insert,update,references Show_view_priv select,insert,update,references Create_routine_priv select,insert,update,references Alter_routine_priv select,insert,update,references +Delete_versioning_rows_priv select,insert,update,references max_questions select,insert,update,references max_connections select,insert,update,references max_user_connections select,insert,update,references diff --git a/mysql-test/r/lowercase_table_grant.result b/mysql-test/r/lowercase_table_grant.result index 009965c0c8e..7e2ac238cf7 100644 --- a/mysql-test/r/lowercase_table_grant.result +++ b/mysql-test/r/lowercase_table_grant.result @@ -7,8 +7,8 @@ Grants for mysqltest_1@localhost GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' GRANT ALL PRIVILEGES ON `mysqltest`.* TO 'mysqltest_1'@'localhost' select * from db where user = 'mysqltest_1'; -Host Db User Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Grant_priv References_priv Index_priv Alter_priv Create_tmp_table_priv Lock_tables_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Execute_priv Event_priv Trigger_priv -localhost mysqltest mysqltest_1 Y Y Y Y Y Y N Y Y Y Y Y Y Y Y Y Y Y Y +Host Db User Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Grant_priv References_priv Index_priv Alter_priv Create_tmp_table_priv Lock_tables_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Execute_priv Event_priv Trigger_priv Delete_versioning_rows_priv +localhost mysqltest mysqltest_1 Y Y Y Y Y Y N Y Y Y Y Y Y Y Y Y Y Y Y Y update db set db = 'MYSQLtest' where db = 'mysqltest' and user = 'mysqltest_1' and host = 'localhost'; flush privileges; show grants for mysqltest_1@localhost; @@ -16,8 +16,8 @@ Grants for mysqltest_1@localhost GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' GRANT ALL PRIVILEGES ON `mysqltest`.* TO 'mysqltest_1'@'localhost' select * from db where user = 'mysqltest_1'; -Host Db User Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Grant_priv References_priv Index_priv Alter_priv Create_tmp_table_priv Lock_tables_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Execute_priv Event_priv Trigger_priv -localhost MYSQLtest mysqltest_1 Y Y Y Y Y Y N Y Y Y Y Y Y Y Y Y Y Y Y +Host Db User Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Grant_priv References_priv Index_priv Alter_priv Create_tmp_table_priv Lock_tables_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Execute_priv Event_priv Trigger_priv Delete_versioning_rows_priv +localhost MYSQLtest mysqltest_1 Y Y Y Y Y Y N Y Y Y Y Y Y Y Y Y Y Y Y Y delete from db where db = 'MYSQLtest' and user = 'mysqltest_1' and host = 'localhost'; flush privileges; drop user mysqltest_1@localhost; diff --git a/mysql-test/r/no_password_column-mdev-11170.result b/mysql-test/r/no_password_column-mdev-11170.result index 81eecc95558..7336244e9f3 100644 --- a/mysql-test/r/no_password_column-mdev-11170.result +++ b/mysql-test/r/no_password_column-mdev-11170.result @@ -42,6 +42,7 @@ Create_user_priv enum('N','Y') NO N Event_priv enum('N','Y') NO N Trigger_priv enum('N','Y') NO N Create_tablespace_priv enum('N','Y') NO N +Delete_versioning_rows_priv enum('N','Y') NO N ssl_type enum('','ANY','X509','SPECIFIED') NO ssl_cipher blob NO NULL x509_issuer blob NO NULL diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 317ba5a3283..f7e5f4394b8 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -1207,21 +1207,21 @@ SET @aux= "SELECT COUNT(*) prepare my_stmt from @aux; execute my_stmt; COUNT(*) -46 +47 Warnings: Warning 1286 Unknown storage engine 'InnoDB' Warning 1286 Unknown storage engine 'InnoDB' Warning 1286 Unknown storage engine 'InnoDB' execute my_stmt; COUNT(*) -46 +47 Warnings: Warning 1286 Unknown storage engine 'InnoDB' Warning 1286 Unknown storage engine 'InnoDB' Warning 1286 Unknown storage engine 'InnoDB' execute my_stmt; COUNT(*) -46 +47 Warnings: Warning 1286 Unknown storage engine 'InnoDB' Warning 1286 Unknown storage engine 'InnoDB' diff --git a/mysql-test/r/sql_mode.result b/mysql-test/r/sql_mode.result index 7c881fd5ad5..22189dad0db 100644 --- a/mysql-test/r/sql_mode.result +++ b/mysql-test/r/sql_mode.result @@ -531,7 +531,7 @@ SET SESSION SQL_MODE = @OLD_SQL_MODE; DROP USER 'user_no_PCTFL'@'localhost'; FLUSH PRIVILEGES; SELECT * FROM mysql.db WHERE Host = 'localhost' AND User LIKE 'user_%PCTFL'; -Host Db User Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Grant_priv References_priv Index_priv Alter_priv Create_tmp_table_priv Lock_tables_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Execute_priv Event_priv Trigger_priv +Host Db User Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Grant_priv References_priv Index_priv Alter_priv Create_tmp_table_priv Lock_tables_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Execute_priv Event_priv Trigger_priv Delete_versioning_rows_priv SELECT * FROM mysql.tables_priv WHERE Host = 'localhost' AND User LIKE 'user_%PCTFL'; Host Db User Table_name Grantor Timestamp Table_priv Column_priv SELECT * FROM mysql.columns_priv WHERE Host = 'localhost' AND User LIKE 'user_%PCTFL'; diff --git a/mysql-test/r/system_mysql_db.result b/mysql-test/r/system_mysql_db.result index 558b552e2fd..4f4926ae61b 100644 --- a/mysql-test/r/system_mysql_db.result +++ b/mysql-test/r/system_mysql_db.result @@ -56,6 +56,7 @@ db CREATE TABLE `db` ( `Execute_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Event_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Trigger_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Delete_versioning_rows_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', PRIMARY KEY (`Host`,`Db`,`User`), KEY `User` (`User`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Database privileges' @@ -119,6 +120,7 @@ user CREATE TABLE `user` ( `Event_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Trigger_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Create_tablespace_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Delete_versioning_rows_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `ssl_type` enum('','ANY','X509','SPECIFIED') CHARACTER SET utf8 NOT NULL DEFAULT '', `ssl_cipher` blob NOT NULL, `x509_issuer` blob NOT NULL, @@ -153,7 +155,7 @@ tables_priv CREATE TABLE `tables_priv` ( `Table_name` char(64) COLLATE utf8_bin NOT NULL DEFAULT '', `Grantor` char(141) COLLATE utf8_bin NOT NULL DEFAULT '', `Timestamp` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), - `Table_priv` set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view','Trigger') CHARACTER SET utf8 NOT NULL DEFAULT '', + `Table_priv` set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view','Trigger','Delete versioning rows') CHARACTER SET utf8 NOT NULL DEFAULT '', `Column_priv` set('Select','Insert','Update','References') CHARACTER SET utf8 NOT NULL DEFAULT '', PRIMARY KEY (`Host`,`Db`,`User`,`Table_name`), KEY `Grantor` (`Grantor`) diff --git a/mysql-test/r/system_mysql_db_fix40123.result b/mysql-test/r/system_mysql_db_fix40123.result index 558b552e2fd..ad33a9dd75f 100644 --- a/mysql-test/r/system_mysql_db_fix40123.result +++ b/mysql-test/r/system_mysql_db_fix40123.result @@ -56,6 +56,7 @@ db CREATE TABLE `db` ( `Execute_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Event_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Trigger_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Delete_versioning_rows_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', PRIMARY KEY (`Host`,`Db`,`User`), KEY `User` (`User`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Database privileges' @@ -118,6 +119,7 @@ user CREATE TABLE `user` ( `Create_user_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Event_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Trigger_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Delete_versioning_rows_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Create_tablespace_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `ssl_type` enum('','ANY','X509','SPECIFIED') CHARACTER SET utf8 NOT NULL DEFAULT '', `ssl_cipher` blob NOT NULL, @@ -153,7 +155,7 @@ tables_priv CREATE TABLE `tables_priv` ( `Table_name` char(64) COLLATE utf8_bin NOT NULL DEFAULT '', `Grantor` char(141) COLLATE utf8_bin NOT NULL DEFAULT '', `Timestamp` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), - `Table_priv` set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view','Trigger') CHARACTER SET utf8 NOT NULL DEFAULT '', + `Table_priv` set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view','Trigger','Delete versioning rows') CHARACTER SET utf8 NOT NULL DEFAULT '', `Column_priv` set('Select','Insert','Update','References') CHARACTER SET utf8 NOT NULL DEFAULT '', PRIMARY KEY (`Host`,`Db`,`User`,`Table_name`), KEY `Grantor` (`Grantor`) diff --git a/mysql-test/r/system_mysql_db_fix50030.result b/mysql-test/r/system_mysql_db_fix50030.result index 17252b09912..2fe786687d9 100644 --- a/mysql-test/r/system_mysql_db_fix50030.result +++ b/mysql-test/r/system_mysql_db_fix50030.result @@ -56,6 +56,7 @@ db CREATE TABLE `db` ( `Execute_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Event_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Trigger_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Delete_versioning_rows_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', PRIMARY KEY (`Host`,`Db`,`User`), KEY `User` (`User`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Database privileges' @@ -118,6 +119,7 @@ user CREATE TABLE `user` ( `Create_user_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Event_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Trigger_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Delete_versioning_rows_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Create_tablespace_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `ssl_type` enum('','ANY','X509','SPECIFIED') CHARACTER SET utf8 NOT NULL DEFAULT '', `ssl_cipher` blob NOT NULL, @@ -153,7 +155,7 @@ tables_priv CREATE TABLE `tables_priv` ( `Table_name` char(64) COLLATE utf8_bin NOT NULL DEFAULT '', `Grantor` char(141) COLLATE utf8_bin NOT NULL DEFAULT '', `Timestamp` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), - `Table_priv` set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view','Trigger') CHARACTER SET utf8 NOT NULL DEFAULT '', + `Table_priv` set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view','Trigger','Delete versioning rows') CHARACTER SET utf8 NOT NULL DEFAULT '', `Column_priv` set('Select','Insert','Update','References') CHARACTER SET utf8 NOT NULL DEFAULT '', PRIMARY KEY (`Host`,`Db`,`User`,`Table_name`), KEY `Grantor` (`Grantor`) diff --git a/mysql-test/r/system_mysql_db_fix50117.result b/mysql-test/r/system_mysql_db_fix50117.result index 558b552e2fd..ad33a9dd75f 100644 --- a/mysql-test/r/system_mysql_db_fix50117.result +++ b/mysql-test/r/system_mysql_db_fix50117.result @@ -56,6 +56,7 @@ db CREATE TABLE `db` ( `Execute_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Event_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Trigger_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Delete_versioning_rows_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', PRIMARY KEY (`Host`,`Db`,`User`), KEY `User` (`User`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Database privileges' @@ -118,6 +119,7 @@ user CREATE TABLE `user` ( `Create_user_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Event_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Trigger_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', + `Delete_versioning_rows_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Create_tablespace_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `ssl_type` enum('','ANY','X509','SPECIFIED') CHARACTER SET utf8 NOT NULL DEFAULT '', `ssl_cipher` blob NOT NULL, @@ -153,7 +155,7 @@ tables_priv CREATE TABLE `tables_priv` ( `Table_name` char(64) COLLATE utf8_bin NOT NULL DEFAULT '', `Grantor` char(141) COLLATE utf8_bin NOT NULL DEFAULT '', `Timestamp` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), - `Table_priv` set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view','Trigger') CHARACTER SET utf8 NOT NULL DEFAULT '', + `Table_priv` set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view','Trigger','Delete versioning rows') CHARACTER SET utf8 NOT NULL DEFAULT '', `Column_priv` set('Select','Insert','Update','References') CHARACTER SET utf8 NOT NULL DEFAULT '', PRIMARY KEY (`Host`,`Db`,`User`,`Table_name`), KEY `Grantor` (`Grantor`) diff --git a/mysql-test/suite/funcs_1/r/innodb_trig_03.result b/mysql-test/suite/funcs_1/r/innodb_trig_03.result index 98f599da3e5..7666b86bc94 100644 --- a/mysql-test/suite/funcs_1/r/innodb_trig_03.result +++ b/mysql-test/suite/funcs_1/r/innodb_trig_03.result @@ -78,7 +78,7 @@ grant ALL on *.* to test_noprivs@localhost; revoke TRIGGER on *.* from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER on *.* to test_yesprivs@localhost; grant SELECT on priv_db.t1 to test_yesprivs@localhost; @@ -168,7 +168,7 @@ grant ALL on *.* to test_noprivs@localhost; revoke UPDATE on *.* from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost -GRANT SELECT, INSERT, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER, UPDATE on *.* to test_yesprivs@localhost; show grants for test_yesprivs@localhost; @@ -183,7 +183,7 @@ test_noprivs@localhost use priv_db; show grants; Grants for test_noprivs@localhost -GRANT SELECT, INSERT, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' select f1 from t1 order by f1; f1 insert 3.5.3.2-no @@ -248,7 +248,7 @@ connection no_privs_424b; show grants; Grants for test_noprivs@localhost GRANT USAGE ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT SELECT, INSERT, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER ON `priv_db`.* TO 'test_noprivs'@'localhost' +GRANT SELECT, INSERT, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.* TO 'test_noprivs'@'localhost' use priv_db; create trigger trg4b_1 before UPDATE on t1 for each row set new.f1 = 'trig 3.5.3.7-1b'; @@ -329,7 +329,7 @@ connection no_privs_424c; show grants; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT SELECT, INSERT, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' +GRANT SELECT, INSERT, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' use priv_db; create trigger trg4c_1 before INSERT on t1 for each row set new.f1 = 'trig 3.5.3.7-1c'; @@ -441,7 +441,7 @@ grant ALL on *.* to test_noprivs@localhost; revoke SELECT on *.* from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER, SELECT on *.* to test_yesprivs@localhost; show grants for test_yesprivs@localhost; @@ -457,7 +457,7 @@ test_noprivs@localhost use priv_db; show grants; Grants for test_noprivs@localhost -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' create trigger trg5a_1 before INSERT on t1 for each row set @test_var = new.f1; connection default; @@ -503,7 +503,7 @@ revoke SELECT on priv_db.* from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER ON `priv_db`.* TO 'test_noprivs'@'localhost' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.* TO 'test_noprivs'@'localhost' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER on *.* to test_yesprivs@localhost; grant SELECT on priv_db.* to test_yesprivs@localhost; @@ -518,7 +518,7 @@ connection no_privs_425b; show grants; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER ON `priv_db`.* TO 'test_noprivs'@'localhost' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.* TO 'test_noprivs'@'localhost' use priv_db; create trigger trg5b_1 before UPDATE on t1 for each row set @test_var= new.f1; @@ -565,7 +565,7 @@ revoke SELECT on priv_db.t1 from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER on *.* to test_yesprivs@localhost; grant SELECT on priv_db.t1 to test_yesprivs@localhost; @@ -580,7 +580,7 @@ connection no_privs_425c; show grants; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' use priv_db; create trigger trg5c_1 before INSERT on t1 for each row set @test_var= new.f1; diff --git a/mysql-test/suite/funcs_1/r/innodb_trig_03e.result b/mysql-test/suite/funcs_1/r/innodb_trig_03e.result index b29c0271fdc..90dabe044e8 100644 --- a/mysql-test/suite/funcs_1/r/innodb_trig_03e.result +++ b/mysql-test/suite/funcs_1/r/innodb_trig_03e.result @@ -603,7 +603,7 @@ trig 1_1-yes revoke TRIGGER on *.* from test_yesprivs@localhost; show grants for test_yesprivs@localhost; Grants for test_yesprivs@localhost -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' disconnect yes_privs; connect yes_privs,localhost,test_yesprivs,PWD,test,$MASTER_MYPORT,$MASTER_MYSOCK; select current_user; @@ -656,7 +656,7 @@ root@localhost grant TRIGGER on priv_db.* to test_yesprivs@localhost; show grants for test_yesprivs@localhost; Grants for test_yesprivs@localhost -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' GRANT TRIGGER ON `priv_db`.* TO 'test_yesprivs'@'localhost' trigger privilege on db level for create: @@ -929,7 +929,7 @@ grant TRIGGER on priv1_db.t1 to test_yesprivs@localhost; show grants for test_yesprivs@localhost; Grants for test_yesprivs@localhost GRANT USAGE ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT ON `priv1_db`.* TO 'test_yesprivs'@'localhost' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, DELETE VERSIONING ROWS ON `priv1_db`.* TO 'test_yesprivs'@'localhost' GRANT SELECT, UPDATE ON `priv2_db`.* TO 'test_yesprivs'@'localhost' GRANT TRIGGER ON `priv1_db`.`t1` TO 'test_yesprivs'@'localhost' diff --git a/mysql-test/suite/funcs_1/r/is_column_privileges.result b/mysql-test/suite/funcs_1/r/is_column_privileges.result index a56ef002935..033fb64f689 100644 --- a/mysql-test/suite/funcs_1/r/is_column_privileges.result +++ b/mysql-test/suite/funcs_1/r/is_column_privileges.result @@ -140,6 +140,7 @@ GRANTEE TABLE_CATALOG TABLE_SCHEMA PRIVILEGE_TYPE IS_GRANTABLE 'testuser3'@'localhost' def db_datadict CREATE TEMPORARY TABLES NO 'testuser3'@'localhost' def db_datadict CREATE VIEW NO 'testuser3'@'localhost' def db_datadict DELETE NO +'testuser3'@'localhost' def db_datadict DELETE VERSIONING ROWS NO 'testuser3'@'localhost' def db_datadict DROP NO 'testuser3'@'localhost' def db_datadict EVENT NO 'testuser3'@'localhost' def db_datadict EXECUTE NO diff --git a/mysql-test/suite/funcs_1/r/is_columns_mysql.result b/mysql-test/suite/funcs_1/r/is_columns_mysql.result index 6bff05c05ae..04db42cd138 100644 --- a/mysql-test/suite/funcs_1/r/is_columns_mysql.result +++ b/mysql-test/suite/funcs_1/r/is_columns_mysql.result @@ -28,6 +28,7 @@ def mysql db Create_tmp_table_priv 14 N NO enum 1 3 NULL NULL NULL utf8 utf8_gen def mysql db Create_view_priv 16 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL def mysql db Db 2 NO char 64 192 NULL NULL NULL utf8 utf8_bin char(64) PRI select,insert,update,references NEVER NULL def mysql db Delete_priv 7 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL +def mysql db Delete_versioning_rows_priv 23 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL def mysql db Drop_priv 9 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL def mysql db Event_priv 21 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL def mysql db Execute_priv 20 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL @@ -199,7 +200,7 @@ def mysql tables_priv Db 2 NO char 64 192 NULL NULL NULL utf8 utf8_bin char(64) def mysql tables_priv Grantor 5 NO char 141 423 NULL NULL NULL utf8 utf8_bin char(141) MUL select,insert,update,references NEVER NULL def mysql tables_priv Host 1 NO char 60 180 NULL NULL NULL utf8 utf8_bin char(60) PRI select,insert,update,references NEVER NULL def mysql tables_priv Table_name 4 NO char 64 192 NULL NULL NULL utf8 utf8_bin char(64) PRI select,insert,update,references NEVER NULL -def mysql tables_priv Table_priv 7 NO set 98 294 NULL NULL NULL utf8 utf8_general_ci set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view','Trigger') select,insert,update,references NEVER NULL +def mysql tables_priv Table_priv 7 NO set 121 363 NULL NULL NULL utf8 utf8_general_ci set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view','Trigger','Delete versioning rows') select,insert,update,references NEVER NULL def mysql tables_priv Timestamp 6 current_timestamp() NO timestamp NULL NULL NULL NULL 0 NULL NULL timestamp on update current_timestamp() select,insert,update,references NEVER NULL def mysql tables_priv User 3 NO char 80 240 NULL NULL NULL utf8 utf8_bin char(80) PRI select,insert,update,references NEVER NULL def mysql table_stats cardinality 3 NULL YES bigint NULL NULL 20 0 NULL NULL NULL bigint(21) unsigned select,insert,update,references NEVER NULL @@ -221,15 +222,16 @@ def mysql time_zone_transition_type Time_zone_id 1 NULL NO int NULL NULL 10 0 NU def mysql time_zone_transition_type Transition_type_id 2 NULL NO int NULL NULL 10 0 NULL NULL NULL int(10) unsigned PRI select,insert,update,references NEVER NULL def mysql user Alter_priv 17 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL def mysql user Alter_routine_priv 28 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL -def mysql user authentication_string 42 NULL NO text 65535 65535 NULL NULL NULL utf8 utf8_bin text select,insert,update,references NEVER NULL +def mysql user authentication_string 43 NULL NO text 65535 65535 NULL NULL NULL utf8 utf8_bin text select,insert,update,references NEVER NULL def mysql user Create_priv 8 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL def mysql user Create_routine_priv 27 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL def mysql user Create_tablespace_priv 32 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL def mysql user Create_tmp_table_priv 20 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL def mysql user Create_user_priv 29 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL def mysql user Create_view_priv 25 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL -def mysql user default_role 45 NO char 80 240 NULL NULL NULL utf8 utf8_bin char(80) select,insert,update,references NEVER NULL +def mysql user default_role 46 NO char 80 240 NULL NULL NULL utf8 utf8_bin char(80) select,insert,update,references NEVER NULL def mysql user Delete_priv 7 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL +def mysql user Delete_versioning_rows_priv 33 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL def mysql user Drop_priv 9 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL def mysql user Event_priv 30 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL def mysql user Execute_priv 22 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL @@ -238,16 +240,16 @@ def mysql user Grant_priv 14 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci e def mysql user Host 1 NO char 60 180 NULL NULL NULL utf8 utf8_bin char(60) PRI select,insert,update,references NEVER NULL def mysql user Index_priv 16 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL def mysql user Insert_priv 5 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL -def mysql user is_role 44 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL +def mysql user is_role 45 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL def mysql user Lock_tables_priv 21 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL -def mysql user max_connections 39 0 NO int NULL NULL 10 0 NULL NULL NULL int(11) unsigned select,insert,update,references NEVER NULL -def mysql user max_questions 37 0 NO int NULL NULL 10 0 NULL NULL NULL int(11) unsigned select,insert,update,references NEVER NULL -def mysql user max_statement_time 46 0.000000 NO decimal NULL NULL 12 6 NULL NULL NULL decimal(12,6) select,insert,update,references NEVER NULL -def mysql user max_updates 38 0 NO int NULL NULL 10 0 NULL NULL NULL int(11) unsigned select,insert,update,references NEVER NULL -def mysql user max_user_connections 40 0 NO int NULL NULL 10 0 NULL NULL NULL int(11) select,insert,update,references NEVER NULL +def mysql user max_connections 40 0 NO int NULL NULL 10 0 NULL NULL NULL int(11) unsigned select,insert,update,references NEVER NULL +def mysql user max_questions 38 0 NO int NULL NULL 10 0 NULL NULL NULL int(11) unsigned select,insert,update,references NEVER NULL +def mysql user max_statement_time 47 0.000000 NO decimal NULL NULL 12 6 NULL NULL NULL decimal(12,6) select,insert,update,references NEVER NULL +def mysql user max_updates 39 0 NO int NULL NULL 10 0 NULL NULL NULL int(11) unsigned select,insert,update,references NEVER NULL +def mysql user max_user_connections 41 0 NO int NULL NULL 10 0 NULL NULL NULL int(11) select,insert,update,references NEVER NULL def mysql user Password 3 NO char 41 41 NULL NULL NULL latin1 latin1_bin char(41) select,insert,update,references NEVER NULL -def mysql user password_expired 43 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL -def mysql user plugin 41 NO char 64 64 NULL NULL NULL latin1 latin1_swedish_ci char(64) select,insert,update,references NEVER NULL +def mysql user password_expired 44 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL +def mysql user plugin 42 NO char 64 64 NULL NULL NULL latin1 latin1_swedish_ci char(64) select,insert,update,references NEVER NULL def mysql user Process_priv 12 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL def mysql user References_priv 15 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL def mysql user Reload_priv 10 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL @@ -257,14 +259,14 @@ def mysql user Select_priv 4 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci e def mysql user Show_db_priv 18 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL def mysql user Show_view_priv 26 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL def mysql user Shutdown_priv 11 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL -def mysql user ssl_cipher 34 NULL NO blob 65535 65535 NULL NULL NULL NULL NULL blob select,insert,update,references NEVER NULL -def mysql user ssl_type 33 NO enum 9 27 NULL NULL NULL utf8 utf8_general_ci enum('','ANY','X509','SPECIFIED') select,insert,update,references NEVER NULL +def mysql user ssl_cipher 35 NULL NO blob 65535 65535 NULL NULL NULL NULL NULL blob select,insert,update,references NEVER NULL +def mysql user ssl_type 34 NO enum 9 27 NULL NULL NULL utf8 utf8_general_ci enum('','ANY','X509','SPECIFIED') select,insert,update,references NEVER NULL def mysql user Super_priv 19 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL def mysql user Trigger_priv 31 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL def mysql user Update_priv 6 N NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL def mysql user User 2 NO char 80 240 NULL NULL NULL utf8 utf8_bin char(80) PRI select,insert,update,references NEVER NULL -def mysql user x509_issuer 35 NULL NO blob 65535 65535 NULL NULL NULL NULL NULL blob select,insert,update,references NEVER NULL -def mysql user x509_subject 36 NULL NO blob 65535 65535 NULL NULL NULL NULL NULL blob select,insert,update,references NEVER NULL +def mysql user x509_issuer 36 NULL NO blob 65535 65535 NULL NULL NULL NULL NULL blob select,insert,update,references NEVER NULL +def mysql user x509_subject 37 NULL NO blob 65535 65535 NULL NULL NULL NULL NULL blob select,insert,update,references NEVER NULL def mysql vtmd_template archive_name 4 NULL YES varchar 64 192 NULL NULL NULL utf8 utf8_bin varchar(64) MUL select,insert,update,references Name of archive table NEVER NULL def mysql vtmd_template col_renames 5 NULL YES blob 65535 65535 NULL NULL NULL NULL NULL blob select,insert,update,references Column name mappings from previous lifetime NEVER NULL def mysql vtmd_template end 2 NULL NO bigint NULL NULL 20 0 NULL NULL NULL bigint(20) unsigned PRI select,insert,update,references TRX_ID of table lifetime end NEVER NULL @@ -382,6 +384,7 @@ NULL mysql column_stats hist_size tinyint NULL NULL NULL NULL tinyint(3) unsigne 3.0000 mysql db Execute_priv enum 1 3 utf8 utf8_general_ci enum('N','Y') 3.0000 mysql db Event_priv enum 1 3 utf8 utf8_general_ci enum('N','Y') 3.0000 mysql db Trigger_priv enum 1 3 utf8 utf8_general_ci enum('N','Y') +3.0000 mysql db Delete_versioning_rows_priv enum 1 3 utf8 utf8_general_ci enum('N','Y') 3.0000 mysql event db char 64 192 utf8 utf8_bin char(64) 3.0000 mysql event name char 64 192 utf8 utf8_general_ci char(64) 1.0000 mysql event body longblob 4294967295 4294967295 NULL NULL longblob @@ -540,7 +543,7 @@ NULL mysql slow_log rows_affected int NULL NULL NULL NULL int(11) 3.0000 mysql tables_priv Table_name char 64 192 utf8 utf8_bin char(64) 3.0000 mysql tables_priv Grantor char 141 423 utf8 utf8_bin char(141) NULL mysql tables_priv Timestamp timestamp NULL NULL NULL NULL timestamp -3.0000 mysql tables_priv Table_priv set 98 294 utf8 utf8_general_ci set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view','Trigger') +3.0000 mysql tables_priv Table_priv set 121 363 utf8 utf8_general_ci set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view','Trigger','Delete versioning rows') 3.0000 mysql tables_priv Column_priv set 31 93 utf8 utf8_general_ci set('Select','Insert','Update','References') 3.0000 mysql table_stats db_name varchar 64 192 utf8 utf8_bin varchar(64) 3.0000 mysql table_stats table_name varchar 64 192 utf8 utf8_bin varchar(64) @@ -591,6 +594,7 @@ NULL mysql time_zone_transition_type Is_DST tinyint NULL NULL NULL NULL tinyint( 3.0000 mysql user Event_priv enum 1 3 utf8 utf8_general_ci enum('N','Y') 3.0000 mysql user Trigger_priv enum 1 3 utf8 utf8_general_ci enum('N','Y') 3.0000 mysql user Create_tablespace_priv enum 1 3 utf8 utf8_general_ci enum('N','Y') +3.0000 mysql user Delete_versioning_rows_priv enum 1 3 utf8 utf8_general_ci enum('N','Y') 3.0000 mysql user ssl_type enum 9 27 utf8 utf8_general_ci enum('','ANY','X509','SPECIFIED') 1.0000 mysql user ssl_cipher blob 65535 65535 NULL NULL blob 1.0000 mysql user x509_issuer blob 65535 65535 NULL NULL blob diff --git a/mysql-test/suite/funcs_1/r/is_schema_privileges.result b/mysql-test/suite/funcs_1/r/is_schema_privileges.result index cf9b70308de..1339639106f 100644 --- a/mysql-test/suite/funcs_1/r/is_schema_privileges.result +++ b/mysql-test/suite/funcs_1/r/is_schema_privileges.result @@ -68,6 +68,7 @@ GRANTEE TABLE_CATALOG TABLE_SCHEMA PRIVILEGE_TYPE ''@'%' def test CREATE ROUTINE ''@'%' def test EVENT ''@'%' def test TRIGGER +''@'%' def test DELETE VERSIONING ROWS ''@'%' def test\_% SELECT ''@'%' def test\_% INSERT ''@'%' def test\_% UPDATE @@ -84,6 +85,7 @@ GRANTEE TABLE_CATALOG TABLE_SCHEMA PRIVILEGE_TYPE ''@'%' def test\_% CREATE ROUTINE ''@'%' def test\_% EVENT ''@'%' def test\_% TRIGGER +''@'%' def test\_% DELETE VERSIONING ROWS ############################################################################### # Testcase 3.2.15.2-3.2.15.4 INFORMATION_SCHEMA.SCHEMA_PRIVILEGES accessibility ############################################################################### diff --git a/mysql-test/suite/funcs_1/r/is_schema_privileges_is_mysql_test.result b/mysql-test/suite/funcs_1/r/is_schema_privileges_is_mysql_test.result index 38257899a4b..528a770e0eb 100644 --- a/mysql-test/suite/funcs_1/r/is_schema_privileges_is_mysql_test.result +++ b/mysql-test/suite/funcs_1/r/is_schema_privileges_is_mysql_test.result @@ -16,6 +16,7 @@ GRANTEE TABLE_CATALOG TABLE_SCHEMA PRIVILEGE_TYPE IS_GRANTABLE ''@'%' def test CREATE TEMPORARY TABLES NO ''@'%' def test CREATE VIEW NO ''@'%' def test DELETE NO +''@'%' def test DELETE VERSIONING ROWS NO ''@'%' def test DROP NO ''@'%' def test EVENT NO ''@'%' def test INDEX NO diff --git a/mysql-test/suite/funcs_1/r/is_table_privileges.result b/mysql-test/suite/funcs_1/r/is_table_privileges.result index 340aead9aba..c448241e14e 100644 --- a/mysql-test/suite/funcs_1/r/is_table_privileges.result +++ b/mysql-test/suite/funcs_1/r/is_table_privileges.result @@ -96,6 +96,7 @@ GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PRIVILEGE_TYPE IS_GRANTABLE 'testuser2'@'localhost' def db_datadict tb1 CREATE YES 'testuser2'@'localhost' def db_datadict tb1 CREATE VIEW YES 'testuser2'@'localhost' def db_datadict tb1 DELETE YES +'testuser2'@'localhost' def db_datadict tb1 DELETE VERSIONING ROWS YES 'testuser2'@'localhost' def db_datadict tb1 DROP YES 'testuser2'@'localhost' def db_datadict tb1 INDEX YES 'testuser2'@'localhost' def db_datadict tb1 INSERT YES @@ -131,6 +132,7 @@ GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PRIVILEGE_TYPE IS_GRANTABLE 'testuser2'@'localhost' def db_datadict tb1 CREATE YES 'testuser2'@'localhost' def db_datadict tb1 CREATE VIEW YES 'testuser2'@'localhost' def db_datadict tb1 DELETE YES +'testuser2'@'localhost' def db_datadict tb1 DELETE VERSIONING ROWS YES 'testuser2'@'localhost' def db_datadict tb1 DROP YES 'testuser2'@'localhost' def db_datadict tb1 INDEX YES 'testuser2'@'localhost' def db_datadict tb1 INSERT YES @@ -184,6 +186,7 @@ GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PRIVILEGE_TYPE IS_GRANTABLE 'testuser1'@'localhost' def test t1_table CREATE NO 'testuser1'@'localhost' def test t1_table CREATE VIEW NO 'testuser1'@'localhost' def test t1_table DELETE NO +'testuser1'@'localhost' def test t1_table DELETE VERSIONING ROWS NO 'testuser1'@'localhost' def test t1_table DROP NO 'testuser1'@'localhost' def test t1_table INDEX NO 'testuser1'@'localhost' def test t1_table INSERT NO @@ -196,6 +199,7 @@ GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PRIVILEGE_TYPE IS_GRANTABLE 'testuser1'@'localhost' def test t1_view CREATE NO 'testuser1'@'localhost' def test t1_view CREATE VIEW NO 'testuser1'@'localhost' def test t1_view DELETE NO +'testuser1'@'localhost' def test t1_view DELETE VERSIONING ROWS NO 'testuser1'@'localhost' def test t1_view DROP NO 'testuser1'@'localhost' def test t1_view INDEX NO 'testuser1'@'localhost' def test t1_view INSERT NO diff --git a/mysql-test/suite/funcs_1/r/is_triggers.result b/mysql-test/suite/funcs_1/r/is_triggers.result index d20eeb9a319..9be16c89001 100644 --- a/mysql-test/suite/funcs_1/r/is_triggers.result +++ b/mysql-test/suite/funcs_1/r/is_triggers.result @@ -144,7 +144,7 @@ connect testuser2, localhost, testuser2, , db_datadict; SHOW GRANTS FOR 'testuser2'@'localhost'; Grants for testuser2@localhost GRANT USAGE ON *.* TO 'testuser2'@'localhost' -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW ON `db_datadict`.`t1` TO 'testuser2'@'localhost' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, DELETE VERSIONING ROWS ON `db_datadict`.`t1` TO 'testuser2'@'localhost' # No TRIGGER Privilege --> no result for query SELECT * FROM information_schema.triggers WHERE trigger_name = 'trg1'; diff --git a/mysql-test/suite/funcs_1/r/is_user_privileges.result b/mysql-test/suite/funcs_1/r/is_user_privileges.result index a300a1f73e7..655b6d9e209 100644 --- a/mysql-test/suite/funcs_1/r/is_user_privileges.result +++ b/mysql-test/suite/funcs_1/r/is_user_privileges.result @@ -119,6 +119,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -165,6 +166,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -211,6 +213,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -281,6 +284,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -327,6 +331,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -373,6 +378,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -429,6 +435,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -475,6 +482,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -521,6 +529,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -599,6 +608,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -645,6 +655,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -691,6 +702,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -761,6 +773,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -807,6 +820,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -853,6 +867,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -909,6 +924,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -955,6 +971,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -1001,6 +1018,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -1109,6 +1127,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -1155,6 +1174,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -1201,6 +1221,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -1304,6 +1325,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -1350,6 +1372,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -1396,6 +1419,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -1452,6 +1476,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -1498,6 +1523,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -1544,6 +1570,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -1607,6 +1634,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -1653,6 +1681,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -1699,6 +1728,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -1777,6 +1807,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -1823,6 +1854,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer @@ -1869,6 +1901,7 @@ Create_user_priv N Event_priv N Trigger_priv N Create_tablespace_priv N +Delete_versioning_rows_priv N ssl_type ssl_cipher x509_issuer diff --git a/mysql-test/suite/funcs_1/r/memory_trig_03.result b/mysql-test/suite/funcs_1/r/memory_trig_03.result index 8fd3e034735..b86315a1a7d 100644 --- a/mysql-test/suite/funcs_1/r/memory_trig_03.result +++ b/mysql-test/suite/funcs_1/r/memory_trig_03.result @@ -78,7 +78,7 @@ grant ALL on *.* to test_noprivs@localhost; revoke TRIGGER on *.* from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER on *.* to test_yesprivs@localhost; grant SELECT on priv_db.t1 to test_yesprivs@localhost; @@ -168,7 +168,7 @@ grant ALL on *.* to test_noprivs@localhost; revoke UPDATE on *.* from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost -GRANT SELECT, INSERT, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER, UPDATE on *.* to test_yesprivs@localhost; show grants for test_yesprivs@localhost; @@ -183,7 +183,7 @@ test_noprivs@localhost use priv_db; show grants; Grants for test_noprivs@localhost -GRANT SELECT, INSERT, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' select f1 from t1 order by f1; f1 insert 3.5.3.2-no @@ -248,7 +248,7 @@ connection no_privs_424b; show grants; Grants for test_noprivs@localhost GRANT USAGE ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT SELECT, INSERT, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER ON `priv_db`.* TO 'test_noprivs'@'localhost' +GRANT SELECT, INSERT, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.* TO 'test_noprivs'@'localhost' use priv_db; create trigger trg4b_1 before UPDATE on t1 for each row set new.f1 = 'trig 3.5.3.7-1b'; @@ -329,7 +329,7 @@ connection no_privs_424c; show grants; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT SELECT, INSERT, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' +GRANT SELECT, INSERT, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' use priv_db; create trigger trg4c_1 before INSERT on t1 for each row set new.f1 = 'trig 3.5.3.7-1c'; @@ -441,7 +441,7 @@ grant ALL on *.* to test_noprivs@localhost; revoke SELECT on *.* from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER, SELECT on *.* to test_yesprivs@localhost; show grants for test_yesprivs@localhost; @@ -457,7 +457,7 @@ test_noprivs@localhost use priv_db; show grants; Grants for test_noprivs@localhost -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' create trigger trg5a_1 before INSERT on t1 for each row set @test_var = new.f1; connection default; @@ -503,7 +503,7 @@ revoke SELECT on priv_db.* from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER ON `priv_db`.* TO 'test_noprivs'@'localhost' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.* TO 'test_noprivs'@'localhost' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER on *.* to test_yesprivs@localhost; grant SELECT on priv_db.* to test_yesprivs@localhost; @@ -518,7 +518,7 @@ connection no_privs_425b; show grants; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER ON `priv_db`.* TO 'test_noprivs'@'localhost' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.* TO 'test_noprivs'@'localhost' use priv_db; create trigger trg5b_1 before UPDATE on t1 for each row set @test_var= new.f1; @@ -565,7 +565,7 @@ revoke SELECT on priv_db.t1 from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER on *.* to test_yesprivs@localhost; grant SELECT on priv_db.t1 to test_yesprivs@localhost; @@ -580,7 +580,7 @@ connection no_privs_425c; show grants; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' use priv_db; create trigger trg5c_1 before INSERT on t1 for each row set @test_var= new.f1; diff --git a/mysql-test/suite/funcs_1/r/memory_trig_03e.result b/mysql-test/suite/funcs_1/r/memory_trig_03e.result index 83c36c6294f..ea0aaf0c86f 100644 --- a/mysql-test/suite/funcs_1/r/memory_trig_03e.result +++ b/mysql-test/suite/funcs_1/r/memory_trig_03e.result @@ -604,7 +604,7 @@ trig 1_1-yes revoke TRIGGER on *.* from test_yesprivs@localhost; show grants for test_yesprivs@localhost; Grants for test_yesprivs@localhost -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' disconnect yes_privs; connect yes_privs,localhost,test_yesprivs,PWD,test,$MASTER_MYPORT,$MASTER_MYSOCK; select current_user; @@ -657,7 +657,7 @@ root@localhost grant TRIGGER on priv_db.* to test_yesprivs@localhost; show grants for test_yesprivs@localhost; Grants for test_yesprivs@localhost -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' GRANT TRIGGER ON `priv_db`.* TO 'test_yesprivs'@'localhost' trigger privilege on db level for create: @@ -930,7 +930,7 @@ grant TRIGGER on priv1_db.t1 to test_yesprivs@localhost; show grants for test_yesprivs@localhost; Grants for test_yesprivs@localhost GRANT USAGE ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT ON `priv1_db`.* TO 'test_yesprivs'@'localhost' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, DELETE VERSIONING ROWS ON `priv1_db`.* TO 'test_yesprivs'@'localhost' GRANT SELECT, UPDATE ON `priv2_db`.* TO 'test_yesprivs'@'localhost' GRANT TRIGGER ON `priv1_db`.`t1` TO 'test_yesprivs'@'localhost' diff --git a/mysql-test/suite/funcs_1/r/myisam_trig_03.result b/mysql-test/suite/funcs_1/r/myisam_trig_03.result index 8fd3e034735..b86315a1a7d 100644 --- a/mysql-test/suite/funcs_1/r/myisam_trig_03.result +++ b/mysql-test/suite/funcs_1/r/myisam_trig_03.result @@ -78,7 +78,7 @@ grant ALL on *.* to test_noprivs@localhost; revoke TRIGGER on *.* from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER on *.* to test_yesprivs@localhost; grant SELECT on priv_db.t1 to test_yesprivs@localhost; @@ -168,7 +168,7 @@ grant ALL on *.* to test_noprivs@localhost; revoke UPDATE on *.* from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost -GRANT SELECT, INSERT, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER, UPDATE on *.* to test_yesprivs@localhost; show grants for test_yesprivs@localhost; @@ -183,7 +183,7 @@ test_noprivs@localhost use priv_db; show grants; Grants for test_noprivs@localhost -GRANT SELECT, INSERT, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' select f1 from t1 order by f1; f1 insert 3.5.3.2-no @@ -248,7 +248,7 @@ connection no_privs_424b; show grants; Grants for test_noprivs@localhost GRANT USAGE ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT SELECT, INSERT, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER ON `priv_db`.* TO 'test_noprivs'@'localhost' +GRANT SELECT, INSERT, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.* TO 'test_noprivs'@'localhost' use priv_db; create trigger trg4b_1 before UPDATE on t1 for each row set new.f1 = 'trig 3.5.3.7-1b'; @@ -329,7 +329,7 @@ connection no_privs_424c; show grants; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT SELECT, INSERT, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' +GRANT SELECT, INSERT, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' use priv_db; create trigger trg4c_1 before INSERT on t1 for each row set new.f1 = 'trig 3.5.3.7-1c'; @@ -441,7 +441,7 @@ grant ALL on *.* to test_noprivs@localhost; revoke SELECT on *.* from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER, SELECT on *.* to test_yesprivs@localhost; show grants for test_yesprivs@localhost; @@ -457,7 +457,7 @@ test_noprivs@localhost use priv_db; show grants; Grants for test_noprivs@localhost -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' create trigger trg5a_1 before INSERT on t1 for each row set @test_var = new.f1; connection default; @@ -503,7 +503,7 @@ revoke SELECT on priv_db.* from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER ON `priv_db`.* TO 'test_noprivs'@'localhost' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.* TO 'test_noprivs'@'localhost' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER on *.* to test_yesprivs@localhost; grant SELECT on priv_db.* to test_yesprivs@localhost; @@ -518,7 +518,7 @@ connection no_privs_425b; show grants; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER ON `priv_db`.* TO 'test_noprivs'@'localhost' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.* TO 'test_noprivs'@'localhost' use priv_db; create trigger trg5b_1 before UPDATE on t1 for each row set @test_var= new.f1; @@ -565,7 +565,7 @@ revoke SELECT on priv_db.t1 from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER on *.* to test_yesprivs@localhost; grant SELECT on priv_db.t1 to test_yesprivs@localhost; @@ -580,7 +580,7 @@ connection no_privs_425c; show grants; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' use priv_db; create trigger trg5c_1 before INSERT on t1 for each row set @test_var= new.f1; diff --git a/mysql-test/suite/funcs_1/r/myisam_trig_03e.result b/mysql-test/suite/funcs_1/r/myisam_trig_03e.result index a4db9050c86..60e6031f0e2 100644 --- a/mysql-test/suite/funcs_1/r/myisam_trig_03e.result +++ b/mysql-test/suite/funcs_1/r/myisam_trig_03e.result @@ -604,7 +604,7 @@ trig 1_1-yes revoke TRIGGER on *.* from test_yesprivs@localhost; show grants for test_yesprivs@localhost; Grants for test_yesprivs@localhost -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' disconnect yes_privs; connect yes_privs,localhost,test_yesprivs,PWD,test,$MASTER_MYPORT,$MASTER_MYSOCK; select current_user; @@ -657,7 +657,7 @@ root@localhost grant TRIGGER on priv_db.* to test_yesprivs@localhost; show grants for test_yesprivs@localhost; Grants for test_yesprivs@localhost -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' GRANT TRIGGER ON `priv_db`.* TO 'test_yesprivs'@'localhost' trigger privilege on db level for create: @@ -930,7 +930,7 @@ grant TRIGGER on priv1_db.t1 to test_yesprivs@localhost; show grants for test_yesprivs@localhost; Grants for test_yesprivs@localhost GRANT USAGE ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT ON `priv1_db`.* TO 'test_yesprivs'@'localhost' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, DELETE VERSIONING ROWS ON `priv1_db`.* TO 'test_yesprivs'@'localhost' GRANT SELECT, UPDATE ON `priv2_db`.* TO 'test_yesprivs'@'localhost' GRANT TRIGGER ON `priv1_db`.`t1` TO 'test_yesprivs'@'localhost' diff --git a/mysql-test/suite/roles/create_and_drop_role_invalid_user_table.result b/mysql-test/suite/roles/create_and_drop_role_invalid_user_table.result index 1a269d72eb7..afe00ed7729 100644 --- a/mysql-test/suite/roles/create_and_drop_role_invalid_user_table.result +++ b/mysql-test/suite/roles/create_and_drop_role_invalid_user_table.result @@ -5,7 +5,7 @@ alter table user drop column default_role; alter table user drop column max_statement_time; flush privileges; create role test_role; -ERROR HY000: Column count of mysql.user is wrong. Expected 44, found 43. Created with MariaDB MYSQL_VERSION_ID, now running MYSQL_VERSION_ID. Please use mysql_upgrade to fix this error +ERROR HY000: Column count of mysql.user is wrong. Expected 45, found 44. Created with MariaDB MYSQL_VERSION_ID, now running MYSQL_VERSION_ID. Please use mysql_upgrade to fix this error drop role test_role; ERROR HY000: Operation DROP ROLE failed for 'test_role' alter table user add column is_role enum('N', 'Y') default 'N' not null @@ -15,7 +15,7 @@ create role test_role; create user test_user@localhost; grant test_role to test_user@localhost; set default role test_role for root@localhost; -ERROR HY000: Column count of mysql.user is wrong. Expected 45, found 44. Created with MariaDB MYSQL_VERSION_ID, now running MYSQL_VERSION_ID. Please use mysql_upgrade to fix this error +ERROR HY000: Column count of mysql.user is wrong. Expected 46, found 45. Created with MariaDB MYSQL_VERSION_ID, now running MYSQL_VERSION_ID. Please use mysql_upgrade to fix this error drop role test_role; drop user test_user@localhost; alter table user add column default_role char(80) binary default '' not null diff --git a/mysql-test/suite/roles/set_role-recursive.result b/mysql-test/suite/roles/set_role-recursive.result index 53b28a25261..9cea63de3bf 100644 --- a/mysql-test/suite/roles/set_role-recursive.result +++ b/mysql-test/suite/roles/set_role-recursive.result @@ -16,11 +16,11 @@ Host User Role Admin_option test_role1 test_role2 N grant select on *.* to test_role2; select * from mysql.user where user like 'test_role1'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time - test_role1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0 N Y 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time + test_role1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0 N Y 0.000000 select * from mysql.user where user like 'test_role2'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time - test_role2 Y N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0 N Y 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time + test_role2 Y N N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0 N Y 0.000000 select * from mysql.roles_mapping; ERROR 42000: SELECT command denied to user 'test_user'@'localhost' for table 'roles_mapping' show grants; diff --git a/mysql-test/suite/roles/set_role-simple.result b/mysql-test/suite/roles/set_role-simple.result index 29b176776e7..c26f06d1bfe 100644 --- a/mysql-test/suite/roles/set_role-simple.result +++ b/mysql-test/suite/roles/set_role-simple.result @@ -11,8 +11,8 @@ localhost root test_role1 Y localhost test_user test_role1 N grant select on *.* to test_role1; select * from mysql.user where user='test_role1'; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time - test_role1 Y N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0 N Y 0.000000 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv Create_tablespace_priv Delete_versioning_rows_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections plugin authentication_string password_expired is_role default_role max_statement_time + test_role1 Y N N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0 N Y 0.000000 select * from mysql.roles_mapping; ERROR 42000: SELECT command denied to user 'test_user'@'localhost' for table 'roles_mapping' show grants; diff --git a/mysql-test/suite/versioning/r/truncate.result b/mysql-test/suite/versioning/r/truncate.result index 957163286c3..47647ade900 100644 --- a/mysql-test/suite/versioning/r/truncate.result +++ b/mysql-test/suite/versioning/r/truncate.result @@ -1,142 +1,18 @@ create table t (a int); -truncate t for system_time all; +truncate t to system_time now(); ERROR HY000: System Versioning required: t -create procedure truncate_history_of_t() -begin -prepare stmt from 'truncate t for system_time between \'1-1-1\' and now(6)'; -execute stmt; -drop prepare stmt; -end~~ create or replace table t (a int) with system versioning; insert into t values (1); update t set a=2; -select * from t for system_time all; -a -2 -1 set @test = 'correct'; create trigger trg_before before delete on t for each row set @test = 'incorrect'; create trigger trg_after after delete on t for each row set @test = 'incorrect'; -truncate t for system_time all; -select * from t for system_time all; -a -2 +truncate t to system_time now(6); select @test from t; @test correct -drop trigger trg_before; -drop trigger trg_after; -update t set a=3; -update t set a=4; -truncate t for system_time as of timestamp now(6); -select * from t for system_time all; -a -4 -2 -3 -truncate t for system_time between '1-1-1' and now(6); -select * from t for system_time all; -a -4 -update t set a=5; -truncate t for system_time from '1-1-1' to now(6); -select * from t for system_time all; -a -5 -update t set a=6; -call truncate_history_of_t(); -select * from t for system_time all; -a -6 -set @ts1 = now(6); -update t set a=7; -set @ts2 = now(6); -update t set a=8; -truncate t for system_time from '1-1-1' to @ts1; -select * from t for system_time all; -a -8 -7 -update t set a=9; -truncate t for system_time between '1-1-1' and @ts2; -select * from t for system_time all; -a -9 -8 -create or replace table t (a int) with system versioning engine=innodb; -insert into t values (1); -update t set a=2; -select * from t for system_time all; -a -2 -1 -truncate t for system_time all; -select * from t for system_time all; -a -2 -update t set a=3; -update t set a=4; -truncate t for system_time as of timestamp now(6); -select * from t for system_time all; -a -4 -2 -3 -truncate t for system_time between '1-1-1' and now(6); -select * from t for system_time all; -a -4 -update t set a=5; -truncate t for system_time from '1-1-1' to now(6); -select * from t for system_time all; -a -5 -update t set a=6; -call truncate_history_of_t(); -select * from t for system_time all; -a -6 -set @ts1 = now(6); -update t set a=7; -set @ts2 = now(6); -update t set a=8; -truncate t for system_time from '1-1-1' to timestamp @ts1; -select * from t for system_time all; -a -8 -7 -update t set a=9; -truncate t for system_time between '1-1-1' and timestamp @ts2; -select * from t for system_time all; -a -9 -8 -create or replace table t (a int) with system versioning; -insert into t values (1), (2); -update t set a=11 where a=1; -set @ts1=now(6); -update t set a=22 where a=2; -select * from t for system_time all; -a -11 -22 -1 -2 -select * from t for system_time before timestamp @ts1; -a -1 -truncate t for system_time before timestamp @ts1; -select * from t for system_time all; -a -11 -22 -2 -truncate t for system_time before timestamp now(6); -select * from t for system_time all; -a -11 -22 -create or replace table t (a int) with system versioning engine=innodb; +drop table t; +create table t (a int) with system versioning; insert into t values (1), (2); update t set a=11 where a=1; set @ts1=now(6); @@ -147,27 +23,15 @@ a 22 1 2 -select * from t for system_time before timestamp @ts1; -a -1 -insert into t values (33); -select max(sys_trx_start + 0) from t into @tx; -select * from t for system_time before transaction @tx; -a -1 -2 -truncate t for system_time before timestamp @ts1; +truncate t to system_time timestamp @ts1; select * from t for system_time all; a 11 22 2 -33 -truncate t for system_time before timestamp now(6); +truncate table t to system_time timestamp now(6); select * from t for system_time all; a 11 22 -33 drop table t; -drop procedure truncate_history_of_t; diff --git a/mysql-test/suite/versioning/r/truncate_privilege.result b/mysql-test/suite/versioning/r/truncate_privilege.result new file mode 100644 index 00000000000..69a43ba8830 --- /dev/null +++ b/mysql-test/suite/versioning/r/truncate_privilege.result @@ -0,0 +1,33 @@ +connect root,localhost,root,,test; +connection root; +create database mysqltest; +create user mysqltest_1@localhost; +connect user1,localhost,mysqltest_1,,test; +connection user1; +connection root; +create table mysqltest.t (a int) with system versioning; +connection user1; +show grants; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +truncate mysqltest.t to system_time now(); +ERROR 42000: DELETE VERSIONING ROWS command denied to user 'mysqltest_1'@'localhost' for table 't' +connection root; +grant delete versioning rows on mysqltest.* to mysqltest_1@localhost; +grant delete versioning rows on mysqltest.t to mysqltest_1@localhost; +connection user1; +show grants; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT DELETE VERSIONING ROWS ON `mysqltest`.* TO 'mysqltest_1'@'localhost' +GRANT DELETE VERSIONING ROWS ON `mysqltest`.`t` TO 'mysqltest_1'@'localhost' +truncate mysqltest.t to system_time now(); +connection root; +grant all on *.* to mysqltest_1@localhost; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT ALL PRIVILEGES ON *.* TO 'mysqltest_1'@'localhost' +GRANT DELETE VERSIONING ROWS ON `mysqltest`.* TO 'mysqltest_1'@'localhost' +GRANT DELETE VERSIONING ROWS ON `mysqltest`.`t` TO 'mysqltest_1'@'localhost' +drop user mysqltest_1@localhost; +drop database mysqltest; diff --git a/mysql-test/suite/versioning/r/vtmd_show.result b/mysql-test/suite/versioning/r/vtmd_show.result index b7409793677..a6991b2d0a1 100644 --- a/mysql-test/suite/versioning/r/vtmd_show.result +++ b/mysql-test/suite/versioning/r/vtmd_show.result @@ -58,8 +58,6 @@ show create table t for system_time between timestamp @tm1 and timestamp @tm1; ERROR HY000: SYSTEM_TIME range selector is prohibited show create table t for system_time from timestamp @tm1 to timestamp @tm1; ERROR HY000: SYSTEM_TIME range selector is prohibited -show create table t for system_time before timestamp @tm1; -ERROR HY000: SYSTEM_TIME range selector is prohibited show create table t for system_time as of timestamp '01-01-1990'; ERROR HY000: VTMD error: failed to query VTMD table show create table t for system_time as of timestamp '01-01-2020'; diff --git a/mysql-test/suite/versioning/t/truncate.combinations b/mysql-test/suite/versioning/t/truncate.combinations new file mode 100644 index 00000000000..75fb20d9f5e --- /dev/null +++ b/mysql-test/suite/versioning/t/truncate.combinations @@ -0,0 +1,5 @@ +[innodb] +default-storage-engine=innodb + +[myisam] +default-storage-engine=myisam diff --git a/mysql-test/suite/versioning/t/truncate.test b/mysql-test/suite/versioning/t/truncate.test index ddd0db5856d..1de94487570 100644 --- a/mysql-test/suite/versioning/t/truncate.test +++ b/mysql-test/suite/versioning/t/truncate.test @@ -2,120 +2,28 @@ create table t (a int); --error ER_VERSIONING_REQUIRED -truncate t for system_time all; - -delimiter ~~; -create procedure truncate_history_of_t() -begin - prepare stmt from 'truncate t for system_time between \'1-1-1\' and now(6)'; - execute stmt; - drop prepare stmt; -end~~ -delimiter ;~~ +truncate t to system_time now(); +# TRUNCATE is not DELETE and trigger must not be called. create or replace table t (a int) with system versioning; insert into t values (1); update t set a=2; -select * from t for system_time all; - set @test = 'correct'; create trigger trg_before before delete on t for each row set @test = 'incorrect'; create trigger trg_after after delete on t for each row set @test = 'incorrect'; - -truncate t for system_time all; -select * from t for system_time all; - +truncate t to system_time now(6); select @test from t; -drop trigger trg_before; -drop trigger trg_after; - -update t set a=3; -update t set a=4; -truncate t for system_time as of timestamp now(6); -select * from t for system_time all; - -truncate t for system_time between '1-1-1' and now(6); -select * from t for system_time all; - -update t set a=5; -truncate t for system_time from '1-1-1' to now(6); -select * from t for system_time all; - -update t set a=6; -call truncate_history_of_t(); -select * from t for system_time all; - -set @ts1 = now(6); -update t set a=7; -set @ts2 = now(6); -update t set a=8; -truncate t for system_time from '1-1-1' to @ts1; -select * from t for system_time all; -update t set a=9; -truncate t for system_time between '1-1-1' and @ts2; -select * from t for system_time all; - - -create or replace table t (a int) with system versioning engine=innodb; -insert into t values (1); -update t set a=2; -select * from t for system_time all; - -truncate t for system_time all; -select * from t for system_time all; - -update t set a=3; -update t set a=4; -truncate t for system_time as of timestamp now(6); -select * from t for system_time all; - -truncate t for system_time between '1-1-1' and now(6); -select * from t for system_time all; - -update t set a=5; -truncate t for system_time from '1-1-1' to now(6); -select * from t for system_time all; - -update t set a=6; -call truncate_history_of_t(); -select * from t for system_time all; - -set @ts1 = now(6); -update t set a=7; -set @ts2 = now(6); -update t set a=8; -truncate t for system_time from '1-1-1' to timestamp @ts1; -select * from t for system_time all; -update t set a=9; -truncate t for system_time between '1-1-1' and timestamp @ts2; -select * from t for system_time all; - -create or replace table t (a int) with system versioning; -insert into t values (1), (2); -update t set a=11 where a=1; -set @ts1=now(6); -update t set a=22 where a=2; -select * from t for system_time all; -select * from t for system_time before timestamp @ts1; -truncate t for system_time before timestamp @ts1; -select * from t for system_time all; -truncate t for system_time before timestamp now(6); -select * from t for system_time all; +drop table t; -create or replace table t (a int) with system versioning engine=innodb; +create table t (a int) with system versioning; insert into t values (1), (2); update t set a=11 where a=1; set @ts1=now(6); update t set a=22 where a=2; select * from t for system_time all; -select * from t for system_time before timestamp @ts1; -insert into t values (33); -select max(sys_trx_start + 0) from t into @tx; -select * from t for system_time before transaction @tx; -truncate t for system_time before timestamp @ts1; +truncate t to system_time timestamp @ts1; select * from t for system_time all; -truncate t for system_time before timestamp now(6); +truncate table t to system_time timestamp now(6); select * from t for system_time all; drop table t; -drop procedure truncate_history_of_t; diff --git a/mysql-test/suite/versioning/t/truncate_privilege.test b/mysql-test/suite/versioning/t/truncate_privilege.test new file mode 100644 index 00000000000..7042f359e13 --- /dev/null +++ b/mysql-test/suite/versioning/t/truncate_privilege.test @@ -0,0 +1,41 @@ +# Can't test with embedded server +-- source include/not_embedded.inc + +--source include/have_innodb.inc + +# Save the initial number of concurrent sessions +--source include/count_sessions.inc + +connect (root,localhost,root,,test); +connection root; + +--disable_warnings +create database mysqltest; +--enable_warnings + +create user mysqltest_1@localhost; +connect (user1,localhost,mysqltest_1,,test); +connection user1; + +connection root; +create table mysqltest.t (a int) with system versioning; + +connection user1; +show grants; +--error ER_TABLEACCESS_DENIED_ERROR +truncate mysqltest.t to system_time now(); + +connection root; +grant delete versioning rows on mysqltest.* to mysqltest_1@localhost; +grant delete versioning rows on mysqltest.t to mysqltest_1@localhost; + +connection user1; +show grants; +truncate mysqltest.t to system_time now(); + +connection root; +grant all on *.* to mysqltest_1@localhost; +show grants for mysqltest_1@localhost; + +drop user mysqltest_1@localhost; +drop database mysqltest; diff --git a/mysql-test/suite/versioning/t/vtmd_show.test b/mysql-test/suite/versioning/t/vtmd_show.test index 24125d2b76b..fdbdcbcae29 100644 --- a/mysql-test/suite/versioning/t/vtmd_show.test +++ b/mysql-test/suite/versioning/t/vtmd_show.test @@ -75,8 +75,6 @@ create or replace table t (a int) with system versioning; show create table t for system_time between timestamp @tm1 and timestamp @tm1; --error ER_VERS_RANGE_PROHIBITED show create table t for system_time from timestamp @tm1 to timestamp @tm1; ---error ER_VERS_RANGE_PROHIBITED -show create table t for system_time before timestamp @tm1; --error ER_VERS_VTMD_ERROR show create table t for system_time as of timestamp '01-01-1990'; --error ER_VERS_VTMD_ERROR diff --git a/scripts/mysql_system_tables.sql b/scripts/mysql_system_tables.sql index 539b26cd176..c911b1f2209 100644 --- a/scripts/mysql_system_tables.sql +++ b/scripts/mysql_system_tables.sql @@ -28,14 +28,14 @@ set versioning_alter_history=keep; set @have_innodb= (select count(engine) from information_schema.engines where engine='INNODB' and support != 'NO'); SET @innodb_or_myisam=IF(@have_innodb <> 0, 'InnoDB', 'MyISAM'); -CREATE TABLE IF NOT EXISTS db ( Host char(60) binary DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL, User char(80) binary DEFAULT '' NOT NULL, Select_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Insert_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Update_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Delete_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Drop_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Grant_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, References_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Index_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_tmp_table_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Lock_tables_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Execute_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Event_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Trigger_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, PRIMARY KEY Host (Host,Db,User), KEY User (User) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Database privileges'; +CREATE TABLE IF NOT EXISTS db ( Host char(60) binary DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL, User char(80) binary DEFAULT '' NOT NULL, Select_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Insert_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Update_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Delete_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Drop_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Grant_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, References_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Index_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_tmp_table_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Lock_tables_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Execute_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Event_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Trigger_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Delete_versioning_rows_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, PRIMARY KEY Host (Host,Db,User), KEY User (User) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Database privileges'; -- Remember for later if db table already existed set @had_db_table= @@warning_count != 0; CREATE TABLE IF NOT EXISTS host ( Host char(60) binary DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL, Select_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Insert_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Update_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Delete_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Drop_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Grant_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, References_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Index_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_tmp_table_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Lock_tables_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Execute_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Trigger_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, PRIMARY KEY Host (Host,Db) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Host privileges; Merged with database privileges'; -CREATE TABLE IF NOT EXISTS user ( Host char(60) binary DEFAULT '' NOT NULL, User char(80) binary DEFAULT '' NOT NULL, Password char(41) character set latin1 collate latin1_bin DEFAULT '' NOT NULL, Select_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Insert_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Update_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Delete_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Drop_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Reload_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Shutdown_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Process_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, File_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Grant_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, References_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Index_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Show_db_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Super_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_tmp_table_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Lock_tables_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Execute_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Repl_slave_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Repl_client_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_user_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Event_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Trigger_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_tablespace_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, ssl_type enum('','ANY','X509', 'SPECIFIED') COLLATE utf8_general_ci DEFAULT '' NOT NULL, ssl_cipher BLOB NOT NULL, x509_issuer BLOB NOT NULL, x509_subject BLOB NOT NULL, max_questions int(11) unsigned DEFAULT 0 NOT NULL, max_updates int(11) unsigned DEFAULT 0 NOT NULL, max_connections int(11) unsigned DEFAULT 0 NOT NULL, max_user_connections int(11) DEFAULT 0 NOT NULL, plugin char(64) CHARACTER SET latin1 DEFAULT '' NOT NULL, authentication_string TEXT NOT NULL, password_expired ENUM('N', 'Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, is_role enum('N', 'Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, default_role char(80) binary DEFAULT '' NOT NULL, max_statement_time decimal(12,6) DEFAULT 0 NOT NULL, PRIMARY KEY Host (Host,User) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Users and global privileges'; +CREATE TABLE IF NOT EXISTS user ( Host char(60) binary DEFAULT '' NOT NULL, User char(80) binary DEFAULT '' NOT NULL, Password char(41) character set latin1 collate latin1_bin DEFAULT '' NOT NULL, Select_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Insert_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Update_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Delete_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Drop_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Reload_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Shutdown_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Process_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, File_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Grant_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, References_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Index_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Show_db_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Super_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_tmp_table_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Lock_tables_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Execute_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Repl_slave_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Repl_client_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_user_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Event_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Trigger_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_tablespace_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Delete_versioning_rows_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, ssl_type enum('','ANY','X509', 'SPECIFIED') COLLATE utf8_general_ci DEFAULT '' NOT NULL, ssl_cipher BLOB NOT NULL, x509_issuer BLOB NOT NULL, x509_subject BLOB NOT NULL, max_questions int(11) unsigned DEFAULT 0 NOT NULL, max_updates int(11) unsigned DEFAULT 0 NOT NULL, max_connections int(11) unsigned DEFAULT 0 NOT NULL, max_user_connections int(11) DEFAULT 0 NOT NULL, plugin char(64) CHARACTER SET latin1 DEFAULT '' NOT NULL, authentication_string TEXT NOT NULL, password_expired ENUM('N', 'Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, is_role enum('N', 'Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, default_role char(80) binary DEFAULT '' NOT NULL, max_statement_time decimal(12,6) DEFAULT 0 NOT NULL, PRIMARY KEY Host (Host,User) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Users and global privileges'; -- Remember for later if user table already existed set @had_user_table= @@warning_count != 0; @@ -51,7 +51,7 @@ CREATE TABLE IF NOT EXISTS plugin ( name varchar(64) DEFAULT '' NOT NULL, dl var CREATE TABLE IF NOT EXISTS servers ( Server_name char(64) NOT NULL DEFAULT '', Host char(64) NOT NULL DEFAULT '', Db char(64) NOT NULL DEFAULT '', Username char(80) NOT NULL DEFAULT '', Password char(64) NOT NULL DEFAULT '', Port INT(4) NOT NULL DEFAULT '0', Socket char(64) NOT NULL DEFAULT '', Wrapper char(64) NOT NULL DEFAULT '', Owner char(64) NOT NULL DEFAULT '', PRIMARY KEY (Server_name)) CHARACTER SET utf8 comment='MySQL Foreign Servers table'; -CREATE TABLE IF NOT EXISTS tables_priv ( Host char(60) binary DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL, User char(80) binary DEFAULT '' NOT NULL, Table_name char(64) binary DEFAULT '' NOT NULL, Grantor char(141) DEFAULT '' NOT NULL, Timestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, Table_priv set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view','Trigger') COLLATE utf8_general_ci DEFAULT '' NOT NULL, Column_priv set('Select','Insert','Update','References') COLLATE utf8_general_ci DEFAULT '' NOT NULL, PRIMARY KEY (Host,Db,User,Table_name), KEY Grantor (Grantor) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Table privileges'; +CREATE TABLE IF NOT EXISTS tables_priv ( Host char(60) binary DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL, User char(80) binary DEFAULT '' NOT NULL, Table_name char(64) binary DEFAULT '' NOT NULL, Grantor char(141) DEFAULT '' NOT NULL, Timestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, Table_priv set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view','Trigger','Delete versioning rows') COLLATE utf8_general_ci DEFAULT '' NOT NULL, Column_priv set('Select','Insert','Update','References') COLLATE utf8_general_ci DEFAULT '' NOT NULL, PRIMARY KEY (Host,Db,User,Table_name), KEY Grantor (Grantor) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Table privileges'; CREATE TABLE IF NOT EXISTS columns_priv ( Host char(60) binary DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL, User char(80) binary DEFAULT '' NOT NULL, Table_name char(64) binary DEFAULT '' NOT NULL, Column_name char(64) binary DEFAULT '' NOT NULL, Timestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, Column_priv set('Select','Insert','Update','References') COLLATE utf8_general_ci DEFAULT '' NOT NULL, PRIMARY KEY (Host,Db,User,Table_name,Column_name) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Column privileges'; diff --git a/scripts/mysql_system_tables_data.sql b/scripts/mysql_system_tables_data.sql index 9556e7ba160..4821b18bcbf 100644 --- a/scripts/mysql_system_tables_data.sql +++ b/scripts/mysql_system_tables_data.sql @@ -30,8 +30,8 @@ SELECT LOWER( REPLACE((SELECT REPLACE(@@hostname,'_','\_')),'%','\%') )INTO @cur -- Fill "db" table with default grants for anyone to -- access database 'test' and 'test_%' if "db" table didn't exist CREATE TEMPORARY TABLE tmp_db LIKE db; -INSERT INTO tmp_db VALUES ('%','test','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y','Y','Y','Y','N','N','Y','Y'); -INSERT INTO tmp_db VALUES ('%','test\_%','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y','Y','Y','Y','N','N','Y','Y'); +INSERT INTO tmp_db VALUES ('%','test','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y','Y','Y','Y','N','N','Y','Y','Y'); +INSERT INTO tmp_db VALUES ('%','test\_%','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y','Y','Y','Y','N','N','Y','Y','Y'); INSERT INTO db SELECT * FROM tmp_db WHERE @had_db_table=0; DROP TABLE tmp_db; @@ -42,12 +42,12 @@ CREATE TEMPORARY TABLE tmp_user_nopasswd LIKE user; CREATE TEMPORARY TABLE tmp_user_socket LIKE user; CREATE TEMPORARY TABLE tmp_user_anonymous LIKE user; -- Classic passwordless root account. -INSERT INTO tmp_user_nopasswd VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N', 'N','', 0); -REPLACE INTO tmp_user_nopasswd SELECT @current_hostname,'root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N','N','',0 FROM dual WHERE @current_hostname != 'localhost'; -REPLACE INTO tmp_user_nopasswd VALUES ('127.0.0.1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N','N','',0); -REPLACE INTO tmp_user_nopasswd VALUES ('::1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N','N', '', 0); +INSERT INTO tmp_user_nopasswd VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N', 'N','', 0); +REPLACE INTO tmp_user_nopasswd SELECT @current_hostname,'root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N','N','',0 FROM dual WHERE @current_hostname != 'localhost'; +REPLACE INTO tmp_user_nopasswd VALUES ('127.0.0.1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N','N','',0); +REPLACE INTO tmp_user_nopasswd VALUES ('::1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N','N', '', 0); -- More secure root account using unix sucket auth. -INSERT INTO tmp_user_socket VALUES ('localhost',IFNULL(@auth_root_socket, 'root'),'','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'unix_socket','','N', 'N','', 0); +INSERT INTO tmp_user_socket VALUES ('localhost',IFNULL(@auth_root_socket, 'root'),'','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'unix_socket','','N', 'N','', 0); -- Anonymous user with no privileges. INSERT INTO tmp_user_anonymous (host,user) VALUES ('localhost',''); INSERT INTO tmp_user_anonymous (host,user) SELECT @current_hostname,'' FROM dual WHERE @current_hostname != 'localhost'; diff --git a/scripts/mysql_system_tables_fix.sql b/scripts/mysql_system_tables_fix.sql index 80d0ef714a3..0bca8dfa4bf 100644 --- a/scripts/mysql_system_tables_fix.sql +++ b/scripts/mysql_system_tables_fix.sql @@ -74,7 +74,7 @@ ALTER TABLE tables_priv COLLATE utf8_general_ci DEFAULT '' NOT NULL, MODIFY Table_priv set('Select','Insert','Update','Delete','Create', 'Drop','Grant','References','Index','Alter', - 'Create View','Show view','Trigger') + 'Create View','Show view','Trigger','Delete versioning rows') COLLATE utf8_general_ci DEFAULT '' NOT NULL, COMMENT='Table privileges'; @@ -729,3 +729,9 @@ ALTER TABLE help_topic MODIFY url TEXT NOT NULL; # MDEV-7383 - varbinary on mix/max of column_stats alter table column_stats modify min_value varbinary(255) DEFAULT NULL, modify max_value varbinary(255) DEFAULT NULL; + +# System versioning +ALTER TABLE user add Delete_versioning_rows_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL DEFAULT 'N' after Trigger_priv; +ALTER TABLE user modify Delete_versioning_rows_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL DEFAULT 'N'; +ALTER TABLE db add Delete_versioning_rows_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL DEFAULT 'N' after Trigger_priv; +ALTER TABLE db modify Delete_versioning_rows_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL DEFAULT 'N'; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 09781f4bbe3..28422c53426 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -170,6 +170,11 @@ TABLE_FIELD_TYPE mysql_db_table_fields[MYSQL_DB_FIELD_COUNT] = { { C_STRING_WITH_LEN("Trigger_priv") }, { C_STRING_WITH_LEN("enum('N','Y')") }, { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("Delete_versioning_rows_priv") }, + { C_STRING_WITH_LEN("enum('N','Y')") }, + { C_STRING_WITH_LEN("utf8") } } }; @@ -695,9 +700,9 @@ bool ROLE_GRANT_PAIR::init(MEM_ROOT *mem, char *username, #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */ #define NORMAL_HANDSHAKE_SIZE 6 -#define ROLE_ASSIGN_COLUMN_IDX 43 -#define DEFAULT_ROLE_COLUMN_IDX 44 -#define MAX_STATEMENT_TIME_COLUMN_IDX 45 +#define ROLE_ASSIGN_COLUMN_IDX 44 +#define DEFAULT_ROLE_COLUMN_IDX 45 +#define MAX_STATEMENT_TIME_COLUMN_IDX 46 /* various flags valid for ACL_USER */ #define IS_ROLE (1L << 0) @@ -2004,6 +2009,9 @@ static bool acl_load(THD *thd, const Grant_tables& tables) if (user_table.num_fields() <= 38 && (user.access & SUPER_ACL)) user.access|= TRIGGER_ACL; + if (user_table.num_fields() <= 46 && (user.access & DELETE_ACL)) + user.access|= DELETE_VERSIONING_ROWS_ACL; + user.sort= get_sort(2, user.host.hostname, user.user.str); user.hostname_length= safe_strlen(user.host.hostname); user.user_resource.user_conn= 0; @@ -8422,13 +8430,14 @@ static const char *command_array[]= "ALTER", "SHOW DATABASES", "SUPER", "CREATE TEMPORARY TABLES", "LOCK TABLES", "EXECUTE", "REPLICATION SLAVE", "REPLICATION CLIENT", "CREATE VIEW", "SHOW VIEW", "CREATE ROUTINE", "ALTER ROUTINE", - "CREATE USER", "EVENT", "TRIGGER", "CREATE TABLESPACE" + "CREATE USER", "EVENT", "TRIGGER", "CREATE TABLESPACE", + "DELETE VERSIONING ROWS" }; static uint command_lengths[]= { 6, 6, 6, 6, 6, 4, 6, 8, 7, 4, 5, 10, 5, 5, 14, 5, 23, 11, 7, 17, 18, 11, 9, - 14, 13, 11, 5, 7, 17 + 14, 13, 11, 5, 7, 17, 22, }; diff --git a/sql/sql_acl.h b/sql/sql_acl.h index daa36f6c32a..dbfab1cac21 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -50,6 +50,7 @@ #define EVENT_ACL (1UL << 26) #define TRIGGER_ACL (1UL << 27) #define CREATE_TABLESPACE_ACL (1UL << 28) +#define DELETE_VERSIONING_ROWS_ACL (1UL << 29) /* don't forget to update 1. static struct show_privileges_st sys_privileges[] @@ -63,12 +64,13 @@ (UPDATE_ACL | SELECT_ACL | INSERT_ACL | DELETE_ACL | CREATE_ACL | DROP_ACL | \ GRANT_ACL | REFERENCES_ACL | INDEX_ACL | ALTER_ACL | CREATE_TMP_ACL | \ LOCK_TABLES_ACL | EXECUTE_ACL | CREATE_VIEW_ACL | SHOW_VIEW_ACL | \ - CREATE_PROC_ACL | ALTER_PROC_ACL | EVENT_ACL | TRIGGER_ACL) + CREATE_PROC_ACL | ALTER_PROC_ACL | EVENT_ACL | TRIGGER_ACL | \ + DELETE_VERSIONING_ROWS_ACL) #define TABLE_ACLS \ (SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL | CREATE_ACL | DROP_ACL | \ GRANT_ACL | REFERENCES_ACL | INDEX_ACL | ALTER_ACL | CREATE_VIEW_ACL | \ - SHOW_VIEW_ACL | TRIGGER_ACL) + SHOW_VIEW_ACL | TRIGGER_ACL | DELETE_VERSIONING_ROWS_ACL) #define COL_ACLS \ (SELECT_ACL | INSERT_ACL | UPDATE_ACL | REFERENCES_ACL) @@ -86,7 +88,7 @@ CREATE_TMP_ACL | LOCK_TABLES_ACL | REPL_SLAVE_ACL | REPL_CLIENT_ACL | \ EXECUTE_ACL | CREATE_VIEW_ACL | SHOW_VIEW_ACL | CREATE_PROC_ACL | \ ALTER_PROC_ACL | CREATE_USER_ACL | EVENT_ACL | TRIGGER_ACL | \ - CREATE_TABLESPACE_ACL) + CREATE_TABLESPACE_ACL | DELETE_VERSIONING_ROWS_ACL) #define DEFAULT_CREATE_PROC_ACLS \ (ALTER_PROC_ACL | EXECUTE_ACL) @@ -118,31 +120,37 @@ CREATE_PROC_ACL | ALTER_PROC_ACL ) #define DB_CHUNK4 (EXECUTE_ACL) #define DB_CHUNK5 (EVENT_ACL | TRIGGER_ACL) +#define DB_CHUNK6 (DELETE_VERSIONING_ROWS_ACL) #define fix_rights_for_db(A) (((A) & DB_CHUNK0) | \ (((A) << 4) & DB_CHUNK1) | \ (((A) << 6) & DB_CHUNK2) | \ (((A) << 9) & DB_CHUNK3) | \ - (((A) << 2) & DB_CHUNK4))| \ - (((A) << 9) & DB_CHUNK5) + (((A) << 2) & DB_CHUNK4) | \ + (((A) << 9) & DB_CHUNK5) | \ + (((A) << 10) & DB_CHUNK6)) #define get_rights_for_db(A) (((A) & DB_CHUNK0) | \ (((A) & DB_CHUNK1) >> 4) | \ (((A) & DB_CHUNK2) >> 6) | \ (((A) & DB_CHUNK3) >> 9) | \ - (((A) & DB_CHUNK4) >> 2))| \ - (((A) & DB_CHUNK5) >> 9) + (((A) & DB_CHUNK4) >> 2) | \ + (((A) & DB_CHUNK5) >> 9) | \ + (((A) & DB_CHUNK6) >> 10)) #define TBL_CHUNK0 DB_CHUNK0 #define TBL_CHUNK1 DB_CHUNK1 #define TBL_CHUNK2 (CREATE_VIEW_ACL | SHOW_VIEW_ACL) #define TBL_CHUNK3 TRIGGER_ACL +#define TBL_CHUNK4 (DELETE_VERSIONING_ROWS_ACL) #define fix_rights_for_table(A) (((A) & TBL_CHUNK0) | \ (((A) << 4) & TBL_CHUNK1) | \ (((A) << 11) & TBL_CHUNK2) | \ - (((A) << 15) & TBL_CHUNK3)) + (((A) << 15) & TBL_CHUNK3) | \ + (((A) << 16) & TBL_CHUNK4)) #define get_rights_for_table(A) (((A) & TBL_CHUNK0) | \ (((A) & TBL_CHUNK1) >> 4) | \ (((A) & TBL_CHUNK2) >> 11) | \ - (((A) & TBL_CHUNK3) >> 15)) + (((A) & TBL_CHUNK3) >> 15) | \ + (((A) & TBL_CHUNK4) >> 16)) #define fix_rights_for_column(A) (((A) & 7) | (((A) & ~7) << 8)) #define get_rights_for_column(A) (((A) & 7) | ((A) >> 8)) #define fix_rights_for_procedure(A) ((((A) << 18) & EXECUTE_ACL) | \ @@ -176,6 +184,7 @@ enum mysql_db_table_field MYSQL_DB_FIELD_EXECUTE_PRIV, MYSQL_DB_FIELD_EVENT_PRIV, MYSQL_DB_FIELD_TRIGGER_PRIV, + MYSQL_DB_FIELD_DELETE_VERSIONING_ROWS_PRIV, MYSQL_DB_FIELD_COUNT }; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 8dc6203ed86..2d56f66dac7 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -275,15 +275,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, // trx_sees() in InnoDB reads sys_trx_start if (!table->versioned_by_sql()) { - if (table_list->vers_conditions.type == FOR_SYSTEM_TIME_BETWEEN || - table_list->vers_conditions.type == FOR_SYSTEM_TIME_FROM_TO) - { - bitmap_set_bit(table->read_set, table->vers_start_field()->field_index); - } - else if (table_list->vers_conditions.type == FOR_SYSTEM_TIME_BEFORE) - { - bitmap_set_bit(table->read_set, table->vers_end_field()->field_index); - } + DBUG_ASSERT(table_list->vers_conditions.type == FOR_SYSTEM_TIME_BEFORE); + bitmap_set_bit(table->read_set, table->vers_end_field()->field_index); } } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index d36d222fb07..30fd1b43e4c 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -564,6 +564,7 @@ static struct show_privileges_st sys_privileges[]= {"Create view", "Tables", "To create new views"}, {"Create user", "Server Admin", "To create new users"}, {"Delete", "Tables", "To delete existing rows"}, + {"Delete versioning rows", "Tables", "To delete versioning table historical rows"}, {"Drop", "Databases,Tables", "To drop databases, tables, and views"}, #ifdef HAVE_EVENT_SCHEDULER {"Event","Server Admin","To create, alter, drop and execute events"}, diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc index b65818a2716..c428491cfa3 100644 --- a/sql/sql_truncate.cc +++ b/sql/sql_truncate.cc @@ -495,9 +495,12 @@ bool Sql_cmd_truncate_table::execute(THD *thd) TABLE_LIST *table= thd->lex->select_lex.table_list.first; DBUG_ENTER("Sql_cmd_truncate_table::execute"); - DBUG_ASSERT(table); if (table->vers_conditions) + { + if (check_one_table_access(thd, DELETE_VERSIONING_ROWS_ACL, table)) + DBUG_RETURN(res); DBUG_RETURN(mysql_delete(thd, table, NULL, NULL, -1, 0, NULL)); + } if (check_one_table_access(thd, DROP_ACL, table)) DBUG_RETURN(res); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 1f0ce5fd6a0..0770913e521 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -8903,12 +8903,6 @@ system_time_expr: { Lex->vers_conditions.init(FOR_SYSTEM_TIME_BETWEEN, $2, $3, $5, $6); } - | BEFORE_SYM - opt_trans_or_timestamp - simple_expr - { - Lex->vers_conditions.init(FOR_SYSTEM_TIME_BEFORE, $2, $3); - } ; select_option_list: @@ -13025,8 +13019,17 @@ opt_delete_option: | IGNORE_SYM { Lex->ignore= 1; } ; +truncate_end: + opt_lock_wait_timeout + | TO_SYM SYSTEM_TIME_SYM opt_trans_or_timestamp simple_expr + { + Lex->vers_conditions.init(FOR_SYSTEM_TIME_BEFORE, $3, $4); + Lex->last_table()->vers_conditions= Lex->vers_conditions; + } + ; + truncate: - TRUNCATE_SYM opt_table_sym + TRUNCATE_SYM { LEX* lex= Lex; lex->sql_command= SQLCOM_TRUNCATE; @@ -13037,15 +13040,13 @@ truncate: YYPS->m_lock_type= TL_WRITE; YYPS->m_mdl_type= MDL_EXCLUSIVE; } - table_name opt_for_system_time_clause opt_lock_wait_timeout + opt_table_sym table_name truncate_end { LEX* lex= thd->lex; DBUG_ASSERT(!lex->m_sql_cmd); lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_truncate_table(); if (lex->m_sql_cmd == NULL) MYSQL_YYABORT; - if ($5) - Lex->last_table()->vers_conditions= Lex->vers_conditions; } ; @@ -16076,6 +16077,7 @@ object_privilege: | EVENT_SYM { Lex->grant |= EVENT_ACL;} | TRIGGER_SYM { Lex->grant |= TRIGGER_ACL; } | CREATE TABLESPACE { Lex->grant |= CREATE_TABLESPACE_ACL; } + | DELETE_SYM VERSIONING_SYM ROWS_SYM { Lex->grant |= DELETE_VERSIONING_ROWS_ACL; } ; opt_and: diff --git a/sql/vtq.h b/sql/vtq.h old mode 100755 new mode 100644 -- cgit v1.2.1 From 78d2430aa22eac6e6b6e24b8776290d4d939a236 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Tue, 12 Sep 2017 16:27:44 +0300 Subject: Tests: VTMD + modify column --- mysql-test/suite/versioning/r/vtmd.result | 10 ++++++++++ mysql-test/suite/versioning/t/vtmd.test | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/mysql-test/suite/versioning/r/vtmd.result b/mysql-test/suite/versioning/r/vtmd.result index 910a937e9c5..ad72da94df3 100644 --- a/mysql-test/suite/versioning/r/vtmd.result +++ b/mysql-test/suite/versioning/r/vtmd.result @@ -265,6 +265,16 @@ A_start B_end name C_archive_name 1 0 other_name t1_ 1 0 t1 t1_ 1 1 t2 NULL +create or replace table t3 (x int) with system versioning; +alter table t3 change x x bigint; +alter table t3 change x x bigint after sys_trx_start; +call check_vtmd('t3_vtmd'); +@start > 0 and @start < @inf +1 +A_start B_end name C_archive_name +1 0 t3 t3_ +1 0 t3 t3_ +1 1 t3 NULL drop database db0; drop database db1; drop database test; diff --git a/mysql-test/suite/versioning/t/vtmd.test b/mysql-test/suite/versioning/t/vtmd.test index 2826c6fd2ff..8ff2f64dc73 100644 --- a/mysql-test/suite/versioning/t/vtmd.test +++ b/mysql-test/suite/versioning/t/vtmd.test @@ -155,6 +155,11 @@ use test; show tables; call check_vtmd('t2_vtmd'); +create or replace table t3 (x int) with system versioning; +alter table t3 change x x bigint; +alter table t3 change x x bigint after sys_trx_start; +call check_vtmd('t3_vtmd'); + drop database db0; drop database db1; drop database test; -- cgit v1.2.1 From 7e764ae188efe3f866222eb393513bf30e2b75ab Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 13 Sep 2017 10:57:23 +0300 Subject: SQL: 1-row partition rotation fix [fixes #260] --- include/my_base.h | 4 ++++ mysql-test/suite/versioning/r/partition.result | 6 ++++++ mysql-test/suite/versioning/t/partition.test | 8 ++++++++ sql/ha_partition.cc | 15 ++++++++------- sql/ha_partition.h | 2 +- sql/sql_partition.cc | 22 +++++++++++++++++----- storage/innobase/handler/ha_innodb.cc | 4 ++-- 7 files changed, 46 insertions(+), 15 deletions(-) diff --git a/include/my_base.h b/include/my_base.h index ea8fd623b28..a9591fccf40 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -407,6 +407,10 @@ enum ha_base_keytype { when only HA_STATUS_VARIABLE but it won't be used. */ #define HA_STATUS_VARIABLE_EXTRA 128U +/* + Treat empty table as empty (ignore HA_STATUS_TIME hack). +*/ +#define HA_STATUS_OPEN 256U /* Errorcodes given by handler functions diff --git a/mysql-test/suite/versioning/r/partition.result b/mysql-test/suite/versioning/r/partition.result index 2a42545755b..ad9ecdfccbf 100644 --- a/mysql-test/suite/versioning/r/partition.result +++ b/mysql-test/suite/versioning/r/partition.result @@ -159,6 +159,12 @@ x 2 create or replace table t1 (x int) with system versioning +partition by system_time limit 1 ( +partition p0 versioning, +partition pn as of now); +alter table t1 change x big int; +create or replace table t1 (x int) +with system versioning partition by system_time ( partition p0 versioning, partition pn as of now); diff --git a/mysql-test/suite/versioning/t/partition.test b/mysql-test/suite/versioning/t/partition.test index cbc02d44e31..479b63399bf 100644 --- a/mysql-test/suite/versioning/t/partition.test +++ b/mysql-test/suite/versioning/t/partition.test @@ -89,6 +89,14 @@ alter table t1 drop partition p0; select x from t1; +# Bug #260: incorrect IB partitioning warning +create or replace table t1 (x int) +with system versioning +partition by system_time limit 1 ( + partition p0 versioning, + partition pn as of now); +alter table t1 change x big int; + # insert, delete, update create or replace table t1 (x int) with system versioning diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 68fffa24a02..efdbf6f7e18 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -3550,7 +3550,7 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) m_part_info->part_expr->get_monotonicity_info(); else if (m_part_info->list_of_part_fields) m_part_func_monotonicity_info= MONOTONIC_STRICT_INCREASING; - info(HA_STATUS_VARIABLE | HA_STATUS_CONST); + info(HA_STATUS_OPEN | HA_STATUS_VARIABLE | HA_STATUS_CONST); DBUG_RETURN(0); err_handler: @@ -6550,6 +6550,7 @@ int ha_partition::info(uint flag) { uint no_lock_flag= flag & HA_STATUS_NO_LOCK; uint extra_var_flag= flag & HA_STATUS_VARIABLE_EXTRA; + uint open_flag= flag & HA_STATUS_OPEN; DBUG_ENTER("ha_partition::info"); #ifndef DBUG_OFF @@ -6590,7 +6591,7 @@ int ha_partition::info(uint flag) do { file= *file_array; - file->info(HA_STATUS_AUTO | no_lock_flag); + file->info(HA_STATUS_AUTO | no_lock_flag | open_flag); set_if_bigger(auto_increment_value, file->stats.auto_increment_value); } while (*(++file_array)); @@ -6644,7 +6645,7 @@ int ha_partition::info(uint flag) i= bitmap_get_next_set(&m_part_info->read_partitions, i)) { file= m_file[i]; - file->info(HA_STATUS_VARIABLE | no_lock_flag | extra_var_flag); + file->info(HA_STATUS_VARIABLE | no_lock_flag | extra_var_flag | open_flag); stats.records+= file->stats.records; stats.deleted+= file->stats.deleted; stats.data_file_length+= file->stats.data_file_length; @@ -6725,7 +6726,7 @@ int ha_partition::info(uint flag) if (!(flag & HA_STATUS_VARIABLE) || !bitmap_is_set(&(m_part_info->read_partitions), (file_array - m_file))) - file->info(HA_STATUS_VARIABLE | no_lock_flag | extra_var_flag); + file->info(HA_STATUS_VARIABLE | no_lock_flag | extra_var_flag | open_flag); if (file->stats.records > max_records) { max_records= file->stats.records; @@ -6744,7 +6745,7 @@ int ha_partition::info(uint flag) this); file= m_file[handler_instance]; - file->info(HA_STATUS_CONST | no_lock_flag); + file->info(HA_STATUS_CONST | no_lock_flag | open_flag); stats.block_size= file->stats.block_size; stats.create_time= file->stats.create_time; ref_length= m_ref_length; @@ -6760,7 +6761,7 @@ int ha_partition::info(uint flag) Note: all engines does not support HA_STATUS_ERRKEY, so set errkey. */ file->errkey= errkey; - file->info(HA_STATUS_ERRKEY | no_lock_flag); + file->info(HA_STATUS_ERRKEY | no_lock_flag | open_flag); errkey= file->errkey; } if (flag & HA_STATUS_TIME) @@ -6777,7 +6778,7 @@ int ha_partition::info(uint flag) do { file= *file_array; - file->info(HA_STATUS_TIME | no_lock_flag); + file->info(HA_STATUS_TIME | no_lock_flag | open_flag); if (file->stats.update_time > stats.update_time) stats.update_time= file->stats.update_time; } while (*(++file_array)); diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 0eb96aa2d00..df5a3544a30 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -1368,7 +1368,7 @@ public: { handler *file= m_file[part_id]; DBUG_ASSERT(bitmap_is_set(&(m_part_info->read_partitions), part_id)); - file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); + file->info(HA_STATUS_OPEN | HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); part_recs+= file->stats.records; } return part_recs; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 08ba4d84d9b..051249db997 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -3426,11 +3426,21 @@ int vers_get_partition_id(partition_info *part_info, DBUG_ASSERT(part_info); Field *sys_trx_end= part_info->part_field_array[STAT_TRX_END]; DBUG_ASSERT(sys_trx_end); - DBUG_ASSERT(part_info->table); + TABLE *table= part_info->table; + DBUG_ASSERT(table); Vers_part_info *vers_info= part_info->vers_info; - DBUG_ASSERT(vers_info && vers_info->initialized()); - DBUG_ASSERT(sys_trx_end->table == part_info->table && part_info->table->versioned()); - DBUG_ASSERT(part_info->table->vers_end_field() == sys_trx_end); + DBUG_ASSERT(vers_info); + DBUG_ASSERT(vers_info->initialized()); + DBUG_ASSERT(sys_trx_end->table == table); + bool tmp_off= false; + if (!table->versioned() && table->file->native_versioned()) + { + // in copy_data_between_tables() versioning may be temporarily turned off + tmp_off= true; + table->s->versioned= true; + } + DBUG_ASSERT(table->versioned()); + DBUG_ASSERT(table->vers_end_field() == sys_trx_end); // new rows have NULL in sys_trx_end if (sys_trx_end->is_max() || sys_trx_end->is_null()) @@ -3440,7 +3450,6 @@ int vers_get_partition_id(partition_info *part_info, else // row is historical { THD *thd= current_thd; - TABLE *table= part_info->table; switch (thd->lex->sql_command) { @@ -3478,6 +3487,9 @@ int vers_get_partition_id(partition_info *part_info, *part_id= vers_info->hist_part->id; } + if (tmp_off) + table->s->versioned= false; + DBUG_PRINT("exit",("partition: %d", *part_id)); DBUG_RETURN(0); } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index d4b5b89ac30..2a34ee85922 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -6862,7 +6862,7 @@ ha_innobase::open( } } - info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST); + info(HA_STATUS_OPEN | HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST); DBUG_RETURN(0); } @@ -14958,7 +14958,7 @@ ha_innobase::info_low( set. That way SHOW TABLE STATUS will show the best estimate, while the optimizer never sees the table empty. */ - if (n_rows == 0 && !(flag & HA_STATUS_TIME)) { + if (n_rows == 0 && !(flag & (HA_STATUS_TIME | HA_STATUS_OPEN))) { n_rows++; } -- cgit v1.2.1 From 9ba635fda3cddf94223ec4800858660f007b37fe Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Thu, 14 Sep 2017 13:56:24 +0300 Subject: SQL: VIEW with UNION fix [fixes #269] --- mysql-test/suite/versioning/r/view.result | 4 ++++ mysql-test/suite/versioning/t/view.test | 3 +++ sql/sql_select.cc | 4 ++++ sql/sql_view.cc | 8 +++++--- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/versioning/r/view.result b/mysql-test/suite/versioning/r/view.result index 7d43df2a914..6a65e3ef644 100644 --- a/mysql-test/suite/versioning/r/view.result +++ b/mysql-test/suite/versioning/r/view.result @@ -187,6 +187,10 @@ create or replace view vt1 as select a, t2.sys_trx_end as endo from t3, t1, t2; show create view vt1; View Create View character_set_client collation_connection vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`a` AS `a`,`t2`.`sys_trx_end` AS `endo`,`t2`.`sys_trx_start` AS `sys_trx_start` from ((`t3` join `t1` FOR SYSTEM_TIME ALL) join `t2` FOR SYSTEM_TIME ALL) where `t1`.`sys_trx_end` = 18446744073709551615 and `t2`.`sys_trx_end` = 18446744073709551615 latin1 latin1_swedish_ci +create or replace view vt1 as select * from t1 union select * from t1; +select * from vt1; +a +1 create or replace view vvt1 as select * from t1, t2, vt1; ERROR HY000: Creating VIEW `vvt1` is prohibited: versioned VIEW `vt1` in query! drop view vt1, vt12; diff --git a/mysql-test/suite/versioning/t/view.test b/mysql-test/suite/versioning/t/view.test index 5b7b267ff38..bd95d0fdfd3 100644 --- a/mysql-test/suite/versioning/t/view.test +++ b/mysql-test/suite/versioning/t/view.test @@ -85,6 +85,9 @@ show create view vt1; create or replace view vt1 as select a, t2.sys_trx_end as endo from t3, t1, t2; show create view vt1; +create or replace view vt1 as select * from t1 union select * from t1; +select * from vt1; + --error ER_VERS_VIEW_PROHIBITED create or replace view vvt1 as select * from t1, t2, vt1; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a5f1e3c9626..9a9dbb2893e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -17079,6 +17079,10 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List &fields, share->row_start_field= sys_trx_start->field_index; share->row_end_field= sys_trx_end->field_index; } + else + { + DBUG_ASSERT(!sys_trx_start && !sys_trx_end); + } DBUG_ASSERT(fieldnr == (uint) (reg_field - table->field)); DBUG_ASSERT(field_count >= (uint) (reg_field - table->field)); diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 4626a0369fb..179026ce80a 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -453,10 +453,12 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, goto err; } + for (SELECT_LEX *sl= select_lex; sl; sl= sl->next_select()) { /* System Versioning: fix system fields of versioned view */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat" #pragma GCC diagnostic ignored "-Wformat-extra-args" + // Similar logic as in mysql_derived_prepare() // Leading versioning table detected implicitly (first one selected) TABLE_LIST *impli_table= NULL; // Leading versioning table specified explicitly @@ -498,7 +500,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, /* Implicitly add versioning fields if needed */ Item *item; - List_iterator_fast it(select_lex->item_list); + List_iterator_fast it(sl->item_list); DBUG_ASSERT(table->alias); while ((item= it++)) @@ -577,9 +579,9 @@ expli_table_err: if (impli_table) { - if (!expli_start && select_lex->vers_push_field(thd, impli_table, impli_start)) + if (!expli_start && sl->vers_push_field(thd, impli_table, impli_start)) goto err; - if (!expli_end && select_lex->vers_push_field(thd, impli_table, impli_end)) + if (!expli_end && sl->vers_push_field(thd, impli_table, impli_end)) goto err; } #pragma GCC diagnostic pop -- cgit v1.2.1 From 6c9b71d734cf666e9ddb44bb6a7766c224dc90b3 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 20 Sep 2017 13:07:15 +0300 Subject: SQL: VTMD for OR REPLACE [fixes #270] --- mysql-test/suite/versioning/r/vtmd.result | 12 ++++--- mysql-test/suite/versioning/t/vtmd.test | 10 ++++-- sql/mysqld.h | 2 +- sql/sql_table.cc | 52 +++++++++++++++++++------------ sql/vtmd.cc | 7 +++-- 5 files changed, 52 insertions(+), 31 deletions(-) diff --git a/mysql-test/suite/versioning/r/vtmd.result b/mysql-test/suite/versioning/r/vtmd.result index ad72da94df3..92c922569fa 100644 --- a/mysql-test/suite/versioning/r/vtmd.result +++ b/mysql-test/suite/versioning/r/vtmd.result @@ -37,7 +37,7 @@ set @start= null; select start from tmp_vtmd for system_time all order by start limit 1 into @start; select @start > 0 and @start < @inf; select -start + 0 = @start as A_start, +start >= @start as A_start, (@start:= end) and end = @inf as B_end, name, substr(archive_name, 1, instr(archive_name, '_')) as C_archive_name @@ -45,12 +45,12 @@ from tmp_vtmd for system_time all; drop table tmp_vtmd; end~~ set versioning_alter_history= keep; -create or replace table t0 (x int) with system versioning; +create table t0 (z int) with system versioning; show tables; Tables_in_test t0 set versioning_alter_history= survive; -create or replace table t0 (x int) with system versioning; +create or replace table t0 (y int) with system versioning; show tables; Tables_in_test t0 @@ -75,14 +75,18 @@ A_start B_end name C_archive_name set versioning_alter_history= keep; drop table t0; set versioning_alter_history= survive; -create or replace table t0 (x int) with system versioning; +create table t0 (x int) with system versioning; ERROR HY000: VTMD error: `test.t0_vtmd` exists and not empty! +drop table t0_vtmd; +create table t0 (y int) with system versioning; +create or replace table t0 (x int) with system versioning; alter table t0 add column (y int); call check_vtmd('t0_vtmd'); @start > 0 and @start < @inf 1 A_start B_end name C_archive_name 1 0 t0 t0_ +1 0 t0 t0_ 1 1 t0 NULL call drop_archives('t0_vtmd'); drop table t0_vtmd; diff --git a/mysql-test/suite/versioning/t/vtmd.test b/mysql-test/suite/versioning/t/vtmd.test index 8ff2f64dc73..5024739fbe5 100644 --- a/mysql-test/suite/versioning/t/vtmd.test +++ b/mysql-test/suite/versioning/t/vtmd.test @@ -46,7 +46,7 @@ begin select start from tmp_vtmd for system_time all order by start limit 1 into @start; select @start > 0 and @start < @inf; select - start + 0 = @start as A_start, + start >= @start as A_start, (@start:= end) and end = @inf as B_end, name, substr(archive_name, 1, instr(archive_name, '_')) as C_archive_name @@ -58,10 +58,10 @@ delimiter ;~~ # create set versioning_alter_history= keep; -create or replace table t0 (x int) with system versioning; +create table t0 (z int) with system versioning; show tables; set versioning_alter_history= survive; -create or replace table t0 (x int) with system versioning; +create or replace table t0 (y int) with system versioning; show tables; show create table t0_vtmd; call check_vtmd('t0_vtmd'); @@ -70,6 +70,10 @@ set versioning_alter_history= keep; drop table t0; set versioning_alter_history= survive; --error ER_VERS_VTMD_ERROR +create table t0 (x int) with system versioning; + +drop table t0_vtmd; +create table t0 (y int) with system versioning; create or replace table t0 (x int) with system versioning; # alter diff --git a/sql/mysqld.h b/sql/mysqld.h index a30612067ba..47776b8288c 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -211,7 +211,7 @@ enum vers_hide_enum enum vers_alter_history_enum { - VERS_ALTER_HISTORY_KEEP, + VERS_ALTER_HISTORY_KEEP= 0, VERS_ALTER_HISTORY_SURVIVE, VERS_ALTER_HISTORY_DROP }; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 1831eecbd26..3866e661f72 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2438,6 +2438,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, else { char *end; + int frm_delete_error= 0; /* It could happen that table's share in the table definition cache is the only thing that keeps the engine plugin loaded @@ -2476,7 +2477,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, // Remove extension for delete *(end= path + path_length - reg_ext_length)= '\0'; - if (thd->lex->sql_command == SQLCOM_DROP_TABLE && + if ((thd->lex->sql_command == SQLCOM_DROP_TABLE || + thd->lex->sql_command == SQLCOM_CREATE_TABLE) && thd->variables.vers_alter_history == VERS_ALTER_HISTORY_SURVIVE && table_type && table_type != view_pseudo_hton) { @@ -2493,29 +2495,33 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, drop_table: error= ha_delete_table(thd, table_type, path, db, table->table_name, !dont_log_query); + if (!error) + { + /* Delete the table definition file */ + strmov(end,reg_ext); + if (table_type && table_type != view_pseudo_hton && + table_type->discover_table) + { + /* + Table type is using discovery and may not need a .frm file. + Delete it silently if it exists + */ + (void) mysql_file_delete(key_file_frm, path, MYF(0)); + } + else if (mysql_file_delete(key_file_frm, path, + MYF(MY_WME))) + { + frm_delete_error= my_errno; + DBUG_ASSERT(frm_delete_error); + } + } } if (!error) { - int frm_delete_error, trigger_drop_error= 0; - /* Delete the table definition file */ - strmov(end,reg_ext); - if (table_type && table_type != view_pseudo_hton && - table_type->discover_table) - { - /* - Table type is using discovery and may not need a .frm file. - Delete it silently if it exists - */ - (void) mysql_file_delete(key_file_frm, path, MYF(0)); - frm_delete_error= 0; - } - else - frm_delete_error= mysql_file_delete(key_file_frm, path, - MYF(MY_WME)); - if (frm_delete_error) - frm_delete_error= my_errno; - else + int trigger_drop_error= 0; + + if (!frm_delete_error) { non_tmp_table_deleted= TRUE; trigger_drop_error= @@ -2534,7 +2540,10 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, if (!error && vtmd.exists) { + enum_sql_command sql_command= thd->lex->sql_command; + thd->lex->sql_command= SQLCOM_DROP_TABLE; error= vtmd.update(thd); + thd->lex->sql_command= sql_command; if (error) mysql_rename_table(table_type, table->db, vtmd.archive_name(), table->db, table->table_name, NO_FK_CHECKS); @@ -5081,6 +5090,9 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, VTMD_table vtmd(*create_table); if (vtmd.update(thd)) { + thd->variables.vers_alter_history = VERS_ALTER_HISTORY_KEEP; + mysql_rm_table_no_locks(thd, create_table, 0, 0, 0, 0, 1, 1); + thd->variables.vers_alter_history = VERS_ALTER_HISTORY_SURVIVE; result= 1; goto err; } diff --git a/sql/vtmd.cc b/sql/vtmd.cc index 83a6fb512ef..58d9bb311bb 100644 --- a/sql/vtmd.cc +++ b/sql/vtmd.cc @@ -237,10 +237,9 @@ VTMD_table::update(THD *thd, const char* archive_name) { err: vtmd->file->print_error(error, MYF(0)); - goto quit; } - - result= false; + else + result= local_da.is_error(); } quit: @@ -436,6 +435,8 @@ VTMD_rename::try_rename(THD *thd, LString new_db, LString new_alias, const char if (lock_table_names(thd, &vtmd_tl, 0, thd->variables.lock_wait_timeout, 0)) return true; tdc_remove_table(thd, TDC_RT_REMOVE_ALL, about.db, vtmd_name, false); + if (local_da.is_error()) // just safety check + return true; bool rc= mysql_rename_table(hton, about.db, vtmd_name, new_db, vtmd_new_name, -- cgit v1.2.1 From 11a9d8f7e3d1d3d7d75b2caea6a62b7da943f7f8 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 20 Sep 2017 13:14:16 +0300 Subject: Tests: typo fix in cte.test Related to c2c8808a16e561bb43ef448fa1b47ae5e32a0f40 --- mysql-test/suite/versioning/r/cte.result | 2 +- mysql-test/suite/versioning/t/cte.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/versioning/r/cte.result b/mysql-test/suite/versioning/r/cte.result index e3b6ba0876e..161255aeaa7 100644 --- a/mysql-test/suite/versioning/r/cte.result +++ b/mysql-test/suite/versioning/r/cte.result @@ -24,7 +24,7 @@ insert into emp (emp_id, name, salary, dept_id, mgr) values (1, "bill", 1000, 10, null), (20, "john", 500, 10, 1), (30, "jane", 750, 10,1 ); -select vtq_commit_ts(max(sys_trx_start + 0)) into @ts_1 from emp; +select vtq_commit_ts(max(sys_trx_start)) into @ts_1 from emp; update emp set mgr=30 where name ="john"; select vtq_commit_ts(sys_trx_start) into @ts_2 from emp where name="john"; /* All report to 'Bill' */ diff --git a/mysql-test/suite/versioning/t/cte.test b/mysql-test/suite/versioning/t/cte.test index 50680f2f375..7a35352f7c8 100644 --- a/mysql-test/suite/versioning/t/cte.test +++ b/mysql-test/suite/versioning/t/cte.test @@ -28,7 +28,7 @@ insert into emp (emp_id, name, salary, dept_id, mgr) values (20, "john", 500, 10, 1), (30, "jane", 750, 10,1 ); -select vtq_commit_ts(max(sys_trx_start + 0)) into @ts_1 from emp; +select vtq_commit_ts(max(sys_trx_start)) into @ts_1 from emp; update emp set mgr=30 where name ="john"; select vtq_commit_ts(sys_trx_start) into @ts_2 from emp where name="john"; -- cgit v1.2.1 From 3b7c10f0b75744774f1d39a787be25e97d15272d Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 20 Sep 2017 14:32:48 +0300 Subject: Style: garbage Copy_field member --- sql/field.h | 1 - 1 file changed, 1 deletion(-) diff --git a/sql/field.h b/sql/field.h index 219f88ced0a..dc2db41c43e 100644 --- a/sql/field.h +++ b/sql/field.h @@ -4258,7 +4258,6 @@ public: uint from_length,to_length; Field *from_field,*to_field; String tmp; // For items - MYSQL_TIME now; // Used for sys_trx_start Copy_field() {} ~Copy_field() {} -- cgit v1.2.1 From 7f2064780cb8960697bef17c7ae63be565690eec Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Fri, 22 Sep 2017 22:09:41 +0300 Subject: SQL: versioning_alter_history values description --- sql/sys_vars.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 25437f7b3b4..3dc5706b9b2 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -409,7 +409,10 @@ static Sys_var_mybool Sys_vers_innodb_algorithm_simple( static const char *vers_alter_history_keywords[]= {"KEEP", "SURVIVE", "DROP", NULL}; static Sys_var_enum Sys_vers_alter_history( - "versioning_alter_history", "Versioning ALTER TABLE mode", + "versioning_alter_history", "Versioning ALTER TABLE mode. " + "KEEP: leave historical system rows as is on ALTER TABLE; " + "SURVIVE: use DDL survival feature; " + "DROP: delete historical system rows on ALTER TABLE", SESSION_VAR(vers_alter_history), CMD_LINE(OPT_ARG), vers_alter_history_keywords, DEFAULT(VERS_ALTER_HISTORY_KEEP)); -- cgit v1.2.1 From f79c4469ff8a17dee54f41786b76197dc2e17626 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Mon, 25 Sep 2017 11:29:16 +0300 Subject: SQL: helpers to get archive tables list [closes #199] --- sql/sql_show.cc | 2 +- sql/sql_show.h | 3 +++ sql/vtmd.cc | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ sql/vtmd.h | 4 ++++ 4 files changed, 79 insertions(+), 1 deletion(-) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 30fd1b43e4c..ac340892505 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -4218,7 +4218,7 @@ int schema_tables_add(THD *thd, Dynamic_array *files, @retval 2 Not fatal error; Safe to ignore this file list */ -static int +int make_table_name_list(THD *thd, Dynamic_array *table_names, LEX *lex, LOOKUP_FIELD_VALUES *lookup_field_vals, LEX_STRING *db_name) diff --git a/sql/sql_show.h b/sql/sql_show.h index e93b855450c..03ff539e959 100644 --- a/sql/sql_show.h +++ b/sql/sql_show.h @@ -199,6 +199,9 @@ typedef struct st_lookup_field_values bool wild_table_value; } LOOKUP_FIELD_VALUES; +int make_table_name_list(THD *thd, Dynamic_array *table_names, + LEX *lex, LOOKUP_FIELD_VALUES *lookup_field_vals, + LEX_STRING *db_name); /* INFORMATION_SCHEMA: Execution plan for get_all_tables() call diff --git a/sql/vtmd.cc b/sql/vtmd.cc index 58d9bb311bb..aa9245570f4 100644 --- a/sql/vtmd.cc +++ b/sql/vtmd.cc @@ -6,6 +6,7 @@ #include "sql_select.h" #include "table_cache.h" // tdc_remove_table() #include "key.h" +#include "sql_show.h" LString VERS_VTMD_TEMPLATE(C_STRING_WITH_LEN("vtmd_template")); @@ -573,3 +574,73 @@ err: close_log_table(thd, &open_tables_backup); return error ? true : false; } + +Dynamic_array VTMD_table::get_archive_tables(THD *thd) +{ + Dynamic_array result; + + Dynamic_array vtmd_tables= get_vtmd_tables(thd); + for (uint i= 0; i < vtmd_tables.elements(); i++) + { + LEX_STRING table_name= *vtmd_tables.at(i); + + Open_tables_backup open_tables_backup; + TABLE_LIST table_list; + // Assume VTMD tables belongs to current db. + table_list.init_one_table(thd->db, strlen(thd->db), + LEX_STRING_WITH_LEN(table_name), table_name.str, + TL_READ); + + TABLE *table= open_log_table(thd, &table_list, &open_tables_backup); + if (!table) + return result; + + READ_RECORD read_record; + int error= 0; + SQL_SELECT *sql_select= make_select(table, 0, 0, NULL, NULL, 0, &error); + if (error) + goto error1; + if (error = init_read_record(&read_record, thd, table, sql_select, NULL, 1, 1, + false)) + goto error2; + + while (!(error= read_record.read_record(&read_record))) + { + Field *field= table->field[FLD_ARCHIVE_NAME]; + if (field->is_null()) + continue; + + String archive_name; + field->val_str(&archive_name); + archive_name.set_ascii(strmake_root(thd->mem_root, archive_name.c_ptr(), + archive_name.length()), + archive_name.length()); + result.push(archive_name); + } + + end_read_record(&read_record); + error2: + delete sql_select; + error1: + close_log_table(thd, &open_tables_backup); + + if (error) + break; + } + + return result; +} + +Dynamic_array get_vtmd_tables(THD *thd) +{ + // Note function retrieves table names from current db only. + LOOKUP_FIELD_VALUES lookup_field_values= { + *thd->make_lex_string(thd->db, strlen(thd->db)), + *thd->make_lex_string(C_STRING_WITH_LEN("%_vtmd")), false, true}; + + Dynamic_array table_names; + make_table_name_list(thd, &table_names, thd->lex, &lookup_field_values, + &lookup_field_values.db_value); + + return table_names; +} diff --git a/sql/vtmd.h b/sql/vtmd.h index 8588462f83f..8a838dc2f88 100644 --- a/sql/vtmd.h +++ b/sql/vtmd.h @@ -87,8 +87,12 @@ public: } bool find_archive_name(THD *thd, String &out); + + static Dynamic_array get_archive_tables(THD *thd); }; +Dynamic_array get_vtmd_tables(THD *thd); + class VTMD_exists : public VTMD_table { protected: -- cgit v1.2.1 From 75bc483d7a92ba1c912ac44c48e6749536b5fa45 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 25 Sep 2017 13:24:44 +0300 Subject: Tests: moved concat_execN() to common.inc --- mysql-test/suite/versioning/common.inc | 14 ++++++++++++++ mysql-test/suite/versioning/common_finish.inc | 2 ++ mysql-test/suite/versioning/r/alter.result | 14 ++++++++++++++ mysql-test/suite/versioning/r/auto_increment.result | 14 ++++++++++++++ mysql-test/suite/versioning/r/commit_id.result | 14 ++++++++++++++ mysql-test/suite/versioning/r/create.result | 12 ++++++++++++ mysql-test/suite/versioning/r/ddl.result | 4 ++-- mysql-test/suite/versioning/r/delete.result | 14 ++++++++++++++ mysql-test/suite/versioning/r/insert.result | 14 ++++++++++++++ mysql-test/suite/versioning/r/partition.result | 14 ++++++++++++++ mysql-test/suite/versioning/r/select.result | 14 ++++++++++++++ mysql-test/suite/versioning/r/select_sp.result | 14 ++++++++++++++ mysql-test/suite/versioning/r/update.result | 14 ++++++++++++++ mysql-test/suite/versioning/r/view.result | 14 ++++++++++++++ mysql-test/suite/versioning/t/ddl.test | 18 ------------------ 15 files changed, 170 insertions(+), 20 deletions(-) diff --git a/mysql-test/suite/versioning/common.inc b/mysql-test/suite/versioning/common.inc index fcd767b140e..3c4d11b84ab 100644 --- a/mysql-test/suite/versioning/common.inc +++ b/mysql-test/suite/versioning/common.inc @@ -66,6 +66,20 @@ begin drop table tmp; end if; end~~ + +create procedure concat_exec2(a varchar(255), b varchar(255)) +begin + prepare stmt from concat(a, b); + execute stmt; + deallocate prepare stmt; +end~~ + +create procedure concat_exec3(a varchar(255), b varchar(255), c varchar(255)) +begin + prepare stmt from concat(a, b, c); + execute stmt; + deallocate prepare stmt; +end~~ delimiter ;~~ let $default_engine= `select default_engine()`; diff --git a/mysql-test/suite/versioning/common_finish.inc b/mysql-test/suite/versioning/common_finish.inc index 0dbe07085c9..9a746f5a98c 100644 --- a/mysql-test/suite/versioning/common_finish.inc +++ b/mysql-test/suite/versioning/common_finish.inc @@ -3,3 +3,5 @@ drop procedure innodb_verify_vtq; drop function default_engine; drop function sys_commit_ts; drop function sys_datatype; +drop procedure concat_exec2; +drop procedure concat_exec3; diff --git a/mysql-test/suite/versioning/r/alter.result b/mysql-test/suite/versioning/r/alter.result index ccf6a31f39f..9e812769ee3 100644 --- a/mysql-test/suite/versioning/r/alter.result +++ b/mysql-test/suite/versioning/r/alter.result @@ -309,6 +309,18 @@ select * from tmp; drop table tmp; end if; end~~ +create procedure concat_exec2(a varchar(255), b varchar(255)) +begin +prepare stmt from concat(a, b); +execute stmt; +deallocate prepare stmt; +end~~ +create procedure concat_exec3(a varchar(255), b varchar(255), c varchar(255)) +begin +prepare stmt from concat(a, b, c); +execute stmt; +deallocate prepare stmt; +end~~ create or replace table t( a int ) engine=innodb; @@ -578,3 +590,5 @@ drop procedure innodb_verify_vtq; drop function default_engine; drop function sys_commit_ts; drop function sys_datatype; +drop procedure concat_exec2; +drop procedure concat_exec3; diff --git a/mysql-test/suite/versioning/r/auto_increment.result b/mysql-test/suite/versioning/r/auto_increment.result index 31604a62740..7eb027f52d6 100644 --- a/mysql-test/suite/versioning/r/auto_increment.result +++ b/mysql-test/suite/versioning/r/auto_increment.result @@ -60,6 +60,18 @@ select * from tmp; drop table tmp; end if; end~~ +create procedure concat_exec2(a varchar(255), b varchar(255)) +begin +prepare stmt from concat(a, b); +execute stmt; +deallocate prepare stmt; +end~~ +create procedure concat_exec3(a varchar(255), b varchar(255), c varchar(255)) +begin +prepare stmt from concat(a, b, c); +execute stmt; +deallocate prepare stmt; +end~~ create procedure test_01( sys_type varchar(255), engine varchar(255), @@ -184,3 +196,5 @@ drop procedure innodb_verify_vtq; drop function default_engine; drop function sys_commit_ts; drop function sys_datatype; +drop procedure concat_exec2; +drop procedure concat_exec3; diff --git a/mysql-test/suite/versioning/r/commit_id.result b/mysql-test/suite/versioning/r/commit_id.result index a9de17cb74c..a53ba70a9b3 100644 --- a/mysql-test/suite/versioning/r/commit_id.result +++ b/mysql-test/suite/versioning/r/commit_id.result @@ -60,6 +60,18 @@ select * from tmp; drop table tmp; end if; end~~ +create procedure concat_exec2(a varchar(255), b varchar(255)) +begin +prepare stmt from concat(a, b); +execute stmt; +deallocate prepare stmt; +end~~ +create procedure concat_exec3(a varchar(255), b varchar(255), c varchar(255)) +begin +prepare stmt from concat(a, b, c); +execute stmt; +deallocate prepare stmt; +end~~ create table t1( id int auto_increment primary key) with system versioning @@ -156,3 +168,5 @@ drop procedure innodb_verify_vtq; drop function default_engine; drop function sys_commit_ts; drop function sys_datatype; +drop procedure concat_exec2; +drop procedure concat_exec3; diff --git a/mysql-test/suite/versioning/r/create.result b/mysql-test/suite/versioning/r/create.result index f5d1566a785..851d287f31e 100644 --- a/mysql-test/suite/versioning/r/create.result +++ b/mysql-test/suite/versioning/r/create.result @@ -60,6 +60,18 @@ select * from tmp; drop table tmp; end if; end~~ +create procedure concat_exec2(a varchar(255), b varchar(255)) +begin +prepare stmt from concat(a, b); +execute stmt; +deallocate prepare stmt; +end~~ +create procedure concat_exec3(a varchar(255), b varchar(255), c varchar(255)) +begin +prepare stmt from concat(a, b, c); +execute stmt; +deallocate prepare stmt; +end~~ drop table if exists t1; create function if not exists non_default_engine() returns varchar(255) diff --git a/mysql-test/suite/versioning/r/ddl.result b/mysql-test/suite/versioning/r/ddl.result index 931697aeb47..0ba0b5de0d4 100644 --- a/mysql-test/suite/versioning/r/ddl.result +++ b/mysql-test/suite/versioning/r/ddl.result @@ -169,8 +169,6 @@ insert into t values (1); update t set a=2 where a=1; alter table t add column b int, algorithm=inplace; set versioning_alter_history = keep; -drop procedure concat_exec2; -drop procedure concat_exec3; drop function get_historical_table_name; drop procedure drop_last_historical; select * from mysql.vtmd_template; @@ -208,3 +206,5 @@ drop procedure innodb_verify_vtq; drop function default_engine; drop function sys_commit_ts; drop function sys_datatype; +drop procedure concat_exec2; +drop procedure concat_exec3; diff --git a/mysql-test/suite/versioning/r/delete.result b/mysql-test/suite/versioning/r/delete.result index 354543bf0ab..7b7e836f84d 100644 --- a/mysql-test/suite/versioning/r/delete.result +++ b/mysql-test/suite/versioning/r/delete.result @@ -60,6 +60,18 @@ select * from tmp; drop table tmp; end if; end~~ +create procedure concat_exec2(a varchar(255), b varchar(255)) +begin +prepare stmt from concat(a, b); +execute stmt; +deallocate prepare stmt; +end~~ +create procedure concat_exec3(a varchar(255), b varchar(255), c varchar(255)) +begin +prepare stmt from concat(a, b, c); +execute stmt; +deallocate prepare stmt; +end~~ create or replace procedure test_01( sys_type varchar(255), engine varchar(255), @@ -357,3 +369,5 @@ drop procedure innodb_verify_vtq; drop function default_engine; drop function sys_commit_ts; drop function sys_datatype; +drop procedure concat_exec2; +drop procedure concat_exec3; diff --git a/mysql-test/suite/versioning/r/insert.result b/mysql-test/suite/versioning/r/insert.result index f92bcdcbe19..d7b7bd972dc 100644 --- a/mysql-test/suite/versioning/r/insert.result +++ b/mysql-test/suite/versioning/r/insert.result @@ -60,6 +60,18 @@ select * from tmp; drop table tmp; end if; end~~ +create procedure concat_exec2(a varchar(255), b varchar(255)) +begin +prepare stmt from concat(a, b); +execute stmt; +deallocate prepare stmt; +end~~ +create procedure concat_exec3(a varchar(255), b varchar(255), c varchar(255)) +begin +prepare stmt from concat(a, b, c); +execute stmt; +deallocate prepare stmt; +end~~ create procedure test_01( sys_type varchar(255), engine varchar(255), @@ -354,3 +366,5 @@ drop procedure innodb_verify_vtq; drop function default_engine; drop function sys_commit_ts; drop function sys_datatype; +drop procedure concat_exec2; +drop procedure concat_exec3; diff --git a/mysql-test/suite/versioning/r/partition.result b/mysql-test/suite/versioning/r/partition.result index ad9ecdfccbf..2107c065a56 100644 --- a/mysql-test/suite/versioning/r/partition.result +++ b/mysql-test/suite/versioning/r/partition.result @@ -60,6 +60,18 @@ select * from tmp; drop table tmp; end if; end~~ +create procedure concat_exec2(a varchar(255), b varchar(255)) +begin +prepare stmt from concat(a, b); +execute stmt; +deallocate prepare stmt; +end~~ +create procedure concat_exec3(a varchar(255), b varchar(255), c varchar(255)) +begin +prepare stmt from concat(a, b, c); +execute stmt; +deallocate prepare stmt; +end~~ create table t1 (x int) with system versioning partition by range columns (x) ( @@ -361,3 +373,5 @@ drop procedure innodb_verify_vtq; drop function default_engine; drop function sys_commit_ts; drop function sys_datatype; +drop procedure concat_exec2; +drop procedure concat_exec3; diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index eabeaf0d85a..f4eb8c35d0e 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -60,6 +60,18 @@ select * from tmp; drop table tmp; end if; end~~ +create procedure concat_exec2(a varchar(255), b varchar(255)) +begin +prepare stmt from concat(a, b); +execute stmt; +deallocate prepare stmt; +end~~ +create procedure concat_exec3(a varchar(255), b varchar(255), c varchar(255)) +begin +prepare stmt from concat(a, b, c); +execute stmt; +deallocate prepare stmt; +end~~ create or replace table t1 ( x int unsigned, y int unsigned @@ -381,3 +393,5 @@ drop procedure innodb_verify_vtq; drop function default_engine; drop function sys_commit_ts; drop function sys_datatype; +drop procedure concat_exec2; +drop procedure concat_exec3; diff --git a/mysql-test/suite/versioning/r/select_sp.result b/mysql-test/suite/versioning/r/select_sp.result index 69fbc1255f1..a4d0bbfde0d 100644 --- a/mysql-test/suite/versioning/r/select_sp.result +++ b/mysql-test/suite/versioning/r/select_sp.result @@ -60,6 +60,18 @@ select * from tmp; drop table tmp; end if; end~~ +create procedure concat_exec2(a varchar(255), b varchar(255)) +begin +prepare stmt from concat(a, b); +execute stmt; +deallocate prepare stmt; +end~~ +create procedure concat_exec3(a varchar(255), b varchar(255), c varchar(255)) +begin +prepare stmt from concat(a, b, c); +execute stmt; +deallocate prepare stmt; +end~~ create procedure test_01() begin declare engine varchar(255) default default_engine(); @@ -424,3 +436,5 @@ drop procedure innodb_verify_vtq; drop function default_engine; drop function sys_commit_ts; drop function sys_datatype; +drop procedure concat_exec2; +drop procedure concat_exec3; diff --git a/mysql-test/suite/versioning/r/update.result b/mysql-test/suite/versioning/r/update.result index 48b3eec3c3d..a9f345963e5 100644 --- a/mysql-test/suite/versioning/r/update.result +++ b/mysql-test/suite/versioning/r/update.result @@ -60,6 +60,18 @@ select * from tmp; drop table tmp; end if; end~~ +create procedure concat_exec2(a varchar(255), b varchar(255)) +begin +prepare stmt from concat(a, b); +execute stmt; +deallocate prepare stmt; +end~~ +create procedure concat_exec3(a varchar(255), b varchar(255), c varchar(255)) +begin +prepare stmt from concat(a, b, c); +execute stmt; +deallocate prepare stmt; +end~~ create procedure test_01( sys_type varchar(255), engine varchar(255), @@ -577,3 +589,5 @@ drop procedure innodb_verify_vtq; drop function default_engine; drop function sys_commit_ts; drop function sys_datatype; +drop procedure concat_exec2; +drop procedure concat_exec3; diff --git a/mysql-test/suite/versioning/r/view.result b/mysql-test/suite/versioning/r/view.result index 6a65e3ef644..45bc113cc27 100644 --- a/mysql-test/suite/versioning/r/view.result +++ b/mysql-test/suite/versioning/r/view.result @@ -60,6 +60,18 @@ select * from tmp; drop table tmp; end if; end~~ +create procedure concat_exec2(a varchar(255), b varchar(255)) +begin +prepare stmt from concat(a, b); +execute stmt; +deallocate prepare stmt; +end~~ +create procedure concat_exec3(a varchar(255), b varchar(255), c varchar(255)) +begin +prepare stmt from concat(a, b, c); +execute stmt; +deallocate prepare stmt; +end~~ create table t1 (x int) with system versioning engine innodb; insert into t1 values (1); select now(6) into @t1; @@ -200,3 +212,5 @@ drop procedure innodb_verify_vtq; drop function default_engine; drop function sys_commit_ts; drop function sys_datatype; +drop procedure concat_exec2; +drop procedure concat_exec3; diff --git a/mysql-test/suite/versioning/t/ddl.test b/mysql-test/suite/versioning/t/ddl.test index ec014af4168..e5b5a4c429a 100644 --- a/mysql-test/suite/versioning/t/ddl.test +++ b/mysql-test/suite/versioning/t/ddl.test @@ -1,21 +1,6 @@ -- source suite/versioning/common.inc delimiter ~~; - -create procedure concat_exec2(a varchar(255), b varchar(255)) -begin - prepare stmt from concat(a, b); - execute stmt; - deallocate prepare stmt; -end~~ - -create procedure concat_exec3(a varchar(255), b varchar(255), c varchar(255)) -begin - prepare stmt from concat(a, b, c); - execute stmt; - deallocate prepare stmt; -end~~ - create function get_historical_table_name(table_name_arg varchar(255)) returns varchar(255) begin @@ -27,7 +12,6 @@ create procedure drop_last_historical(table_name_arg varchar(255)) begin call concat_exec2('drop table ', get_historical_table_name(table_name_arg)); end~~ - delimiter ;~~ set versioning_alter_history= survive; @@ -108,8 +92,6 @@ alter table t add column b int, algorithm=inplace; set versioning_alter_history = keep; -drop procedure concat_exec2; -drop procedure concat_exec3; drop function get_historical_table_name; drop procedure drop_last_historical; -- cgit v1.2.1 From 79e17b26fb5a05048a9ba78f8db471c043d3e410 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 27 Sep 2017 10:24:40 +0300 Subject: SQL: VTMD_table::get_archive_tables() misc fixes --- sql/vtmd.cc | 67 ++++++++++++++++++++++++++++++++++--------------------------- sql/vtmd.h | 5 +---- 2 files changed, 38 insertions(+), 34 deletions(-) diff --git a/sql/vtmd.cc b/sql/vtmd.cc index aa9245570f4..e0824957c1b 100644 --- a/sql/vtmd.cc +++ b/sql/vtmd.cc @@ -485,7 +485,8 @@ VTMD_rename::revert_rename(THD *thd, LString new_db) return rc; } -void VTMD_table::archive_name( +void +VTMD_table::archive_name( THD* thd, const char* table_name, char* new_name, @@ -497,7 +498,8 @@ void VTMD_table::archive_name( now.second, now.second_part); } -bool VTMD_table::find_archive_name(THD *thd, String &out) +bool +VTMD_table::find_archive_name(THD *thd, String &out) { String vtmd_name; if (about.vers_vtmd_name(vtmd_name)) @@ -575,11 +577,28 @@ err: return error ? true : false; } -Dynamic_array VTMD_table::get_archive_tables(THD *thd) +static +bool +get_vtmd_tables(THD *thd, Dynamic_array &table_names) { - Dynamic_array result; + // Note function retrieves table names from current db only. + LOOKUP_FIELD_VALUES lookup_field_values= { + *thd->make_lex_string(thd->db, strlen(thd->db)), + *thd->make_lex_string(C_STRING_WITH_LEN("%_vtmd")), false, true}; + + int res= make_table_name_list(thd, &table_names, thd->lex, &lookup_field_values, + &lookup_field_values.db_value); + + return res; +} + +bool +VTMD_table::get_archive_tables(THD *thd, Dynamic_array &result) +{ + Dynamic_array vtmd_tables; + if (get_vtmd_tables(thd, vtmd_tables)) + return true; - Dynamic_array vtmd_tables= get_vtmd_tables(thd); for (uint i= 0; i < vtmd_tables.elements(); i++) { LEX_STRING table_name= *vtmd_tables.at(i); @@ -593,16 +612,23 @@ Dynamic_array VTMD_table::get_archive_tables(THD *thd) TABLE *table= open_log_table(thd, &table_list, &open_tables_backup); if (!table) - return result; + return true; READ_RECORD read_record; int error= 0; SQL_SELECT *sql_select= make_select(table, 0, 0, NULL, NULL, 0, &error); if (error) - goto error1; - if (error = init_read_record(&read_record, thd, table, sql_select, NULL, 1, 1, - false)) - goto error2; + { + close_log_table(thd, &open_tables_backup); + return true; + } + error= init_read_record(&read_record, thd, table, sql_select, NULL, 1, 1, false); + if (error) + { + delete sql_select; + close_log_table(thd, &open_tables_backup); + return true; + } while (!(error= read_record.read_record(&read_record))) { @@ -619,28 +645,9 @@ Dynamic_array VTMD_table::get_archive_tables(THD *thd) } end_read_record(&read_record); - error2: delete sql_select; - error1: close_log_table(thd, &open_tables_backup); - - if (error) - break; } - return result; -} - -Dynamic_array get_vtmd_tables(THD *thd) -{ - // Note function retrieves table names from current db only. - LOOKUP_FIELD_VALUES lookup_field_values= { - *thd->make_lex_string(thd->db, strlen(thd->db)), - *thd->make_lex_string(C_STRING_WITH_LEN("%_vtmd")), false, true}; - - Dynamic_array table_names; - make_table_name_list(thd, &table_names, thd->lex, &lookup_field_values, - &lookup_field_values.db_value); - - return table_names; + return false; } diff --git a/sql/vtmd.h b/sql/vtmd.h index 8a838dc2f88..a7350d8b3fe 100644 --- a/sql/vtmd.h +++ b/sql/vtmd.h @@ -87,12 +87,9 @@ public: } bool find_archive_name(THD *thd, String &out); - - static Dynamic_array get_archive_tables(THD *thd); + bool get_archive_tables(THD *thd, Dynamic_array &result); }; -Dynamic_array get_vtmd_tables(THD *thd); - class VTMD_exists : public VTMD_table { protected: -- cgit v1.2.1 From e9e3cb0f6ef8b9a6a6f10b7006958d29a93a7eda Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 27 Sep 2017 14:29:25 +0300 Subject: SQL: VTMD for SHOW CREATE fixes [related to #125] --- mysql-test/suite/versioning/r/vtmd_show.result | 6 +- mysql-test/suite/versioning/t/vtmd_show.test | 2 +- sql/sql_show.cc | 25 +-- sql/vtmd.cc | 274 ++++++++++++------------- sql/vtmd.h | 11 +- 5 files changed, 155 insertions(+), 163 deletions(-) diff --git a/mysql-test/suite/versioning/r/vtmd_show.result b/mysql-test/suite/versioning/r/vtmd_show.result index a6991b2d0a1..4c77182c5de 100644 --- a/mysql-test/suite/versioning/r/vtmd_show.result +++ b/mysql-test/suite/versioning/r/vtmd_show.result @@ -51,7 +51,7 @@ drop table tt_vtmd; end~~ create table t (a int) with system versioning; show create table t for system_time as of now; -ERROR 42S02: Table 'test.t_vtmd' doesn't exist +ERROR HY000: VTMD error: Table 'test.t_vtmd' doesn't exist set versioning_alter_history=survive; create or replace table t (a int) with system versioning; show create table t for system_time between timestamp @tm1 and timestamp @tm1; @@ -59,9 +59,9 @@ ERROR HY000: SYSTEM_TIME range selector is prohibited show create table t for system_time from timestamp @tm1 to timestamp @tm1; ERROR HY000: SYSTEM_TIME range selector is prohibited show create table t for system_time as of timestamp '01-01-1990'; -ERROR HY000: VTMD error: failed to query VTMD table +ERROR HY000: VTMD error: Table 'test.t' doesn't exist show create table t for system_time as of timestamp '01-01-2020'; -ERROR HY000: VTMD error: failed to query VTMD table +ERROR HY000: VTMD error: Table 'test.t' doesn't exist drop table t; call drop_archives('t_vtmd'); drop table t_vtmd; diff --git a/mysql-test/suite/versioning/t/vtmd_show.test b/mysql-test/suite/versioning/t/vtmd_show.test index fdbdcbcae29..4397198c839 100644 --- a/mysql-test/suite/versioning/t/vtmd_show.test +++ b/mysql-test/suite/versioning/t/vtmd_show.test @@ -65,7 +65,7 @@ end~~ delimiter ;~~ create table t (a int) with system versioning; ---error ER_NO_SUCH_TABLE +--error ER_VERS_VTMD_ERROR show create table t for system_time as of now; set versioning_alter_history=survive; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index ac340892505..2ae9f27c6e9 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1270,23 +1270,22 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) */ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint(); - TABLE_LIST tl; - bool versioned_query= - table_list->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED; - String archive_name; - if (versioned_query) + TABLE_LIST archive; + bool versioned= table_list->vers_conditions; + if (versioned) { - DBUG_ASSERT(table_list->vers_conditions.type == FOR_SYSTEM_TIME_AS_OF); + String archive_name; + DBUG_ASSERT(table_list->vers_conditions == FOR_SYSTEM_TIME_AS_OF); VTMD_table vtmd(*table_list); if (vtmd.find_archive_name(thd, archive_name)) goto exit; - tl.init_one_table(table_list->db, table_list->db_length, archive_name.ptr(), + archive.init_one_table(table_list->db, table_list->db_length, archive_name.ptr(), archive_name.length(), archive_name.ptr(), TL_READ); - tl.alias= table_list->table_name; - tl.vers_force_alias= true; - table_list= &tl; + archive.alias= table_list->table_name; + archive.vers_force_alias= true; + table_list= &archive; } if (mysqld_show_create_get_fields(thd, table_list, &field_list, &buffer)) @@ -1302,9 +1301,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) protocol->store(table_list->view_name.str, system_charset_info); else { - if (versioned_query) - protocol->store(tl.alias, system_charset_info); - else if (table_list->schema_table) + if (table_list->schema_table) protocol->store(table_list->schema_table->table_name, system_charset_info); else @@ -1332,7 +1329,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) my_eof(thd); exit: - if (versioned_query) + if (versioned) { /* If commit fails, we should be able to reset the OK status. */ thd->get_stmt_da()->set_overwrite_status(true); diff --git a/sql/vtmd.cc b/sql/vtmd.cc index e0824957c1b..6ba55679ec4 100644 --- a/sql/vtmd.cc +++ b/sql/vtmd.cc @@ -54,17 +54,17 @@ VTMD_table::find_record(ulonglong sys_trx_end, bool &found) key_buf_t key; found= false; - DBUG_ASSERT(vtmd); + DBUG_ASSERT(vtmd.table); - if (key.allocate(vtmd->s->max_unique_length)) + if (key.allocate(vtmd.table->s->max_unique_length)) return true; DBUG_ASSERT(sys_trx_end); - vtmd->vers_end_field()->set_notnull(); - vtmd->vers_end_field()->store(sys_trx_end, true); - key_copy(key, vtmd->record[0], vtmd->key_info + IDX_TRX_END, 0); + vtmd.table->vers_end_field()->set_notnull(); + vtmd.table->vers_end_field()->store(sys_trx_end, true); + key_copy(key, vtmd.table->record[0], vtmd.table->key_info + IDX_TRX_END, 0); - error= vtmd->file->ha_index_read_idx_map(vtmd->record[1], IDX_TRX_END, + error= vtmd.table->file->ha_index_read_idx_map(vtmd.table->record[1], IDX_TRX_END, key, HA_WHOLE_KEY, HA_READ_KEY_EXACT); @@ -72,27 +72,59 @@ VTMD_table::find_record(ulonglong sys_trx_end, bool &found) { if (error == HA_ERR_RECORD_DELETED || error == HA_ERR_KEY_NOT_FOUND) return false; - vtmd->file->print_error(error, MYF(0)); + vtmd.table->file->print_error(error, MYF(0)); return true; } - restore_record(vtmd, record[1]); + restore_record(vtmd.table, record[1]); found= true; return false; } + +bool +VTMD_table::open(THD *thd, Local_da &local_da, bool *created) +{ + if (created) + *created= false; + + if (0 == vtmd_name.length() && about.vers_vtmd_name(vtmd_name)) + return true; + + while (true) // max 2 iterations + { + vtmd.init_one_table( + DB_WITH_LEN(about), + XSTRING_WITH_LEN(vtmd_name), + vtmd_name, + TL_WRITE_CONCURRENT_INSERT); + + TABLE *res= open_log_table(thd, &vtmd, &open_tables_backup); + if (res) + return false; + + if (created && !*created && local_da.is_error() && local_da.sql_errno() == ER_NO_SUCH_TABLE) + { + local_da.reset_diagnostics_area(); + if (create(thd)) + break; + *created= true; + } + else + break; + } + return true; +} + bool VTMD_table::update(THD *thd, const char* archive_name) { - TABLE_LIST vtmd_tl; bool result= true; - bool close_log= false; bool found= false; - bool created= false; + bool created; int error; size_t an_len= 0; - Open_tables_backup open_tables_backup; ulonglong save_thd_options; { Local_da local_da(thd, ER_VERS_VTMD_ERROR); @@ -100,34 +132,10 @@ VTMD_table::update(THD *thd, const char* archive_name) save_thd_options= thd->variables.option_bits; thd->variables.option_bits&= ~OPTION_BIN_LOG; - if (about.vers_vtmd_name(vtmd_name)) - goto quit; + if (open(thd, local_da, &created)) + goto open_error; - while (true) // max 2 iterations - { - vtmd_tl.init_one_table( - DB_WITH_LEN(about), - XSTRING_WITH_LEN(vtmd_name), - vtmd_name, - TL_WRITE_CONCURRENT_INSERT); - - vtmd= open_log_table(thd, &vtmd_tl, &open_tables_backup); - if (vtmd) - break; - - if (!created && local_da.is_error() && local_da.sql_errno() == ER_NO_SUCH_TABLE) - { - local_da.reset_diagnostics_area(); - if (create(thd)) - goto quit; - created= true; - continue; - } - goto quit; - } - close_log= true; - - if (!vtmd->versioned()) + if (!vtmd.table->versioned()) { my_message(ER_VERS_VTMD_ERROR, "VTMD is not versioned", MYF(0)); goto quit; @@ -136,64 +144,64 @@ VTMD_table::update(THD *thd, const char* archive_name) if (!created && find_record(ULONGLONG_MAX, found)) goto quit; - if ((error= vtmd->file->extra(HA_EXTRA_MARK_AS_LOG_TABLE))) + if ((error= vtmd.table->file->extra(HA_EXTRA_MARK_AS_LOG_TABLE))) { - vtmd->file->print_error(error, MYF(0)); + vtmd.table->file->print_error(error, MYF(0)); goto quit; } /* Honor next number columns if present */ - vtmd->next_number_field= vtmd->found_next_number_field; + vtmd.table->next_number_field= vtmd.table->found_next_number_field; - if (vtmd->s->fields != FIELD_COUNT) + if (vtmd.table->s->fields != FIELD_COUNT) { my_printf_error(ER_VERS_VTMD_ERROR, "`%s.%s` unexpected fields count: %d", MYF(0), - vtmd->s->db.str, vtmd->s->table_name.str, vtmd->s->fields); + vtmd.table->s->db.str, vtmd.table->s->table_name.str, vtmd.table->s->fields); goto quit; } if (archive_name) { an_len= strlen(archive_name); - vtmd->field[FLD_ARCHIVE_NAME]->store(archive_name, an_len, table_alias_charset); - vtmd->field[FLD_ARCHIVE_NAME]->set_notnull(); + vtmd.table->field[FLD_ARCHIVE_NAME]->store(archive_name, an_len, table_alias_charset); + vtmd.table->field[FLD_ARCHIVE_NAME]->set_notnull(); } else { - vtmd->field[FLD_ARCHIVE_NAME]->set_null(); + vtmd.table->field[FLD_ARCHIVE_NAME]->set_null(); } - vtmd->field[FLD_COL_RENAMES]->set_null(); + vtmd.table->field[FLD_COL_RENAMES]->set_null(); if (found) { if (thd->lex->sql_command == SQLCOM_CREATE_TABLE) { my_printf_error(ER_VERS_VTMD_ERROR, "`%s.%s` exists and not empty!", MYF(0), - vtmd->s->db.str, vtmd->s->table_name.str); + vtmd.table->s->db.str, vtmd.table->s->table_name.str); goto quit; } - vtmd->mark_columns_needed_for_update(); // not needed? + vtmd.table->mark_columns_needed_for_update(); // not needed? if (archive_name) { - vtmd->s->versioned= false; - error= vtmd->file->ha_update_row(vtmd->record[1], vtmd->record[0]); - vtmd->s->versioned= true; + vtmd.table->s->versioned= false; + error= vtmd.table->file->ha_update_row(vtmd.table->record[1], vtmd.table->record[0]); + vtmd.table->s->versioned= true; if (!error) { if (thd->lex->sql_command == SQLCOM_DROP_TABLE) { - error= vtmd->file->ha_delete_row(vtmd->record[0]); + error= vtmd.table->file->ha_delete_row(vtmd.table->record[0]); } else { DBUG_ASSERT(thd->lex->sql_command == SQLCOM_ALTER_TABLE); - ulonglong sys_trx_end= (ulonglong) vtmd->vers_start_field()->val_int(); - store_record(vtmd, record[1]); - vtmd->field[FLD_NAME]->store(TABLE_NAME_WITH_LEN(about), system_charset_info); - vtmd->field[FLD_NAME]->set_notnull(); - vtmd->field[FLD_ARCHIVE_NAME]->set_null(); - error= vtmd->file->ha_update_row(vtmd->record[1], vtmd->record[0]); + ulonglong sys_trx_end= (ulonglong) vtmd.table->vers_start_field()->val_int(); + store_record(vtmd.table, record[1]); + vtmd.table->field[FLD_NAME]->store(TABLE_NAME_WITH_LEN(about), system_charset_info); + vtmd.table->field[FLD_NAME]->set_notnull(); + vtmd.table->field[FLD_ARCHIVE_NAME]->set_null(); + error= vtmd.table->file->ha_update_row(vtmd.table->record[1], vtmd.table->record[0]); if (error) goto err; @@ -203,60 +211,58 @@ VTMD_table::update(THD *thd, const char* archive_name) bool found; if (find_record(sys_trx_end, found)) goto quit; - if (!found || !vtmd->field[FLD_ARCHIVE_NAME]->is_null()) + if (!found || !vtmd.table->field[FLD_ARCHIVE_NAME]->is_null()) break; - store_record(vtmd, record[1]); - vtmd->field[FLD_ARCHIVE_NAME]->store(archive_name, an_len, table_alias_charset); - vtmd->field[FLD_ARCHIVE_NAME]->set_notnull(); - vtmd->s->versioned= false; - error= vtmd->file->ha_update_row(vtmd->record[1], vtmd->record[0]); - vtmd->s->versioned= true; + store_record(vtmd.table, record[1]); + vtmd.table->field[FLD_ARCHIVE_NAME]->store(archive_name, an_len, table_alias_charset); + vtmd.table->field[FLD_ARCHIVE_NAME]->set_notnull(); + vtmd.table->s->versioned= false; + error= vtmd.table->file->ha_update_row(vtmd.table->record[1], vtmd.table->record[0]); + vtmd.table->s->versioned= true; if (error) goto err; - sys_trx_end= (ulonglong) vtmd->vers_start_field()->val_int(); + sys_trx_end= (ulonglong) vtmd.table->vers_start_field()->val_int(); } // while (true) } // else (thd->lex->sql_command != SQLCOM_DROP_TABLE) } // if (!error) } // if (archive_name) else { - vtmd->field[FLD_NAME]->store(TABLE_NAME_WITH_LEN(about), system_charset_info); - vtmd->field[FLD_NAME]->set_notnull(); - error= vtmd->file->ha_update_row(vtmd->record[1], vtmd->record[0]); + vtmd.table->field[FLD_NAME]->store(TABLE_NAME_WITH_LEN(about), system_charset_info); + vtmd.table->field[FLD_NAME]->set_notnull(); + error= vtmd.table->file->ha_update_row(vtmd.table->record[1], vtmd.table->record[0]); } } // if (found) else { - vtmd->field[FLD_NAME]->store(TABLE_NAME_WITH_LEN(about), system_charset_info); - vtmd->field[FLD_NAME]->set_notnull(); - vtmd->mark_columns_needed_for_insert(); // not needed? - error= vtmd->file->ha_write_row(vtmd->record[0]); + vtmd.table->field[FLD_NAME]->store(TABLE_NAME_WITH_LEN(about), system_charset_info); + vtmd.table->field[FLD_NAME]->set_notnull(); + vtmd.table->mark_columns_needed_for_insert(); // not needed? + error= vtmd.table->file->ha_write_row(vtmd.table->record[0]); } if (error) { err: - vtmd->file->print_error(error, MYF(0)); + vtmd.table->file->print_error(error, MYF(0)); } else result= local_da.is_error(); } quit: - if (close_log) - close_log_table(thd, &open_tables_backup); + close_log_table(thd, &open_tables_backup); +open_error: thd->variables.option_bits= save_thd_options; return result; } - bool VTMD_rename::move_archives(THD *thd, LString &new_db) { - TABLE_LIST vtmd_tl; - vtmd_tl.init_one_table( + vtmd.init_one_table( DB_WITH_LEN(about), XSTRING_WITH_LEN(vtmd_name), vtmd_name, @@ -269,66 +275,66 @@ VTMD_rename::move_archives(THD *thd, LString &new_db) Open_tables_backup open_tables_backup; key_buf_t key; - vtmd= open_log_table(thd, &vtmd_tl, &open_tables_backup); - if (!vtmd) + TABLE *res= open_log_table(thd, &vtmd, &open_tables_backup); + if (!res) return true; - if (key.allocate(vtmd->key_info[IDX_ARCHIVE_NAME].key_length)) + if (key.allocate(vtmd.table->key_info[IDX_ARCHIVE_NAME].key_length)) { close_log_table(thd, &open_tables_backup); return true; } - if ((error= vtmd->file->ha_start_keyread(IDX_ARCHIVE_NAME))) + if ((error= vtmd.table->file->ha_start_keyread(IDX_ARCHIVE_NAME))) goto err; end_keyread= true; - if ((error= vtmd->file->ha_index_init(IDX_ARCHIVE_NAME, true))) + if ((error= vtmd.table->file->ha_index_init(IDX_ARCHIVE_NAME, true))) goto err; index_end= true; - error= vtmd->file->ha_index_first(vtmd->record[0]); + error= vtmd.table->file->ha_index_first(vtmd.table->record[0]); while (!error) { - if (!vtmd->field[FLD_ARCHIVE_NAME]->is_null()) + if (!vtmd.table->field[FLD_ARCHIVE_NAME]->is_null()) { - vtmd->field[FLD_ARCHIVE_NAME]->val_str(&archive); + vtmd.table->field[FLD_ARCHIVE_NAME]->val_str(&archive); key_copy(key, - vtmd->record[0], - &vtmd->key_info[IDX_ARCHIVE_NAME], - vtmd->key_info[IDX_ARCHIVE_NAME].key_length, + vtmd.table->record[0], + &vtmd.table->key_info[IDX_ARCHIVE_NAME], + vtmd.table->key_info[IDX_ARCHIVE_NAME].key_length, false); - error= vtmd->file->ha_index_read_map( - vtmd->record[0], + error= vtmd.table->file->ha_index_read_map( + vtmd.table->record[0], key, - vtmd->key_info[IDX_ARCHIVE_NAME].ext_key_part_map, + vtmd.table->key_info[IDX_ARCHIVE_NAME].ext_key_part_map, HA_READ_PREFIX_LAST); if (!error) { if ((rc= move_table(thd, archive, new_db))) break; - error= vtmd->file->ha_index_next(vtmd->record[0]); + error= vtmd.table->file->ha_index_next(vtmd.table->record[0]); } } else { archive.length(0); - error= vtmd->file->ha_index_next(vtmd->record[0]); + error= vtmd.table->file->ha_index_next(vtmd.table->record[0]); } } if (error && error != HA_ERR_END_OF_FILE) { err: - vtmd->file->print_error(error, MYF(0)); + vtmd.table->file->print_error(error, MYF(0)); rc= true; } if (index_end) - vtmd->file->ha_index_end(); + vtmd.table->file->ha_index_end(); if (end_keyread) - vtmd->file->ha_end_keyread(); + vtmd.table->file->ha_end_keyread(); close_log_table(thd, &open_tables_backup); return rc; @@ -501,80 +507,64 @@ VTMD_table::archive_name( bool VTMD_table::find_archive_name(THD *thd, String &out) { - String vtmd_name; - if (about.vers_vtmd_name(vtmd_name)) - return true; - READ_RECORD info; - int error= 0; + int error; SQL_SELECT *select= NULL; COND *conds= NULL; List dummy; SELECT_LEX &select_lex= thd->lex->select_lex; - TABLE_LIST tl; - tl.init_one_table(about.db, about.db_length, vtmd_name.ptr(), - vtmd_name.length(), vtmd_name.ptr(), TL_READ); - - Open_tables_backup open_tables_backup; - if (!(vtmd= open_log_table(thd, &tl, &open_tables_backup))) - { - my_error(ER_VERS_VTMD_ERROR, MYF(0), "failed to open VTMD table"); + Local_da local_da(thd, ER_VERS_VTMD_ERROR); + if (open(thd, local_da)) return true; - } Name_resolution_context &ctx= thd->lex->select_lex.context; TABLE_LIST *table_list= ctx.table_list; TABLE_LIST *first_name_resolution_table= ctx.first_name_resolution_table; - table_map map = tl.table->map; - ctx.table_list= &tl; - ctx.first_name_resolution_table= &tl; - tl.table->map= 1; - - tl.vers_conditions= about.vers_conditions; - if ((error= vers_setup_select(thd, &tl, &conds, &select_lex)) || - (error= setup_conds(thd, &tl, dummy, &conds))) - { - my_error(ER_VERS_VTMD_ERROR, MYF(0), - "failed to setup conditions for querying VTMD table"); + table_map map = vtmd.table->map; + ctx.table_list= &vtmd; + ctx.first_name_resolution_table= &vtmd; + vtmd.table->map= 1; + + vtmd.vers_conditions= about.vers_conditions; + if ((error= vers_setup_select(thd, &vtmd, &conds, &select_lex)) || + (error= setup_conds(thd, &vtmd, dummy, &conds))) goto err; - } - select= make_select(tl.table, 0, 0, conds, NULL, 0, &error); + select= make_select(vtmd.table, 0, 0, conds, NULL, 0, &error); if (error) goto loc_err; - if ((error= - init_read_record(&info, thd, tl.table, select, NULL, 1, 1, false))) + + error= init_read_record(&info, thd, vtmd.table, select, NULL, + 1 /* use_record_cache */, true /* print_error */, + false /* disable_rr_cache */); + if (error) goto loc_err; while (!(error= info.read_record(&info)) && !thd->killed && !thd->is_error()) { if (select->skip_record(thd) > 0) { - tl.table->field[FLD_ARCHIVE_NAME]->val_str(&out); - - if (out.length() == 0) - { - // Handle AS OF NOW or just RENAMEd case - out.set(about.table_name, about.table_name_length, - system_charset_info); - } + vtmd.table->field[FLD_ARCHIVE_NAME]->val_str(&out); + if (out.length() == 0) // Handle AS OF NOW or RENAME TABLE case + out.set(about.table_name, about.table_name_length, system_charset_info); break; } } -loc_err: - if (error) - my_error(ER_VERS_VTMD_ERROR, MYF(0), "failed to query VTMD table"); + if (error < 0) + my_error(ER_NO_SUCH_TABLE, MYF(0), about.db, about.alias); +loc_err: end_read_record(&info); err: delete select; ctx.table_list= table_list; ctx.first_name_resolution_table= first_name_resolution_table; - tl.table->map= map; + vtmd.table->map= map; close_log_table(thd, &open_tables_backup); - return error ? true : false; + DBUG_ASSERT(!error || local_da.is_error()); + return error; } static diff --git a/sql/vtmd.h b/sql/vtmd.h index a7350d8b3fe..5a987723a47 100644 --- a/sql/vtmd.h +++ b/sql/vtmd.h @@ -48,8 +48,10 @@ class THD; class VTMD_table { + Open_tables_backup open_tables_backup; + protected: - TABLE *vtmd; + TABLE_LIST vtmd; const TABLE_LIST &about; SString_t vtmd_name; @@ -72,13 +74,16 @@ public: }; VTMD_table(TABLE_LIST &_about) : - vtmd(NULL), about(_about) - {} + { + vtmd.table= NULL; + } bool create(THD *thd); bool find_record(ulonglong sys_trx_end, bool &found); + bool open(THD *thd, Local_da &local_da, bool *created= NULL); bool update(THD *thd, const char* archive_name= NULL); + bool setup_select(THD *thd); static void archive_name(THD *thd, const char *table_name, char *new_name, size_t new_name_size); void archive_name(THD *thd, char *new_name, size_t new_name_size) -- cgit v1.2.1 From c5801dd67b86d2a3e27f05fcbdb01d20014019a2 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Wed, 27 Sep 2017 22:08:20 +0300 Subject: SQL: hide archive tables [closes #193] --- mysql-test/suite/versioning/r/ddl.result | 38 +++++++-------- mysql-test/suite/versioning/r/vtmd.result | 79 ++++++++++++++++++++++++++----- mysql-test/suite/versioning/t/ddl.test | 38 +++++++-------- mysql-test/suite/versioning/t/vtmd.test | 25 ++++++++-- sql/sql_show.cc | 61 ++++++++++++++++++++++++ sql/vtmd.cc | 25 +++++----- sql/vtmd.h | 3 +- 7 files changed, 204 insertions(+), 65 deletions(-) diff --git a/mysql-test/suite/versioning/r/ddl.result b/mysql-test/suite/versioning/r/ddl.result index 0ba0b5de0d4..1bfca2da8f6 100644 --- a/mysql-test/suite/versioning/r/ddl.result +++ b/mysql-test/suite/versioning/r/ddl.result @@ -72,15 +72,15 @@ prepare stmt from concat(a, b, c); execute stmt; deallocate prepare stmt; end~~ -create function get_historical_table_name(table_name_arg varchar(255)) +create function get_archive_table_name() returns varchar(255) begin -return (select table_name from information_schema.tables -where table_schema='test' and table_name like concat(table_name_arg, '_%') limit 1); +return (select archive_name from t_vtmd for system_time all where archive_name is not NULL +order by start desc limit 1); end~~ -create procedure drop_last_historical(table_name_arg varchar(255)) +create procedure drop_last_archive() begin -call concat_exec2('drop table ', get_historical_table_name(table_name_arg)); +call concat_exec2('drop table ', get_archive_table_name()); end~~ set versioning_alter_history= survive; create or replace table t (a int) with system versioning; @@ -91,21 +91,21 @@ alter table t add column b int; select * from t; a b 2 NULL -call concat_exec3('select * from ', get_historical_table_name('t'), ' for system_time all'); +call concat_exec3('select * from ', get_archive_table_name(), ' for system_time all'); a 2 1 -call concat_exec3('select @tm=sys_trx_start from ', get_historical_table_name('t'), ' for system_time all where a=2'); +call concat_exec3('select @tm=sys_trx_start from ', get_archive_table_name(), ' for system_time all where a=2'); @tm=sys_trx_start 1 select @tm 0 and @start < @inf @@ -206,10 +208,6 @@ show tables; Tables_in_db1 other_name other_name_vtmd -t0_TIMESTAMP_SUFFIX -t0_TIMESTAMP_SUFFIX -t0_TIMESTAMP_SUFFIX -t0_TIMESTAMP_SUFFIX call test.check_vtmd('db1.other_name_vtmd'); @start > 0 and @start < @inf 1 @@ -246,10 +244,6 @@ alter table t1 rename to test.t2, add column (y int); use test; show tables; Tables_in_test -t0_TIMESTAMP_SUFFIX -t0_TIMESTAMP_SUFFIX -t0_TIMESTAMP_SUFFIX -t0_TIMESTAMP_SUFFIX t2 t2_vtmd call check_vtmd('t2_vtmd'); @@ -279,6 +273,67 @@ A_start B_end name C_archive_name 1 0 t3 t3_ 1 0 t3 t3_ 1 1 t3 NULL +set versioning_hide = auto; +call show_tables(); +Tables_in_test +t2 +t2_vtmd +t3 +t3_vtmd +table_name table_schema +t2 test +t2_vtmd test +t3 test +t3_vtmd test +set versioning_hide = implicit; +call show_tables(); +Tables_in_test +t2 +t2_vtmd +t3 +t3_vtmd +table_name table_schema +t2 test +t2_vtmd test +t3 test +t3_vtmd test +set versioning_hide = full; +call show_tables(); +Tables_in_test +t2 +t2_vtmd +t3 +t3_vtmd +table_name table_schema +t2 test +t2_vtmd test +t3 test +t3_vtmd test +set versioning_hide = never; +call show_tables(); +Tables_in_test +t0_TIMESTAMP_SUFFIX +t0_TIMESTAMP_SUFFIX +t0_TIMESTAMP_SUFFIX +t0_TIMESTAMP_SUFFIX +t2 +t2_vtmd +t3 +t3_TIMESTAMP_SUFFIX +t3_TIMESTAMP_SUFFIX +t3_vtmd +table_name table_schema +t1_TIMESTAMP_SUFFIX db1 +t0_TIMESTAMP_SUFFIX test +t0_TIMESTAMP_SUFFIX test +t0_TIMESTAMP_SUFFIX test +t0_TIMESTAMP_SUFFIX test +t2 test +t2_vtmd test +t3 test +t3_TIMESTAMP_SUFFIX test +t3_TIMESTAMP_SUFFIX test +t3_vtmd test drop database db0; drop database db1; drop database test; diff --git a/mysql-test/suite/versioning/t/ddl.test b/mysql-test/suite/versioning/t/ddl.test index e5b5a4c429a..5be62281a6d 100644 --- a/mysql-test/suite/versioning/t/ddl.test +++ b/mysql-test/suite/versioning/t/ddl.test @@ -1,16 +1,16 @@ -- source suite/versioning/common.inc delimiter ~~; -create function get_historical_table_name(table_name_arg varchar(255)) +create function get_archive_table_name() returns varchar(255) begin - return (select table_name from information_schema.tables - where table_schema='test' and table_name like concat(table_name_arg, '_%') limit 1); + return (select archive_name from t_vtmd for system_time all where archive_name is not NULL + order by start desc limit 1); end~~ -create procedure drop_last_historical(table_name_arg varchar(255)) +create procedure drop_last_archive() begin - call concat_exec2('drop table ', get_historical_table_name(table_name_arg)); + call concat_exec2('drop table ', get_archive_table_name()); end~~ delimiter ;~~ @@ -23,14 +23,14 @@ select sys_trx_start from t where a=2 into @tm; alter table t add column b int; select * from t; -call concat_exec3('select * from ', get_historical_table_name('t'), ' for system_time all'); +call concat_exec3('select * from ', get_archive_table_name(), ' for system_time all'); -call concat_exec3('select @tm=sys_trx_start from ', get_historical_table_name('t'), ' for system_time all where a=2'); +call concat_exec3('select @tm=sys_trx_start from ', get_archive_table_name(), ' for system_time all where a=2'); select @tm &all_archive_tables) +{ + if (thd->variables.vers_hide == VERS_HIDE_NEVER) + return false; + + Dynamic_array all_db; + LOOKUP_FIELD_VALUES lookup_field_values= { + *thd->make_lex_string(C_STRING_WITH_LEN("%")), {NULL, 0}, true, false}; + if (make_db_list(thd, &all_db, &lookup_field_values)) + return true; + + LEX_STRING information_schema= {C_STRING_WITH_LEN("information_schema")}; + for (size_t i= 0; i < all_db.elements(); i++) + { + LEX_STRING db= *all_db.at(i); + if (db.length == information_schema.length && + !memcmp(db.str, information_schema.str, db.length)) + { + all_db.del(i); + break; + } + } + + for (size_t i= 0; i < all_db.elements(); i++) + { + LEX_STRING db_name= *all_db.at(i); + Dynamic_array archive_tables; + if (VTMD_table::get_archive_tables(thd, db_name.str, db_name.length, + archive_tables)) + return true; + for (size_t i= 0; i < archive_tables.elements(); i++) + if (all_archive_tables.push(archive_tables.at(i))) + return true; + } + + return false; +} + +static bool is_archive_table(const Dynamic_array &all_archive_tables, + LEX_STRING candidate) +{ + for (size_t i= 0; i < all_archive_tables.elements(); i++) + { + const String &archive_table= all_archive_tables.at(i); + if (candidate.length == archive_table.length() && + !memcmp(candidate.str, archive_table.ptr(), candidate.length)) + { + return true; + } + } + return false; +} /** @brief Fill I_S tables whose data are retrieved @@ -4905,6 +4958,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) #endif uint table_open_method= tables->table_open_method; bool can_deadlock; + Dynamic_array all_archive_tables; DBUG_ENTER("get_all_tables"); /* @@ -4967,6 +5021,10 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) if (make_db_list(thd, &db_names, &plan->lookup_field_vals)) goto err; + + if (get_all_archive_tables(thd, all_archive_tables)) + goto err; + for (size_t i=0; i < db_names.elements(); i++) { LEX_STRING *db_name= db_names.at(i); @@ -4992,6 +5050,9 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) LEX_STRING *table_name= table_names.at(i); DBUG_ASSERT(table_name->length <= NAME_LEN); + if (is_archive_table(all_archive_tables, *table_name)) + continue; + #ifndef NO_EMBEDDED_ACCESS_CHECKS if (!(thd->col_access & TABLE_ACLS)) { diff --git a/sql/vtmd.cc b/sql/vtmd.cc index 6ba55679ec4..679a70e3e80 100644 --- a/sql/vtmd.cc +++ b/sql/vtmd.cc @@ -569,24 +569,26 @@ err: static bool -get_vtmd_tables(THD *thd, Dynamic_array &table_names) +get_vtmd_tables(THD *thd, const char *db, + size_t db_length, Dynamic_array &table_names) { - // Note function retrieves table names from current db only. LOOKUP_FIELD_VALUES lookup_field_values= { - *thd->make_lex_string(thd->db, strlen(thd->db)), + *thd->make_lex_string(db, db_length), *thd->make_lex_string(C_STRING_WITH_LEN("%_vtmd")), false, true}; - int res= make_table_name_list(thd, &table_names, thd->lex, &lookup_field_values, - &lookup_field_values.db_value); + int res= + make_table_name_list(thd, &table_names, thd->lex, &lookup_field_values, + &lookup_field_values.db_value); return res; } bool -VTMD_table::get_archive_tables(THD *thd, Dynamic_array &result) +VTMD_table::get_archive_tables(THD *thd, const char *db, size_t db_length, + Dynamic_array &result) { Dynamic_array vtmd_tables; - if (get_vtmd_tables(thd, vtmd_tables)) + if (get_vtmd_tables(thd, db, db_length, vtmd_tables)) return true; for (uint i= 0; i < vtmd_tables.elements(); i++) @@ -595,10 +597,8 @@ VTMD_table::get_archive_tables(THD *thd, Dynamic_array &result) Open_tables_backup open_tables_backup; TABLE_LIST table_list; - // Assume VTMD tables belongs to current db. - table_list.init_one_table(thd->db, strlen(thd->db), - LEX_STRING_WITH_LEN(table_name), table_name.str, - TL_READ); + table_list.init_one_table(db, db_length, LEX_STRING_WITH_LEN(table_name), + table_name.str, TL_READ); TABLE *table= open_log_table(thd, &table_list, &open_tables_backup); if (!table) @@ -633,6 +633,9 @@ VTMD_table::get_archive_tables(THD *thd, Dynamic_array &result) archive_name.length()); result.push(archive_name); } + // check for EOF + if (!thd->is_error()) + error= 0; end_read_record(&read_record); delete sql_select; diff --git a/sql/vtmd.h b/sql/vtmd.h index 5a987723a47..a2b010ece7d 100644 --- a/sql/vtmd.h +++ b/sql/vtmd.h @@ -92,7 +92,8 @@ public: } bool find_archive_name(THD *thd, String &out); - bool get_archive_tables(THD *thd, Dynamic_array &result); + static bool get_archive_tables(THD *thd, const char *db, size_t db_length, + Dynamic_array &result); }; class VTMD_exists : public VTMD_table -- cgit v1.2.1 From 5e42511ce169d6883499d00072c309647f303aee Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Thu, 28 Sep 2017 13:16:04 +0300 Subject: SQL: SELECT from archive table [closes #127] --- mysql-test/suite/versioning/r/vtmd.result | 8 ++++++++ mysql-test/suite/versioning/t/vtmd.test | 4 ++++ sql/sql_parse.cc | 16 ++++++++++++++++ sql/sql_show.cc | 13 ++++++++----- sql/vtmd.cc | 21 +++++++++++++++++++-- sql/vtmd.h | 2 +- 6 files changed, 56 insertions(+), 8 deletions(-) diff --git a/mysql-test/suite/versioning/r/vtmd.result b/mysql-test/suite/versioning/r/vtmd.result index a8f8cf186b5..dae8914157b 100644 --- a/mysql-test/suite/versioning/r/vtmd.result +++ b/mysql-test/suite/versioning/r/vtmd.result @@ -86,7 +86,15 @@ ERROR HY000: VTMD error: `test.t0_vtmd` exists and not empty! drop table t0_vtmd; create table t0 (y int) with system versioning; create or replace table t0 (x int) with system versioning; +insert into t0 values (1); +set @t0= now(6); alter table t0 add column (y int); +select * from t0 for system_time as of @t0; +x +1 +select * from t0; +x y +1 NULL call check_vtmd('t0_vtmd'); @start > 0 and @start < @inf 1 diff --git a/mysql-test/suite/versioning/t/vtmd.test b/mysql-test/suite/versioning/t/vtmd.test index c3ebc2821b4..49cd85b60e1 100644 --- a/mysql-test/suite/versioning/t/vtmd.test +++ b/mysql-test/suite/versioning/t/vtmd.test @@ -86,7 +86,11 @@ create table t0 (y int) with system versioning; create or replace table t0 (x int) with system versioning; # alter +insert into t0 values (1); +set @t0= now(6); alter table t0 add column (y int); +select * from t0 for system_time as of @t0; +select * from t0; call check_vtmd('t0_vtmd'); call drop_archives('t0_vtmd'); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index cc0dcf9a3a8..69938946678 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -113,6 +113,7 @@ #include "wsrep_mysqld.h" #include "wsrep_thd.h" +#include "vtmd.h" static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length, Parser_state *parser_state, @@ -6373,6 +6374,21 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables) if (check_dependencies_in_with_clauses(lex->with_clauses_list)) return 1; + if (thd->variables.vers_alter_history == VERS_ALTER_HISTORY_SURVIVE) + { + for (TABLE_LIST *table= all_tables; table; table= table->next_local) + { + if (table->vers_conditions) + { + VTMD_exists vtmd(*table); + if (vtmd.check_exists(thd)) + return 1; + if (vtmd.exists && vtmd.setup_select(thd)) + return 1; + } + } + } + if (!(res= open_and_lock_tables(thd, all_tables, TRUE, 0))) { if (lex->describe) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index b886f42580f..eb5bcc300bf 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1280,12 +1280,15 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) if (vtmd.find_archive_name(thd, archive_name)) goto exit; - archive.init_one_table(table_list->db, table_list->db_length, archive_name.ptr(), - archive_name.length(), archive_name.ptr(), TL_READ); + if (archive_name.length() > 0) + { + archive.init_one_table(table_list->db, table_list->db_length, archive_name.ptr(), + archive_name.length(), archive_name.ptr(), TL_READ); - archive.alias= table_list->table_name; - archive.vers_force_alias= true; - table_list= &archive; + archive.alias= table_list->table_name; + archive.vers_force_alias= true; + table_list= &archive; + } } if (mysqld_show_create_get_fields(thd, table_list, &field_list, &buffer)) diff --git a/sql/vtmd.cc b/sql/vtmd.cc index 679a70e3e80..1ed9014331c 100644 --- a/sql/vtmd.cc +++ b/sql/vtmd.cc @@ -7,6 +7,8 @@ #include "table_cache.h" // tdc_remove_table() #include "key.h" #include "sql_show.h" +#include "sql_parse.h" +#include "sql_lex.h" LString VERS_VTMD_TEMPLATE(C_STRING_WITH_LEN("vtmd_template")); @@ -546,8 +548,6 @@ VTMD_table::find_archive_name(THD *thd, String &out) if (select->skip_record(thd) > 0) { vtmd.table->field[FLD_ARCHIVE_NAME]->val_str(&out); - if (out.length() == 0) // Handle AS OF NOW or RENAME TABLE case - out.set(about.table_name, about.table_name_length, system_charset_info); break; } } @@ -644,3 +644,20 @@ VTMD_table::get_archive_tables(THD *thd, const char *db, size_t db_length, return false; } + +bool VTMD_table::setup_select(THD* thd) +{ + SString archive_name; + if (find_archive_name(thd, archive_name)) + return true; + + if (archive_name.length() == 0) + return false; + + about.table_name= (char *) thd->memdup(archive_name.c_ptr_safe(), archive_name.length() + 1); + about.table_name_length= archive_name.length(); + DBUG_ASSERT(!about.mdl_request.ticket); + about.mdl_request.init(MDL_key::TABLE, about.db, about.table_name, + about.mdl_request.type, about.mdl_request.duration); + return false; +} diff --git a/sql/vtmd.h b/sql/vtmd.h index a2b010ece7d..a89cfd446ba 100644 --- a/sql/vtmd.h +++ b/sql/vtmd.h @@ -52,7 +52,7 @@ class VTMD_table protected: TABLE_LIST vtmd; - const TABLE_LIST &about; + TABLE_LIST &about; SString_t vtmd_name; private: -- cgit v1.2.1 From 9062385c20b62a7231b256f3f7af44ea9b1f5ad9 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Fri, 29 Sep 2017 17:51:10 +0300 Subject: SQL: invalidate current SP at archive substitution [closes #127] Related to #125 --- sql/sp_cache.cc | 4 ++++ sql/sp_cache.h | 1 + sql/sp_head.cc | 10 +--------- sql/sp_rcontext.h | 5 +---- sql/sql_parse.cc | 5 +++++ sql/sql_show.cc | 13 +------------ sql/vtmd.cc | 9 +++++++++ 7 files changed, 22 insertions(+), 25 deletions(-) diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc index b80cde335db..634a084d1fb 100644 --- a/sql/sp_cache.cc +++ b/sql/sp_cache.cc @@ -238,6 +238,10 @@ void sp_cache_flush_obsolete(sp_cache **cp, sp_head **sp) } } +void sp_cache_flush(sp_cache *cp, sp_head *sp) +{ + cp->remove(sp); +} /** Return the current global version of the cache. diff --git a/sql/sp_cache.h b/sql/sp_cache.h index b21d4c4bf25..c776df263ce 100644 --- a/sql/sp_cache.h +++ b/sql/sp_cache.h @@ -62,6 +62,7 @@ void sp_cache_insert(sp_cache **cp, sp_head *sp); sp_head *sp_cache_lookup(sp_cache **cp, sp_name *name); void sp_cache_invalidate(); void sp_cache_flush_obsolete(sp_cache **cp, sp_head **sp); +void sp_cache_flush(sp_cache *cp, sp_head *sp); ulong sp_cache_version(); void sp_cache_enforce_limit(sp_cache *cp, ulong upper_limit_for_elements); diff --git a/sql/sp_head.cc b/sql/sp_head.cc index f470ca3f283..d3310578225 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1589,10 +1589,7 @@ sp_head::execute_trigger(THD *thd, goto err_with_cleanup; } -#ifndef DBUG_OFF nctx->sp= this; -#endif - thd->spcont= nctx; err_status= execute(thd, FALSE); @@ -1713,9 +1710,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, */ thd->restore_active_arena(&call_arena, &backup_arena); -#ifndef DBUG_OFF nctx->sp= this; -#endif /* Pass arguments. */ for (arg_no= 0; arg_no < argcount; arg_no++) @@ -1919,9 +1914,7 @@ sp_head::execute_procedure(THD *thd, List *args) DBUG_RETURN(TRUE); } -#ifndef DBUG_OFF octx->sp= 0; -#endif thd->spcont= octx; /* set callers_arena to thd, for upper-level function to work */ @@ -1934,9 +1927,8 @@ sp_head::execute_procedure(THD *thd, List *args) thd->spcont= save_spcont; DBUG_RETURN(TRUE); } -#ifndef DBUG_OFF + nctx->sp= this; -#endif if (params > 0) { diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h index 98464518787..a5e5df407ca 100644 --- a/sql/sp_rcontext.h +++ b/sql/sp_rcontext.h @@ -176,11 +176,8 @@ public: /// of the client/server protocol. bool end_partial_result_set; -#ifndef DBUG_OFF - /// The stored program for which this runtime context is created. Used for - /// checking if correct runtime context is used for variable handling. + /// The stored program for which this runtime context is created. sp_head *sp; -#endif ///////////////////////////////////////////////////////////////////////// // SP-variables. diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 69938946678..2541ecb1c53 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5810,6 +5810,11 @@ end_with_restore_list: if (do_execute_sp(thd, sp)) goto error; + + if (sp->sp_cache_version() == ULONG_MAX) + { + sp_cache_flush(thd->sp_proc_cache, sp); + } } break; } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index eb5bcc300bf..5f407e728e1 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1274,21 +1274,10 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) bool versioned= table_list->vers_conditions; if (versioned) { - String archive_name; DBUG_ASSERT(table_list->vers_conditions == FOR_SYSTEM_TIME_AS_OF); VTMD_table vtmd(*table_list); - if (vtmd.find_archive_name(thd, archive_name)) + if (vtmd.setup_select(thd)) goto exit; - - if (archive_name.length() > 0) - { - archive.init_one_table(table_list->db, table_list->db_length, archive_name.ptr(), - archive_name.length(), archive_name.ptr(), TL_READ); - - archive.alias= table_list->table_name; - archive.vers_force_alias= true; - table_list= &archive; - } } if (mysqld_show_create_get_fields(thd, table_list, &field_list, &buffer)) diff --git a/sql/vtmd.cc b/sql/vtmd.cc index 1ed9014331c..2821b2226c7 100644 --- a/sql/vtmd.cc +++ b/sql/vtmd.cc @@ -9,6 +9,8 @@ #include "sql_show.h" #include "sql_parse.h" #include "sql_lex.h" +#include "sp_head.h" +#include "sp_rcontext.h" LString VERS_VTMD_TEMPLATE(C_STRING_WITH_LEN("vtmd_template")); @@ -659,5 +661,12 @@ bool VTMD_table::setup_select(THD* thd) DBUG_ASSERT(!about.mdl_request.ticket); about.mdl_request.init(MDL_key::TABLE, about.db, about.table_name, about.mdl_request.type, about.mdl_request.duration); + about.vers_force_alias= true; + // Since we modified SELECT_LEX::table_list, we need to invalidate current SP + if (thd->spcont) + { + DBUG_ASSERT(thd->spcont->sp); + thd->spcont->sp->set_sp_cache_version(ULONG_MAX); + } return false; } -- cgit v1.2.1 From 1d056f5abcfffe768474ae7860485c5e9ad3644e Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 3 Oct 2017 00:31:44 +0300 Subject: SQL: not a VTMD table warning [related to #199] --- mysql-test/suite/versioning/r/vtmd.result | 20 ++++++++++++++++---- mysql-test/suite/versioning/t/vtmd.test | 14 ++++++++++---- sql/share/errmsg-utf8.txt | 7 +++++-- sql/sql_base.cc | 29 +++++++++++++++++++++++++---- sql/table.h | 6 ++++++ sql/vtmd.cc | 21 +++++++++++++++++++-- 6 files changed, 81 insertions(+), 16 deletions(-) diff --git a/mysql-test/suite/versioning/r/vtmd.result b/mysql-test/suite/versioning/r/vtmd.result index dae8914157b..68037697a36 100644 --- a/mysql-test/suite/versioning/r/vtmd.result +++ b/mysql-test/suite/versioning/r/vtmd.result @@ -281,7 +281,7 @@ A_start B_end name C_archive_name 1 0 t3 t3_ 1 0 t3 t3_ 1 1 t3 NULL -set versioning_hide = auto; +set versioning_hide= auto; call show_tables(); Tables_in_test t2 @@ -293,7 +293,7 @@ t2 test t2_vtmd test t3 test t3_vtmd test -set versioning_hide = implicit; +set versioning_hide= implicit; call show_tables(); Tables_in_test t2 @@ -305,7 +305,7 @@ t2 test t2_vtmd test t3 test t3_vtmd test -set versioning_hide = full; +set versioning_hide= full; call show_tables(); Tables_in_test t2 @@ -317,7 +317,7 @@ t2 test t2_vtmd test t3 test t3_vtmd test -set versioning_hide = never; +set versioning_hide= never; call show_tables(); Tables_in_test t0_TIMESTAMP_SUFFIX @@ -342,6 +342,18 @@ t3 test t3_TIMESTAMP_SUFFIX test t3_TIMESTAMP_SUFFIX test t3_vtmd test +set versioning_hide= auto; +create or replace table u0_vtmd (x int) with system versioning; +show tables; +Tables_in_test +t2 +t2_vtmd +t3 +t3_vtmd +u0_vtmd +u0_vtmd_vtmd +Warnings: +Warning 4088 Table `test.u0_vtmd` is not a VTMD table drop database db0; drop database db1; drop database test; diff --git a/mysql-test/suite/versioning/t/vtmd.test b/mysql-test/suite/versioning/t/vtmd.test index 49cd85b60e1..c7d6883b0b9 100644 --- a/mysql-test/suite/versioning/t/vtmd.test +++ b/mysql-test/suite/versioning/t/vtmd.test @@ -174,19 +174,25 @@ alter table t3 change x x bigint; alter table t3 change x x bigint after sys_trx_start; call check_vtmd('t3_vtmd'); -set versioning_hide = auto; +# hide archive tables +set versioning_hide= auto; call show_tables(); -set versioning_hide = implicit; +set versioning_hide= implicit; call show_tables(); -set versioning_hide = full; +set versioning_hide= full; call show_tables(); -set versioning_hide = never; +set versioning_hide= never; --replace_regex /\d{8}_\d{6}_\d{6}/TIMESTAMP_SUFFIX/ call show_tables(); +# wrong VTMD handling +set versioning_hide= auto; +create or replace table u0_vtmd (x int) with system versioning; +show tables; + drop database db0; drop database db1; drop database test; diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index c551bcef809..e1bfa9e9172 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7581,10 +7581,13 @@ ER_VERS_NO_TRX_ID eng "TRX_ID %lu not found in VTQ" ER_WRONG_TABLESPACE_NAME 42000 - eng "Incorrect tablespace name `%-.192s`" + eng "Incorrect tablespace name `%-.192s`" ER_VERS_ALTER_SYSTEM_FIELD eng "Can not change system versioning field '%s'" ER_VERS_SYS_FIELD_NOT_HIDDEN - eng "System versioning field '%s' is not hidden" + eng "System versioning field '%s' is not hidden" + +ER_NOT_LOG_TABLE + eng "Table `%s.%s` is not a log table" diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 27bf5ab6931..fce479740f2 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -8723,10 +8723,31 @@ open_log_table(THD *thd, TABLE_LIST *one_table, Open_tables_backup *backup) if ((table= open_ltable(thd, one_table, one_table->lock_type, flags))) { - DBUG_ASSERT(table->s->table_category == TABLE_CATEGORY_LOG); - /* Make sure all columns get assigned to a default value */ - table->use_all_columns(); - DBUG_ASSERT(table->no_replicate); + if (table->s->table_category == TABLE_CATEGORY_LOG) + { + /* Make sure all columns get assigned to a default value */ + table->use_all_columns(); + DBUG_ASSERT(table->no_replicate); + } + else + { + my_error(ER_NOT_LOG_TABLE, MYF(0), table->s->db.str, table->s->table_name.str); + int error= 0; + if (table->current_lock != F_UNLCK) + { + table->current_lock= F_UNLCK; + error= table->file->ha_external_lock(thd, F_UNLCK); + } + if (error) + table->file->print_error(error, MYF(0)); + else + { + tc_release_table(table); + thd->reset_open_tables_state(thd); + thd->restore_backup_open_tables_state(backup); + table= NULL; + } + } } else thd->restore_backup_open_tables_state(backup); diff --git a/sql/table.h b/sql/table.h index d857ba4752b..2e618e26361 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1530,6 +1530,12 @@ public: return s->versioned && file->native_versioned(); } + bool vers_vtmd() const + { + DBUG_ASSERT(s); + return s->versioned && s->vtmd; + } + Field *vers_start_field() const { DBUG_ASSERT(s && s->versioned); diff --git a/sql/vtmd.cc b/sql/vtmd.cc index 2821b2226c7..0f008fc1e91 100644 --- a/sql/vtmd.cc +++ b/sql/vtmd.cc @@ -593,6 +593,7 @@ VTMD_table::get_archive_tables(THD *thd, const char *db, size_t db_length, if (get_vtmd_tables(thd, db, db_length, vtmd_tables)) return true; + Local_da local_da(thd, ER_VERS_VTMD_ERROR); for (uint i= 0; i < vtmd_tables.elements(); i++) { LEX_STRING table_name= *vtmd_tables.at(i); @@ -603,8 +604,24 @@ VTMD_table::get_archive_tables(THD *thd, const char *db, size_t db_length, table_name.str, TL_READ); TABLE *table= open_log_table(thd, &table_list, &open_tables_backup); - if (!table) - return true; + if (!table || !table->vers_vtmd()) + { + if (table) + close_log_table(thd, &open_tables_backup); + else + { + if (local_da.is_error() && local_da.sql_errno() == ER_NOT_LOG_TABLE) + local_da.reset_diagnostics_area(); + else + return true; + } + push_warning_printf( + thd, Sql_condition::WARN_LEVEL_WARN, + ER_VERS_VTMD_ERROR, + "Table `%s.%s` is not a VTMD table", + db, table_name.str); + continue; + } READ_RECORD read_record; int error= 0; -- cgit v1.2.1 From d7a484b04feb184cf697122f63f821f338c35769 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Wed, 4 Oct 2017 13:36:31 +0300 Subject: SQL: segfault after make_select() in VTMD --- mysql-test/suite/versioning/r/vtmd.result | 4 ++++ mysql-test/suite/versioning/t/vtmd.test | 4 ++++ sql/vtmd.cc | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/versioning/r/vtmd.result b/mysql-test/suite/versioning/r/vtmd.result index 68037697a36..47f0dfd3491 100644 --- a/mysql-test/suite/versioning/r/vtmd.result +++ b/mysql-test/suite/versioning/r/vtmd.result @@ -354,6 +354,10 @@ u0_vtmd u0_vtmd_vtmd Warnings: Warning 4088 Table `test.u0_vtmd` is not a VTMD table +set versioning_alter_history= survive; +create or replace table t (x int) with system versioning; +select * from t for system_time all; +x sys_trx_start sys_trx_end drop database db0; drop database db1; drop database test; diff --git a/mysql-test/suite/versioning/t/vtmd.test b/mysql-test/suite/versioning/t/vtmd.test index c7d6883b0b9..c5483c182cc 100644 --- a/mysql-test/suite/versioning/t/vtmd.test +++ b/mysql-test/suite/versioning/t/vtmd.test @@ -193,6 +193,10 @@ set versioning_hide= auto; create or replace table u0_vtmd (x int) with system versioning; show tables; +set versioning_alter_history= survive; +create or replace table t (x int) with system versioning; +select * from t for system_time all; + drop database db0; drop database db1; drop database test; diff --git a/sql/vtmd.cc b/sql/vtmd.cc index 0f008fc1e91..a1d7375dfef 100644 --- a/sql/vtmd.cc +++ b/sql/vtmd.cc @@ -547,7 +547,7 @@ VTMD_table::find_archive_name(THD *thd, String &out) while (!(error= info.read_record(&info)) && !thd->killed && !thd->is_error()) { - if (select->skip_record(thd) > 0) + if (!select || select->skip_record(thd) > 0) { vtmd.table->field[FLD_ARCHIVE_NAME]->val_str(&out); break; -- cgit v1.2.1 From 8e193661d29494e14ff59e484020c51369f65aa4 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 9 Oct 2017 18:42:59 +0300 Subject: IB: vtq_notify_on_commit initialization fix --- storage/innobase/trx/trx0trx.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index a7d0071c67e..1dc844cd1c9 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -145,6 +145,8 @@ trx_init( trx->check_unique_secondary = true; + trx->vtq_notify_on_commit = false; + trx->lock.n_rec_locks = 0; trx->dict_operation = TRX_DICT_OP_NONE; @@ -1363,7 +1365,6 @@ trx_start_low( trx->start_time_micro += trx->start_time * 1000000; } - trx->vtq_notify_on_commit = false; ut_a(trx->error_state == DB_SUCCESS); MONITOR_INC(MONITOR_TRX_ACTIVE); -- cgit v1.2.1 From 17bd486f361a150cb6e4c0320c1fa8e344beb76b Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 17 Oct 2017 17:20:46 +0300 Subject: SQL: thd_start_utime() fix [fixes #284] --- mysql-test/suite/versioning/common.inc | 3 ++- mysql-test/suite/versioning/r/alter.result | 3 ++- mysql-test/suite/versioning/r/auto_increment.result | 3 ++- mysql-test/suite/versioning/r/commit_id.result | 3 ++- mysql-test/suite/versioning/r/create.result | 3 ++- mysql-test/suite/versioning/r/ddl.result | 3 ++- mysql-test/suite/versioning/r/delete.result | 3 ++- mysql-test/suite/versioning/r/insert.result | 3 ++- mysql-test/suite/versioning/r/partition.result | 3 ++- mysql-test/suite/versioning/r/select.result | 3 ++- mysql-test/suite/versioning/r/select_sp.result | 3 ++- mysql-test/suite/versioning/r/update.result | 3 ++- mysql-test/suite/versioning/r/view.result | 3 ++- sql/sql_class.cc | 2 +- 14 files changed, 27 insertions(+), 14 deletions(-) diff --git a/mysql-test/suite/versioning/common.inc b/mysql-test/suite/versioning/common.inc index 3c4d11b84ab..ca3ccd41752 100644 --- a/mysql-test/suite/versioning/common.inc +++ b/mysql-test/suite/versioning/common.inc @@ -1,5 +1,6 @@ set @@session.time_zone='+00:00'; select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; +set @test_start=now(6); delimiter ~~; create procedure if not exists verify_vtq() @@ -9,7 +10,7 @@ begin @i:= @i + 1 as No, transaction_id > 0 as A, commit_id > transaction_id as B, - begin_timestamp > '1-1-1 0:0:0' as C, + begin_timestamp > @test_start as C, commit_timestamp >= begin_timestamp as D from information_schema.innodb_vtq where transaction_id > @start_trx_id; diff --git a/mysql-test/suite/versioning/r/alter.result b/mysql-test/suite/versioning/r/alter.result index 9e812769ee3..d6cbaf96b73 100644 --- a/mysql-test/suite/versioning/r/alter.result +++ b/mysql-test/suite/versioning/r/alter.result @@ -249,6 +249,7 @@ t CREATE TABLE `t` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING set @@session.time_zone='+00:00'; select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; +set @test_start=now(6); create procedure if not exists verify_vtq() begin set @i= 0; @@ -256,7 +257,7 @@ select @i:= @i + 1 as No, transaction_id > 0 as A, commit_id > transaction_id as B, -begin_timestamp > '1-1-1 0:0:0' as C, +begin_timestamp > @test_start as C, commit_timestamp >= begin_timestamp as D from information_schema.innodb_vtq where transaction_id > @start_trx_id; diff --git a/mysql-test/suite/versioning/r/auto_increment.result b/mysql-test/suite/versioning/r/auto_increment.result index 7eb027f52d6..533a5cc45af 100644 --- a/mysql-test/suite/versioning/r/auto_increment.result +++ b/mysql-test/suite/versioning/r/auto_increment.result @@ -1,5 +1,6 @@ set @@session.time_zone='+00:00'; select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; +set @test_start=now(6); create procedure if not exists verify_vtq() begin set @i= 0; @@ -7,7 +8,7 @@ select @i:= @i + 1 as No, transaction_id > 0 as A, commit_id > transaction_id as B, -begin_timestamp > '1-1-1 0:0:0' as C, +begin_timestamp > @test_start as C, commit_timestamp >= begin_timestamp as D from information_schema.innodb_vtq where transaction_id > @start_trx_id; diff --git a/mysql-test/suite/versioning/r/commit_id.result b/mysql-test/suite/versioning/r/commit_id.result index a53ba70a9b3..56ca1f4bec3 100644 --- a/mysql-test/suite/versioning/r/commit_id.result +++ b/mysql-test/suite/versioning/r/commit_id.result @@ -1,5 +1,6 @@ set @@session.time_zone='+00:00'; select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; +set @test_start=now(6); create procedure if not exists verify_vtq() begin set @i= 0; @@ -7,7 +8,7 @@ select @i:= @i + 1 as No, transaction_id > 0 as A, commit_id > transaction_id as B, -begin_timestamp > '1-1-1 0:0:0' as C, +begin_timestamp > @test_start as C, commit_timestamp >= begin_timestamp as D from information_schema.innodb_vtq where transaction_id > @start_trx_id; diff --git a/mysql-test/suite/versioning/r/create.result b/mysql-test/suite/versioning/r/create.result index 851d287f31e..a190ac30fd9 100644 --- a/mysql-test/suite/versioning/r/create.result +++ b/mysql-test/suite/versioning/r/create.result @@ -1,5 +1,6 @@ set @@session.time_zone='+00:00'; select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; +set @test_start=now(6); create procedure if not exists verify_vtq() begin set @i= 0; @@ -7,7 +8,7 @@ select @i:= @i + 1 as No, transaction_id > 0 as A, commit_id > transaction_id as B, -begin_timestamp > '1-1-1 0:0:0' as C, +begin_timestamp > @test_start as C, commit_timestamp >= begin_timestamp as D from information_schema.innodb_vtq where transaction_id > @start_trx_id; diff --git a/mysql-test/suite/versioning/r/ddl.result b/mysql-test/suite/versioning/r/ddl.result index 1bfca2da8f6..759cb5f449a 100644 --- a/mysql-test/suite/versioning/r/ddl.result +++ b/mysql-test/suite/versioning/r/ddl.result @@ -1,5 +1,6 @@ set @@session.time_zone='+00:00'; select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; +set @test_start=now(6); create procedure if not exists verify_vtq() begin set @i= 0; @@ -7,7 +8,7 @@ select @i:= @i + 1 as No, transaction_id > 0 as A, commit_id > transaction_id as B, -begin_timestamp > '1-1-1 0:0:0' as C, +begin_timestamp > @test_start as C, commit_timestamp >= begin_timestamp as D from information_schema.innodb_vtq where transaction_id > @start_trx_id; diff --git a/mysql-test/suite/versioning/r/delete.result b/mysql-test/suite/versioning/r/delete.result index 7b7e836f84d..910d99c8643 100644 --- a/mysql-test/suite/versioning/r/delete.result +++ b/mysql-test/suite/versioning/r/delete.result @@ -1,5 +1,6 @@ set @@session.time_zone='+00:00'; select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; +set @test_start=now(6); create procedure if not exists verify_vtq() begin set @i= 0; @@ -7,7 +8,7 @@ select @i:= @i + 1 as No, transaction_id > 0 as A, commit_id > transaction_id as B, -begin_timestamp > '1-1-1 0:0:0' as C, +begin_timestamp > @test_start as C, commit_timestamp >= begin_timestamp as D from information_schema.innodb_vtq where transaction_id > @start_trx_id; diff --git a/mysql-test/suite/versioning/r/insert.result b/mysql-test/suite/versioning/r/insert.result index d7b7bd972dc..4bfa4fe0720 100644 --- a/mysql-test/suite/versioning/r/insert.result +++ b/mysql-test/suite/versioning/r/insert.result @@ -1,5 +1,6 @@ set @@session.time_zone='+00:00'; select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; +set @test_start=now(6); create procedure if not exists verify_vtq() begin set @i= 0; @@ -7,7 +8,7 @@ select @i:= @i + 1 as No, transaction_id > 0 as A, commit_id > transaction_id as B, -begin_timestamp > '1-1-1 0:0:0' as C, +begin_timestamp > @test_start as C, commit_timestamp >= begin_timestamp as D from information_schema.innodb_vtq where transaction_id > @start_trx_id; diff --git a/mysql-test/suite/versioning/r/partition.result b/mysql-test/suite/versioning/r/partition.result index 2107c065a56..2ba2b870ae9 100644 --- a/mysql-test/suite/versioning/r/partition.result +++ b/mysql-test/suite/versioning/r/partition.result @@ -1,5 +1,6 @@ set @@session.time_zone='+00:00'; select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; +set @test_start=now(6); create procedure if not exists verify_vtq() begin set @i= 0; @@ -7,7 +8,7 @@ select @i:= @i + 1 as No, transaction_id > 0 as A, commit_id > transaction_id as B, -begin_timestamp > '1-1-1 0:0:0' as C, +begin_timestamp > @test_start as C, commit_timestamp >= begin_timestamp as D from information_schema.innodb_vtq where transaction_id > @start_trx_id; diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index f4eb8c35d0e..6c179d2e166 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -1,5 +1,6 @@ set @@session.time_zone='+00:00'; select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; +set @test_start=now(6); create procedure if not exists verify_vtq() begin set @i= 0; @@ -7,7 +8,7 @@ select @i:= @i + 1 as No, transaction_id > 0 as A, commit_id > transaction_id as B, -begin_timestamp > '1-1-1 0:0:0' as C, +begin_timestamp > @test_start as C, commit_timestamp >= begin_timestamp as D from information_schema.innodb_vtq where transaction_id > @start_trx_id; diff --git a/mysql-test/suite/versioning/r/select_sp.result b/mysql-test/suite/versioning/r/select_sp.result index a4d0bbfde0d..44b7d4e25b4 100644 --- a/mysql-test/suite/versioning/r/select_sp.result +++ b/mysql-test/suite/versioning/r/select_sp.result @@ -1,5 +1,6 @@ set @@session.time_zone='+00:00'; select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; +set @test_start=now(6); create procedure if not exists verify_vtq() begin set @i= 0; @@ -7,7 +8,7 @@ select @i:= @i + 1 as No, transaction_id > 0 as A, commit_id > transaction_id as B, -begin_timestamp > '1-1-1 0:0:0' as C, +begin_timestamp > @test_start as C, commit_timestamp >= begin_timestamp as D from information_schema.innodb_vtq where transaction_id > @start_trx_id; diff --git a/mysql-test/suite/versioning/r/update.result b/mysql-test/suite/versioning/r/update.result index a9f345963e5..d54add35def 100644 --- a/mysql-test/suite/versioning/r/update.result +++ b/mysql-test/suite/versioning/r/update.result @@ -1,5 +1,6 @@ set @@session.time_zone='+00:00'; select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; +set @test_start=now(6); create procedure if not exists verify_vtq() begin set @i= 0; @@ -7,7 +8,7 @@ select @i:= @i + 1 as No, transaction_id > 0 as A, commit_id > transaction_id as B, -begin_timestamp > '1-1-1 0:0:0' as C, +begin_timestamp > @test_start as C, commit_timestamp >= begin_timestamp as D from information_schema.innodb_vtq where transaction_id > @start_trx_id; diff --git a/mysql-test/suite/versioning/r/view.result b/mysql-test/suite/versioning/r/view.result index 45bc113cc27..ff009be57f5 100644 --- a/mysql-test/suite/versioning/r/view.result +++ b/mysql-test/suite/versioning/r/view.result @@ -1,5 +1,6 @@ set @@session.time_zone='+00:00'; select ifnull(max(transaction_id), 0) into @start_trx_id from information_schema.innodb_vtq; +set @test_start=now(6); create procedure if not exists verify_vtq() begin set @i= 0; @@ -7,7 +8,7 @@ select @i:= @i + 1 as No, transaction_id > 0 as A, commit_id > transaction_id as B, -begin_timestamp > '1-1-1 0:0:0' as C, +begin_timestamp > @test_start as C, commit_timestamp >= begin_timestamp as D from information_schema.innodb_vtq where transaction_id > @start_trx_id; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 4226da573cb..4a780812ec4 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -4644,7 +4644,7 @@ extern "C" time_t thd_start_time(const MYSQL_THD thd) of the current query. */ extern "C" unsigned long long thd_start_utime(const MYSQL_THD thd) { - return thd->start_utime; + return thd->start_time * 1000000 + thd->start_time_sec_part; } -- cgit v1.2.1 From ce66d5b2a53d76d286e8443807c4ebd7743cc354 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 17 Oct 2017 17:23:59 +0300 Subject: SQL: assertion in partition_info::vers_trx_id_to_ts() Related to #283 --- sql/partition_info.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/partition_info.cc b/sql/partition_info.cc index af97791ab80..f2e3c12aa4a 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -3383,6 +3383,7 @@ static bool has_same_column_order(List *create_list, bool partition_info::vers_trx_id_to_ts(THD* thd, Field* in_trx_id, Field_timestamp& out_ts) { + DBUG_ASSERT(table); handlerton *hton= plugin_hton(table->s->db_plugin); DBUG_ASSERT(hton); ulonglong trx_id= in_trx_id->val_int(); -- cgit v1.2.1