summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/mysqldump.c17
-rw-r--r--debian/mariadb-server-10.3.install1
-rwxr-xr-xdebian/patches/33_scripts__mysql_create_system_tables__no_test.dpatch15
-rwxr-xr-xdebian/patches/38_scripts__mysqld_safe.sh__signals.dpatch10
-rwxr-xr-xdebian/patches/41_scripts__mysql_install_db.sh__no_test.dpatch6
-rwxr-xr-xdebian/patches/50_mysql-test__db_test.dpatch10
-rw-r--r--include/m_string.h1
-rw-r--r--include/my_base.h4
-rw-r--r--include/mysql.h1
-rw-r--r--include/mysql/psi/mysql_thread.h29
-rw-r--r--include/mysql_com.h11
-rw-r--r--libmysqld/CMakeLists.txt2
-rw-r--r--libmysqld/lib_sql.cc2
-rw-r--r--mysql-test/collections/buildbot_suites.bat1
-rwxr-xr-xmysql-test/mysql-test-run.pl31
-rw-r--r--mysql-test/r/1st.result1
-rw-r--r--mysql-test/r/alter_user.result56
-rw-r--r--mysql-test/r/connect.result3
-rw-r--r--mysql-test/r/create_user.result48
-rw-r--r--mysql-test/r/ctype_upgrade.result6
-rw-r--r--mysql-test/r/derived_view.result2
-rw-r--r--mysql-test/r/events_grant.result2
-rw-r--r--mysql-test/r/fulltext.result2
-rw-r--r--mysql-test/r/grant.result18
-rw-r--r--mysql-test/r/information_schema.result6
-rw-r--r--mysql-test/r/information_schema_all_engines.result2
-rw-r--r--mysql-test/r/join.result1
-rw-r--r--mysql-test/r/log_tables_upgrade.result1
-rw-r--r--mysql-test/r/lowercase_table_grant.result8
-rw-r--r--mysql-test/r/mysql_upgrade-6984.result6
-rw-r--r--mysql-test/r/mysql_upgrade.result12
-rw-r--r--mysql-test/r/mysql_upgrade_no_innodb.result6
-rw-r--r--mysql-test/r/mysql_upgrade_noengine.result3
-rw-r--r--mysql-test/r/mysql_upgrade_ssl.result1
-rw-r--r--mysql-test/r/mysql_upgrade_view.result18
-rw-r--r--mysql-test/r/mysqlbinlog_row_compressed.result16
-rw-r--r--mysql-test/r/mysqlbinlog_row_minimal.result16
-rw-r--r--mysql-test/r/mysqlcheck.result9
-rw-r--r--mysql-test/r/mysqld--help.result14
-rw-r--r--mysql-test/r/no_password_column-mdev-11170.result1
-rw-r--r--mysql-test/r/partition_alter.result7
-rw-r--r--mysql-test/r/ps.result9
-rw-r--r--mysql-test/r/sql_mode.result2
-rw-r--r--mysql-test/r/system_mysql_db.result5
-rw-r--r--mysql-test/r/system_mysql_db_fix40123.result5
-rw-r--r--mysql-test/r/system_mysql_db_fix50030.result5
-rw-r--r--mysql-test/r/system_mysql_db_fix50117.result5
-rw-r--r--mysql-test/r/trigger.result2
-rw-r--r--mysql-test/suite/binlog/r/binlog_base64_flag.result2
-rw-r--r--mysql-test/suite/encryption/r/encrypt_and_grep.result3
-rw-r--r--mysql-test/suite/encryption/r/innodb-spatial-index.result1
-rw-r--r--mysql-test/suite/encryption/r/innodb_encryption.result5
-rw-r--r--mysql-test/suite/encryption/r/innodb_lotoftables.result40
-rw-r--r--mysql-test/suite/funcs_1/r/innodb_trig_03.result22
-rw-r--r--mysql-test/suite/funcs_1/r/innodb_trig_03e.result6
-rw-r--r--mysql-test/suite/funcs_1/r/innodb_views.result8
-rw-r--r--mysql-test/suite/funcs_1/r/is_column_privileges.result1
-rw-r--r--mysql-test/suite/funcs_1/r/is_columns.result1
-rw-r--r--mysql-test/suite/funcs_1/r/is_columns_mysql.result46
-rw-r--r--mysql-test/suite/funcs_1/r/is_columns_mysql_embedded.result41
-rw-r--r--mysql-test/suite/funcs_1/r/is_key_column_usage.result2
-rw-r--r--mysql-test/suite/funcs_1/r/is_key_column_usage_embedded.result2
-rw-r--r--mysql-test/suite/funcs_1/r/is_schema_privileges.result2
-rw-r--r--mysql-test/suite/funcs_1/r/is_schema_privileges_is_mysql_test.result1
-rw-r--r--mysql-test/suite/funcs_1/r/is_statistics.result1
-rw-r--r--mysql-test/suite/funcs_1/r/is_statistics_mysql.result5
-rw-r--r--mysql-test/suite/funcs_1/r/is_statistics_mysql_embedded.result10
-rw-r--r--mysql-test/suite/funcs_1/r/is_table_constraints.result2
-rw-r--r--mysql-test/suite/funcs_1/r/is_table_constraints_mysql.result2
-rw-r--r--mysql-test/suite/funcs_1/r/is_table_constraints_mysql_embedded.result4
-rw-r--r--mysql-test/suite/funcs_1/r/is_table_privileges.result4
-rw-r--r--mysql-test/suite/funcs_1/r/is_tables_mysql.result23
-rw-r--r--mysql-test/suite/funcs_1/r/is_tables_mysql_embedded.result46
-rw-r--r--mysql-test/suite/funcs_1/r/is_triggers.result2
-rw-r--r--mysql-test/suite/funcs_1/r/is_user_privileges.result33
-rw-r--r--mysql-test/suite/funcs_1/r/memory_trig_03.result22
-rw-r--r--mysql-test/suite/funcs_1/r/memory_trig_03e.result6
-rw-r--r--mysql-test/suite/funcs_1/r/memory_views.result8
-rw-r--r--mysql-test/suite/funcs_1/r/myisam_trig_03.result22
-rw-r--r--mysql-test/suite/funcs_1/r/myisam_trig_03e.result6
-rw-r--r--mysql-test/suite/funcs_1/r/myisam_views-big.result8
-rw-r--r--mysql-test/suite/funcs_1/r/storedproc.result22
-rw-r--r--mysql-test/suite/innodb/r/innodb-index-online-fk.result5
-rw-r--r--mysql-test/suite/innodb/r/instant_alter_debug.result2
-rw-r--r--mysql-test/suite/innodb/r/row_format_redundant.result2
-rw-r--r--mysql-test/suite/innodb/t/ibuf_not_empty.test2
-rw-r--r--mysql-test/suite/innodb/t/innodb_force_recovery.test1
-rw-r--r--mysql-test/suite/innodb/t/log_corruption.test1
-rw-r--r--mysql-test/suite/innodb/t/row_format_redundant.test6
-rw-r--r--mysql-test/suite/innodb_fts/r/fulltext.result2
-rw-r--r--mysql-test/suite/innodb_zip/r/16k.result4
-rw-r--r--mysql-test/suite/mariabackup/system_versioning.result53
-rw-r--r--mysql-test/suite/mariabackup/system_versioning.test52
-rw-r--r--mysql-test/suite/roles/create_and_drop_role_invalid_user_table.result4
-rw-r--r--mysql-test/suite/roles/set_role-recursive.result8
-rw-r--r--mysql-test/suite/roles/set_role-simple.result4
-rw-r--r--mysql-test/suite/sys_vars/r/sysvars_server_embedded.result56
-rw-r--r--mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result56
-rw-r--r--mysql-test/suite/versioning/common.inc127
-rw-r--r--mysql-test/suite/versioning/common.opt2
-rw-r--r--mysql-test/suite/versioning/common_finish.inc11
-rw-r--r--mysql-test/suite/versioning/disabled.def (renamed from mysql-test/suite/handler/disabled.def)4
-rw-r--r--mysql-test/suite/versioning/engines.combinations8
-rw-r--r--mysql-test/suite/versioning/engines.inc1
-rw-r--r--mysql-test/suite/versioning/key_type.combinations2
-rw-r--r--mysql-test/suite/versioning/key_type.inc23
-rw-r--r--mysql-test/suite/versioning/r/alter.result469
-rw-r--r--mysql-test/suite/versioning/r/auto_increment.result119
-rw-r--r--mysql-test/suite/versioning/r/commit_id.result98
-rw-r--r--mysql-test/suite/versioning/r/create.result473
-rw-r--r--mysql-test/suite/versioning/r/cte.result118
-rw-r--r--mysql-test/suite/versioning/r/ddl.result211
-rw-r--r--mysql-test/suite/versioning/r/delete.result320
-rw-r--r--mysql-test/suite/versioning/r/derived.result295
-rw-r--r--mysql-test/suite/versioning/r/foreign.result232
-rw-r--r--mysql-test/suite/versioning/r/insert.result361
-rw-r--r--mysql-test/suite/versioning/r/online.result38
-rw-r--r--mysql-test/suite/versioning/r/optimized.result97
-rw-r--r--mysql-test/suite/versioning/r/partition.result412
-rw-r--r--mysql-test/suite/versioning/r/replace.result10
-rw-r--r--mysql-test/suite/versioning/r/rpl.result118
-rw-r--r--mysql-test/suite/versioning/r/select.result446
-rw-r--r--mysql-test/suite/versioning/r/select_sp.result369
-rw-r--r--mysql-test/suite/versioning/r/simple.result73
-rw-r--r--mysql-test/suite/versioning/r/sysvars.result129
-rw-r--r--mysql-test/suite/versioning/r/truncate.result71
-rw-r--r--mysql-test/suite/versioning/r/truncate_privilege.result33
-rw-r--r--mysql-test/suite/versioning/r/trx_id.result96
-rw-r--r--mysql-test/suite/versioning/r/update.result627
-rw-r--r--mysql-test/suite/versioning/r/view.result120
-rw-r--r--mysql-test/suite/versioning/r/vtmd.result365
-rw-r--r--mysql-test/suite/versioning/r/vtmd_show.result229
-rw-r--r--mysql-test/suite/versioning/t/alter.test408
-rw-r--r--mysql-test/suite/versioning/t/auto_increment.test68
-rw-r--r--mysql-test/suite/versioning/t/commit_id.test94
-rw-r--r--mysql-test/suite/versioning/t/create.test367
-rw-r--r--mysql-test/suite/versioning/t/cte.test101
-rw-r--r--mysql-test/suite/versioning/t/ddl.test105
-rw-r--r--mysql-test/suite/versioning/t/delete.test129
-rw-r--r--mysql-test/suite/versioning/t/derived.test236
-rw-r--r--mysql-test/suite/versioning/t/engines.combinations8
-rw-r--r--mysql-test/suite/versioning/t/foreign.combinations5
-rw-r--r--mysql-test/suite/versioning/t/foreign.test282
-rw-r--r--mysql-test/suite/versioning/t/insert.test254
-rw-r--r--mysql-test/suite/versioning/t/online.test45
-rw-r--r--mysql-test/suite/versioning/t/optimized.test33
-rw-r--r--mysql-test/suite/versioning/t/partition.combinations5
-rw-r--r--mysql-test/suite/versioning/t/partition.opt1
-rw-r--r--mysql-test/suite/versioning/t/partition.test356
-rw-r--r--mysql-test/suite/versioning/t/replace.test13
-rw-r--r--mysql-test/suite/versioning/t/rpl.test108
-rw-r--r--mysql-test/suite/versioning/t/select.test291
-rw-r--r--mysql-test/suite/versioning/t/select_sp.test232
-rw-r--r--mysql-test/suite/versioning/t/simple.test73
-rw-r--r--mysql-test/suite/versioning/t/sysvars.test87
-rw-r--r--mysql-test/suite/versioning/t/truncate.opt1
-rw-r--r--mysql-test/suite/versioning/t/truncate.test72
-rw-r--r--mysql-test/suite/versioning/t/truncate_privilege.test41
-rw-r--r--mysql-test/suite/versioning/t/trx_id.test97
-rw-r--r--mysql-test/suite/versioning/t/update.test289
-rw-r--r--mysql-test/suite/versioning/t/view.test102
-rw-r--r--mysql-test/suite/versioning/t/vtmd.opt1
-rw-r--r--mysql-test/suite/versioning/t/vtmd.test204
-rw-r--r--mysql-test/suite/versioning/t/vtmd_show.opt1
-rw-r--r--mysql-test/suite/versioning/t/vtmd_show.test90
-rw-r--r--mysql-test/t/mysqldump.test2
-rw-r--r--mysql-test/t/partition_alter.test11
-rw-r--r--mysql-test/t/system_mysql_db_fix40123.test2
-rw-r--r--mysql-test/t/system_mysql_db_fix50030.test2
-rw-r--r--mysql-test/t/system_mysql_db_fix50117.test2
-rw-r--r--mysys/my_thr_init.c4
-rw-r--r--plugin/versioning/CMakeLists.txt17
-rw-r--r--plugin/versioning/versioning.cc204
-rw-r--r--scripts/mysql_system_tables.sql26
-rw-r--r--scripts/mysql_system_tables_data.sql14
-rw-r--r--scripts/mysql_system_tables_fix.sql8
-rw-r--r--sql/CMakeLists.txt2
-rw-r--r--sql/event_queue.cc2
-rw-r--r--sql/field.cc125
-rw-r--r--sql/field.h133
-rw-r--r--sql/gen_lex_token.cc2
-rw-r--r--sql/ha_partition.cc36
-rw-r--r--sql/ha_partition.h105
-rw-r--r--sql/ha_sequence.cc3
-rw-r--r--sql/handler.cc824
-rw-r--r--sql/handler.h147
-rw-r--r--sql/item.cc47
-rw-r--r--sql/item.h110
-rw-r--r--sql/item_cmpfunc.cc6
-rw-r--r--sql/item_create.cc51
-rw-r--r--sql/item_create.h41
-rw-r--r--sql/item_func.h27
-rw-r--r--sql/item_timefunc.cc21
-rw-r--r--sql/item_timefunc.h14
-rw-r--r--sql/item_vers.cc182
-rw-r--r--sql/item_vers.h114
-rw-r--r--sql/lex.h8
-rw-r--r--sql/log_event.cc60
-rw-r--r--sql/log_event.h5
-rw-r--r--sql/mysqld.cc78
-rw-r--r--sql/mysqld.h49
-rw-r--r--sql/opt_range.cc11
-rw-r--r--sql/opt_range.h32
-rw-r--r--sql/partition_element.h124
-rw-r--r--sql/partition_info.cc655
-rw-r--r--sql/partition_info.h206
-rw-r--r--sql/semisync_master_ack_receiver.cc4
-rw-r--r--sql/share/errmsg-utf8.txt142
-rw-r--r--sql/sp_cache.cc6
-rw-r--r--sql/sp_cache.h1
-rw-r--r--sql/sp_head.cc8
-rw-r--r--sql/sp_head.h4
-rw-r--r--sql/sql_acl.cc27
-rw-r--r--sql/sql_acl.h27
-rw-r--r--sql/sql_alter.h26
-rw-r--r--sql/sql_base.cc112
-rw-r--r--sql/sql_class.cc26
-rw-r--r--sql/sql_class.h193
-rw-r--r--sql/sql_delete.cc97
-rw-r--r--sql/sql_error.h2
-rw-r--r--sql/sql_insert.cc143
-rw-r--r--sql/sql_insert.h1
-rw-r--r--sql/sql_lex.cc72
-rw-r--r--sql/sql_lex.h33
-rw-r--r--sql/sql_parse.cc43
-rw-r--r--sql/sql_partition.cc317
-rw-r--r--sql/sql_partition.h35
-rw-r--r--sql/sql_rename.cc22
-rw-r--r--sql/sql_select.cc447
-rw-r--r--sql/sql_select.h5
-rw-r--r--sql/sql_show.cc183
-rw-r--r--sql/sql_show.h3
-rw-r--r--sql/sql_table.cc516
-rw-r--r--sql/sql_time.cc1
-rw-r--r--sql/sql_time.h1
-rw-r--r--sql/sql_trigger.cc2
-rw-r--r--sql/sql_trigger.h7
-rw-r--r--sql/sql_truncate.cc10
-rw-r--r--sql/sql_tvc.cc2
-rw-r--r--sql/sql_type.cc26
-rw-r--r--sql/sql_type.h21
-rw-r--r--sql/sql_union.cc2
-rw-r--r--sql/sql_update.cc169
-rw-r--r--sql/sql_view.cc30
-rw-r--r--sql/sql_yacc.yy427
-rw-r--r--sql/sql_yacc_ora.yy13
-rw-r--r--sql/sys_vars.cc55
-rw-r--r--sql/sys_vars.ic98
-rw-r--r--sql/table.cc598
-rw-r--r--sql/table.h342
-rw-r--r--sql/threadpool_common.cc16
-rw-r--r--sql/tztime.h1
-rw-r--r--sql/unireg.cc120
-rw-r--r--sql/unireg.h7
-rw-r--r--sql/vers_string.h133
-rw-r--r--sql/vers_utils.h81
-rw-r--r--sql/vtmd.cc695
-rw-r--r--sql/vtmd.h187
-rw-r--r--storage/innobase/dict/dict0mem.cc80
-rw-r--r--storage/innobase/handler/ha_innodb.cc105
-rw-r--r--storage/innobase/handler/handler0alter.cc38
-rw-r--r--storage/innobase/include/data0data.h16
-rw-r--r--storage/innobase/include/data0type.h21
-rw-r--r--storage/innobase/include/dict0mem.h37
-rw-r--r--storage/innobase/include/dict0types.h7
-rw-r--r--storage/innobase/include/row0ins.h3
-rw-r--r--storage/innobase/include/row0merge.h4
-rw-r--r--storage/innobase/include/row0mysql.h33
-rw-r--r--storage/innobase/include/row0upd.h21
-rw-r--r--storage/innobase/include/srv0srv.h8
-rw-r--r--storage/innobase/include/trx0trx.h66
-rw-r--r--storage/innobase/include/trx0types.h3
-rw-r--r--storage/innobase/pars/pars0pars.cc6
-rw-r--r--storage/innobase/row/row0ins.cc35
-rw-r--r--storage/innobase/row/row0merge.cc66
-rw-r--r--storage/innobase/row/row0mysql.cc114
-rw-r--r--storage/innobase/row/row0sel.cc9
-rw-r--r--storage/innobase/row/row0upd.cc13
-rw-r--r--storage/innobase/trx/trx0rec.cc25
-rw-r--r--storage/innobase/trx/trx0roll.cc3
-rw-r--r--storage/innobase/trx/trx0trx.cc11
-rw-r--r--storage/maria/ma_checkpoint.c4
-rw-r--r--storage/rocksdb/mysql-test/rocksdb/r/misc.result1
-rw-r--r--storage/tokudb/mysql-test/tokudb/r/tokudb_support_xa.result2
-rw-r--r--storage/tokudb/mysql-test/tokudb/t/tokudb_support_xa.test2
285 files changed, 20250 insertions, 946 deletions
diff --git a/client/mysqldump.c b/client/mysqldump.c
index 6d734cf9472..c2264ff9e6c 100644
--- a/client/mysqldump.c
+++ b/client/mysqldump.c
@@ -996,7 +996,9 @@ static int get_options(int *argc, char ***argv)
my_hash_insert(&ignore_table,
(uchar*) my_strdup("mysql.general_log", MYF(MY_WME))) ||
my_hash_insert(&ignore_table,
- (uchar*) my_strdup("mysql.slow_log", MYF(MY_WME))))
+ (uchar*) my_strdup("mysql.slow_log", MYF(MY_WME))) ||
+ my_hash_insert(&ignore_table,
+ (uchar*) my_strdup("mysql.transaction_registry", MYF(MY_WME))))
return(EX_EOM);
if ((ho_error= handle_options(argc, argv, my_long_options, get_one_option)))
@@ -2674,7 +2676,8 @@ static inline my_bool general_log_or_slow_log_tables(const char *db,
{
return (!my_strcasecmp(charset_info, db, "mysql")) &&
(!my_strcasecmp(charset_info, table, "general_log") ||
- !my_strcasecmp(charset_info, table, "slow_log"));
+ !my_strcasecmp(charset_info, table, "slow_log") ||
+ !my_strcasecmp(charset_info, table, "transaction_registry"));
}
/*
@@ -4616,6 +4619,7 @@ static int dump_all_tables_in_db(char *database)
char hash_key[2*NAME_LEN+2]; /* "db.tablename" */
char *afterdot;
my_bool general_log_table_exists= 0, slow_log_table_exists=0;
+ my_bool transaction_registry_table_exists= 0;
int using_mysql_db= !my_strcasecmp(charset_info, database, "mysql");
DBUG_ENTER("dump_all_tables_in_db");
@@ -4718,6 +4722,8 @@ static int dump_all_tables_in_db(char *database)
general_log_table_exists= 1;
else if (!my_strcasecmp(charset_info, table, "slow_log"))
slow_log_table_exists= 1;
+ else if (!my_strcasecmp(charset_info, table, "transaction_registry"))
+ transaction_registry_table_exists= 1;
}
}
}
@@ -4764,6 +4770,13 @@ static int dump_all_tables_in_db(char *database)
verbose_msg("-- Warning: get_table_structure() failed with some internal "
"error for 'slow_log' table\n");
}
+ if (transaction_registry_table_exists)
+ {
+ if (!get_table_structure((char *) "transaction_registry",
+ database, table_type, &ignore_flag) )
+ verbose_msg("-- Warning: get_table_structure() failed with some internal "
+ "error for 'transaction_registry' table\n");
+ }
}
if (flush_privileges && using_mysql_db)
{
diff --git a/debian/mariadb-server-10.3.install b/debian/mariadb-server-10.3.install
index 604179c7dca..bc700ab2486 100644
--- a/debian/mariadb-server-10.3.install
+++ b/debian/mariadb-server-10.3.install
@@ -55,6 +55,7 @@ usr/lib/mysql/plugin/query_response_time.so
usr/lib/mysql/plugin/server_audit.so
usr/lib/mysql/plugin/simple_password_check.so
usr/lib/mysql/plugin/sql_errlog.so
+usr/lib/mysql/plugin/versioning.so
usr/lib/mysql/plugin/wsrep_info.so
usr/share/apport/package-hooks/source_mariadb-10.3.py
usr/share/doc/mariadb-server-10.3/mysqld.sym.gz
diff --git a/debian/patches/33_scripts__mysql_create_system_tables__no_test.dpatch b/debian/patches/33_scripts__mysql_create_system_tables__no_test.dpatch
index 183212ef678..06c984c398c 100755
--- a/debian/patches/33_scripts__mysql_create_system_tables__no_test.dpatch
+++ b/debian/patches/33_scripts__mysql_create_system_tables__no_test.dpatch
@@ -10,16 +10,15 @@
@DPATCH@
--- a/scripts/mysql_system_tables_data.sql
+++ b/scripts/mysql_system_tables_data.sql
-@@ -26,16 +26,6 @@
- -- a plain character
+@@ -27,15 +27,6 @@
SELECT LOWER( REPLACE((SELECT REPLACE(@@hostname,'_','\_')),'%','\%') )INTO @current_hostname;
--
+
--- 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;
-
@@ -27,10 +26,10 @@
-- Fill "user" table with default users allowing root access
-- from local machine if "user" table didn't exist before
CREATE TEMPORARY TABLE tmp_user_nopasswd LIKE user;
-@@ -48,9 +38,6 @@ REPLACE INTO tmp_user_nopasswd VALUES ('127.0.0.1','root','','Y','Y','Y','Y','Y'
- 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);
+@@ -48,9 +39,6 @@ REPLACE INTO tmp_user_nopasswd VALUES ('127.0.0.1','root','','Y','Y','Y','Y','Y'
+ 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/debian/patches/38_scripts__mysqld_safe.sh__signals.dpatch b/debian/patches/38_scripts__mysqld_safe.sh__signals.dpatch
index 5a9c3a59698..5cbc897c272 100755
--- a/debian/patches/38_scripts__mysqld_safe.sh__signals.dpatch
+++ b/debian/patches/38_scripts__mysqld_safe.sh__signals.dpatch
@@ -7,9 +7,9 @@
@DPATCH@
---- a/scripts/mysqld_safe.sh 2013-01-11 16:02:41 +0000
-+++ b/scripts/mysqld_safe.sh 2013-01-11 16:03:14 +0000
-@@ -32,7 +32,6 @@ err_log=
+--- a/scripts/mysqld_safe.sh 2013-01-11 16:02:41 +0000
++++ b/scripts/mysqld_safe.sh 2013-01-11 16:03:14 +0000
+@@ -36,7 +36,6 @@ skip_err_log=0
syslog_tag_mysqld=mysqld
syslog_tag_mysqld_safe=mysqld_safe
@@ -17,7 +17,7 @@
# MySQL-specific environment variable. First off, it's not really a umask,
# it's the desired mode. Second, it follows umask(2), not umask(3) in that
-@@ -163,7 +162,7 @@ eval_log_error () {
+@@ -181,7 +180,7 @@ eval_log_error () {
# sed buffers output (only GNU sed supports a -u (unbuffered) option)
# which means that messages may not get sent to syslog until the
# mysqld process quits.
@@ -26,7 +26,7 @@
;;
*)
echo "Internal program error (non-fatal):" \
-@@ -805,6 +804,13 @@ then
+@@ -895,6 +894,13 @@ then
fi
#
diff --git a/debian/patches/41_scripts__mysql_install_db.sh__no_test.dpatch b/debian/patches/41_scripts__mysql_install_db.sh__no_test.dpatch
index 5ab8ab3d3d7..9a063e408a5 100755
--- a/debian/patches/41_scripts__mysql_install_db.sh__no_test.dpatch
+++ b/debian/patches/41_scripts__mysql_install_db.sh__no_test.dpatch
@@ -7,9 +7,9 @@
@DPATCH@
---- mysql-dfsg-5.1-5.1.23rc.orig/scripts/mysql_install_db.sh 2008-01-29 22:41:20.000000000 +0100
-+++ mysql-dfsg-5.1-5.1.23rc/scripts/mysql_install_db.sh 2008-02-28 10:08:11.000000000 +0100
-@@ -372,7 +372,7 @@ then
+--- mysql-dfsg-5.1-5.1.23rc.orig/scripts/mysql_install_db.sh 2008-01-29 22:41:20.000000000 +0100
++++ mysql-dfsg-5.1-5.1.23rc/scripts/mysql_install_db.sh 2008-02-28 10:08:11.000000000 +0100
+@@ -407,7 +407,7 @@ then
fi
# Create database directories
diff --git a/debian/patches/50_mysql-test__db_test.dpatch b/debian/patches/50_mysql-test__db_test.dpatch
index 14c0fc4acf6..ed2efb95998 100755
--- a/debian/patches/50_mysql-test__db_test.dpatch
+++ b/debian/patches/50_mysql-test__db_test.dpatch
@@ -8,15 +8,15 @@
@DPATCH@
---- old/mysql-test/mysql-test-run.pl 2009-06-16 14:24:09.000000000 +0200
-+++ new/mysql-test/mysql-test-run.pl 2009-07-04 00:03:34.000000000 +0200
-@@ -3578,6 +3578,11 @@ sub mysql_install_db {
+--- old/mysql-test/mysql-test-run.pl 2009-06-16 14:24:09.000000000 +0200
++++ new/mysql-test/mysql-test-run.pl 2009-07-04 00:03:34.000000000 +0200
+@@ -3180,6 +3180,11 @@ sub mysql_install_db {
mtr_appendfile_to_file("$sql_dir/mysql_system_tables_data.sql",
$bootstrap_sql_file);
+ mtr_tofile($bootstrap_sql_file, "-- Debian removed the default privileges on the 'test' database\n");
-+ mtr_tofile($bootstrap_sql_file, "INSERT INTO mysql.db VALUES ('%','test','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y','Y','Y','Y','N','N','Y','Y');\n");
-+ mtr_tofile($bootstrap_sql_file, "INSERT INTO mysql.db VALUES ('%','test\\_%','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y','Y','Y','Y','N','N','Y','Y');\n");
++ mtr_tofile($bootstrap_sql_file, "INSERT INTO mysql.db VALUES ('%','test','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y','Y','Y','Y','N','N','Y','Y','Y');\n");
++ mtr_tofile($bootstrap_sql_file, "INSERT INTO mysql.db VALUES ('%','test\\_%','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y','Y','Y','Y','N','N','Y','Y','Y');\n");
+
+
# Add test data for timezone - this is just a subset, on a real
diff --git a/include/m_string.h b/include/m_string.h
index 5cd0b0d2a92..d7ee2582c88 100644
--- a/include/m_string.h
+++ b/include/m_string.h
@@ -201,6 +201,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
typedef struct st_mysql_const_lex_string LEX_CSTRING;
diff --git a/include/my_base.h b/include/my_base.h
index 71dca2e831a..2c93165c912 100644
--- a/include/my_base.h
+++ b/include/my_base.h
@@ -414,6 +414,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/include/mysql.h b/include/mysql.h
index 8d8e0589282..a42f90db1ae 100644
--- a/include/mysql.h
+++ b/include/mysql.h
@@ -145,7 +145,6 @@ typedef unsigned long long my_ulonglong;
#define ER_VIRTUAL_COLUMN_FUNCTION_IS_NOT_ALLOWED ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED
#define ER_PRIMARY_KEY_BASED_ON_VIRTUAL_COLUMN ER_PRIMARY_KEY_BASED_ON_GENERATED_COLUMN
#define ER_WRONG_FK_OPTION_FOR_VIRTUAL_COLUMN ER_WRONG_FK_OPTION_FOR_GENERATED_COLUMN
-#define ER_WARNING_NON_DEFAULT_VALUE_FOR_VIRTUAL_COLUMN ER_WARNING_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN
#define ER_UNSUPPORTED_ACTION_ON_VIRTUAL_COLUMN ER_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN
#define ER_UNSUPPORTED_ENGINE_FOR_VIRTUAL_COLUMNS ER_UNSUPPORTED_ENGINE_FOR_GENERATED_COLUMNS
diff --git a/include/mysql/psi/mysql_thread.h b/include/mysql/psi/mysql_thread.h
index 54a0eaabef7..258e283afe6 100644
--- a/include/mysql/psi/mysql_thread.h
+++ b/include/mysql/psi/mysql_thread.h
@@ -62,6 +62,35 @@
@{
*/
+#ifdef HAVE_PSI_THREAD_INTERFACE
+#define PSI_CALL_delete_current_thread PSI_THREAD_CALL(delete_current_thread)
+#define PSI_CALL_get_thread PSI_THREAD_CALL(get_thread)
+#define PSI_CALL_new_thread PSI_THREAD_CALL(new_thread)
+#define PSI_CALL_register_thread PSI_THREAD_CALL(register_thread)
+#define PSI_CALL_set_thread PSI_THREAD_CALL(set_thread)
+#define PSI_CALL_set_thread_connect_attrs PSI_THREAD_CALL(set_thread_connect_attrs)
+#define PSI_CALL_set_thread_db PSI_THREAD_CALL(set_thread_db)
+#define PSI_CALL_set_thread_id PSI_THREAD_CALL(set_thread_id)
+#define PSI_CALL_set_thread_info PSI_THREAD_CALL(set_thread_info)
+#define PSI_CALL_set_thread_start_time PSI_THREAD_CALL(set_thread_start_time)
+#define PSI_CALL_set_thread_user_host PSI_THREAD_CALL(set_thread_user_host)
+#define PSI_CALL_spawn_thread PSI_THREAD_CALL(spawn_thread)
+#else
+#define PSI_CALL_delete_current_thread() do { } while(0)
+#define PSI_CALL_get_thread() NULL
+#define PSI_CALL_new_thread(A1,A2,A3) NULL
+#define PSI_CALL_register_thread(A1,A2,A3) do { } while(0)
+#define PSI_CALL_set_thread(A1) do { } while(0)
+#define PSI_CALL_set_thread_connect_attrs(A1,A2,A3) 0
+#define PSI_CALL_set_thread_db(A1,A2) do { } while(0)
+#define PSI_CALL_set_thread_id(A1,A2) do { } while(0)
+#define PSI_CALL_set_thread_info(A1, A2) do { } while(0)
+#define PSI_CALL_set_thread_start_time(A1) do { } while(0)
+#define PSI_CALL_set_thread_user_host(A1, A2, A3, A4) do { } while(0)
+#define PSI_CALL_spawn_thread(A1, A2, A3, A4, A5) 0
+#endif
+
+
/**
An instrumented mutex structure.
@sa mysql_mutex_t
diff --git a/include/mysql_com.h b/include/mysql_com.h
index 71858c93046..6db7ef58c6f 100644
--- a/include/mysql_com.h
+++ b/include/mysql_com.h
@@ -192,6 +192,17 @@ 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 VERS_SYS_START_FLAG (1 << 27) /* autogenerated column declared with
+ `generated always as row start`
+ (see II.a SQL Standard) */
+#define VERS_SYS_END_FLAG (1 << 28) /* autogenerated column declared with
+ `generated always as row end`
+ (see II.a SQL Standard).*/
+#define VERS_SYSTEM_FIELD (VERS_SYS_START_FLAG | VERS_SYS_END_FLAG)
+#define VERS_UPDATE_UNVERSIONED_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/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt
index 6e717267548..933f8353afc 100644
--- a/libmysqld/CMakeLists.txt
+++ b/libmysqld/CMakeLists.txt
@@ -120,6 +120,8 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc
../sql/proxy_protocol.cc
../sql/sql_tvc.cc ../sql/sql_tvc.h
../sql/opt_split.cc
+ ../sql/item_vers.cc
+ ../sql/vtmd.cc
${GEN_SOURCES}
${MYSYS_LIBWRAP_SOURCE}
)
diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc
index 25ef6e9b18e..53506de96ad 100644
--- a/libmysqld/lib_sql.cc
+++ b/libmysqld/lib_sql.cc
@@ -731,7 +731,7 @@ emb_transfer_connect_attrs(MYSQL *mysql)
ptr= buf= (uchar *) my_alloca(length + 9);
send_client_connect_attrs(mysql, buf);
net_field_length_ll(&ptr);
- PSI_THREAD_CALL(set_thread_connect_attrs)((char *) ptr, length, thd->charset());
+ PSI_CALL_set_thread_connect_attrs((char *) ptr, length, thd->charset());
my_afree(buf);
}
#endif
diff --git a/mysql-test/collections/buildbot_suites.bat b/mysql-test/collections/buildbot_suites.bat
index 89e68919c7f..7589eabd452 100644
--- a/mysql-test/collections/buildbot_suites.bat
+++ b/mysql-test/collections/buildbot_suites.bat
@@ -1,6 +1,7 @@
perl mysql-test-run.pl --verbose-restart --force --testcase-timeout=45 --suite-timeout=600 --max-test-fail=500 --retry=3 --parallel=4 --suite=^
main,^
innodb,^
+versioning,^
plugins,^
mariabackup,^
rocksdb
diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
index 90ac4c85248..6b37f682a7b 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-
galera-
);
@@ -3761,14 +3762,32 @@ sub run_testcase ($$) {
$ENV{'MTR_TEST_NAME'} = $tinfo->{name};
resfile_report_test($tinfo) if $opt_resfile;
- # Allow only alpanumerics pluss _ - + . in combination names,
- # or anything beginning with -- (the latter comes from --combination)
- my $combination= $tinfo->{combination};
- if ($combination && $combination !~ /^\w[-\w\.\+]*$/
- && $combination !~ /^--/)
+ for my $key (grep { /^MTR_COMBINATION/ } keys %ENV)
{
- mtr_error("Combination '$combination' contains illegal characters");
+ delete $ENV{$key};
}
+
+ if (ref $tinfo->{combinations} eq 'ARRAY')
+ {
+ for (my $i = 0; $i < @{$tinfo->{combinations}}; ++$i )
+ {
+ my $combination = $tinfo->{combinations}->[$i];
+ # Allow only alphanumerics plus _ - + . in combination names,
+ # or anything beginning with -- (the latter comes from --combination)
+ if ($combination && $combination !~ /^\w[-\w\.\+]*$/
+ && $combination !~ /^--/)
+ {
+ mtr_error("Combination '$combination' contains illegal characters");
+ }
+ $ENV{"MTR_COMBINATION_". uc(${combination})} = 1;
+ }
+ $ENV{"MTR_COMBINATIONS"} = join(',', @{$tinfo->{combinations}});
+ }
+ elsif (exists $tinfo->{combinations})
+ {
+ die 'Unexpected type of $tinfo->{combinations}';
+ }
+
# -------------------------------------------------------
# Init variables that can change between each test case
# -------------------------------------------------------
diff --git a/mysql-test/r/1st.result b/mysql-test/r/1st.result
index f9e4b37aa94..cb2da3505f5 100644
--- a/mysql-test/r/1st.result
+++ b/mysql-test/r/1st.result
@@ -36,4 +36,5 @@ time_zone_leap_second
time_zone_name
time_zone_transition
time_zone_transition_type
+transaction_registry
user
diff --git a/mysql-test/r/alter_user.result b/mysql-test/r/alter_user.result
index ac668bba8fa..c4e41c77eca 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 Truncate_versioning_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 Truncate_versioning_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 Truncate_versioning_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 Truncate_versioning_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 Truncate_versioning_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 Truncate_versioning_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 Truncate_versioning_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 Truncate_versioning_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 Truncate_versioning_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 Truncate_versioning_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 Truncate_versioning_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 Truncate_versioning_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 Truncate_versioning_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 Truncate_versioning_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/connect.result b/mysql-test/r/connect.result
index dfe4406605e..f36483e6d8d 100644
--- a/mysql-test/r/connect.result
+++ b/mysql-test/r/connect.result
@@ -32,6 +32,7 @@ time_zone_leap_second
time_zone_name
time_zone_transition
time_zone_transition_type
+transaction_registry
user
connect con2,localhost,root,,test;
show tables;
@@ -79,6 +80,7 @@ time_zone_leap_second
time_zone_name
time_zone_transition
time_zone_transition_type
+transaction_registry
user
connect con4,localhost,test,gambling,test;
show tables;
@@ -138,6 +140,7 @@ time_zone_leap_second
time_zone_name
time_zone_transition
time_zone_transition_type
+transaction_registry
user
connect con6,localhost,test,gambling3,test;
show tables;
diff --git a/mysql-test/r/create_user.result b/mysql-test/r/create_user.result
index 1411f2e8792..f8c5582da0c 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 Truncate_versioning_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 Truncate_versioning_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 Truncate_versioning_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 Truncate_versioning_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 Truncate_versioning_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 Truncate_versioning_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 Truncate_versioning_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 Truncate_versioning_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 Truncate_versioning_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 Truncate_versioning_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 Truncate_versioning_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 Truncate_versioning_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/ctype_upgrade.result b/mysql-test/r/ctype_upgrade.result
index 53cb858035b..5f0be66f8fb 100644
--- a/mysql-test/r/ctype_upgrade.result
+++ b/mysql-test/r/ctype_upgrade.result
@@ -8,7 +8,7 @@ CHECK TABLE maria050313_utf8_croatian_ci FOR UPGRADE;
Table Op Msg_type Msg_text
test.maria050313_utf8_croatian_ci check error Upgrade required. Please do "REPAIR TABLE `maria050313_utf8_croatian_ci`" or dump/reload to fix it!
SHOW CREATE TABLE maria050313_utf8_croatian_ci;
-ERROR HY000: Table rebuild required. Please do "ALTER TABLE `test.maria050313_utf8_croatian_c` FORCE" or dump/reload to fix it!
+ERROR HY000: Table rebuild required. Please do "ALTER TABLE `test.maria050313_utf8_croatian_ci` FORCE" or dump/reload to fix it!
REPAIR TABLE maria050313_utf8_croatian_ci;
Table Op Msg_type Msg_text
test.maria050313_utf8_croatian_ci repair status OK
@@ -45,7 +45,7 @@ CHECK TABLE maria050313_ucs2_croatian_ci_def FOR UPGRADE;
Table Op Msg_type Msg_text
test.maria050313_ucs2_croatian_ci_def check error Upgrade required. Please do "REPAIR TABLE `maria050313_ucs2_croatian_ci_def`" or dump/reload to fix it!
SELECT count(*) FROM maria050313_ucs2_croatian_ci_def;
-ERROR HY000: Table rebuild required. Please do "ALTER TABLE `test.maria050313_ucs2_croatian_c` FORCE" or dump/reload to fix it!
+ERROR HY000: Table rebuild required. Please do "ALTER TABLE `test.maria050313_ucs2_croatian_ci_def` FORCE" or dump/reload to fix it!
REPAIR TABLE maria050313_ucs2_croatian_ci_def;
Table Op Msg_type Msg_text
test.maria050313_ucs2_croatian_ci_def repair status OK
@@ -257,6 +257,7 @@ mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
+mysql.transaction_registry OK
mysql.user OK
Phase 2/7: Installing used storage engines... Skipped
Phase 3/7: Fixing views
@@ -315,6 +316,7 @@ mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
+mysql.transaction_registry OK
mysql.user OK
Phase 2/7: Installing used storage engines... Skipped
Phase 3/7: Fixing views
diff --git a/mysql-test/r/derived_view.result b/mysql-test/r/derived_view.result
index d3c9fc1e064..85e56ff176e 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/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/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/grant.result b/mysql-test/r/grant.result
index 5f9e682d63d..52835b44085 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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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 Truncate_versioning_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 34f8fe25352..a4c287f54d8 100644
--- a/mysql-test/r/information_schema.result
+++ b/mysql-test/r/information_schema.result
@@ -121,6 +121,7 @@ time_zone_leap_second
time_zone_name
time_zone_transition
time_zone_transition_type
+transaction_registry
user
v1
select c,table_name from v1
@@ -145,6 +146,7 @@ time_zone_leap_second time_zone_leap_second
time_zone_name time_zone_name
time_zone_transition time_zone_transition
time_zone_transition_type time_zone_transition_type
+transaction_registry transaction_registry
select c,table_name from v1
left join information_schema.TABLES v2 on (v1.c=v2.table_name)
where v1.c like "t%";
@@ -167,6 +169,7 @@ time_zone_leap_second time_zone_leap_second
time_zone_name time_zone_name
time_zone_transition time_zone_transition
time_zone_transition_type time_zone_transition_type
+transaction_registry transaction_registry
select c, v2.table_name from v1
right join information_schema.TABLES v2 on (v1.c=v2.table_name)
where v1.c like "t%";
@@ -189,6 +192,7 @@ time_zone_leap_second time_zone_leap_second
time_zone_name time_zone_name
time_zone_transition time_zone_transition
time_zone_transition_type time_zone_transition_type
+transaction_registry transaction_registry
select table_name from information_schema.TABLES
where table_schema = "mysqltest" and table_name like "t%";
table_name
@@ -487,6 +491,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 +749,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
+Truncate_versioning_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/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 df48dbba605..046674d5569 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 8
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..8f822d56020 100644
--- a/mysql-test/r/log_tables_upgrade.result
+++ b/mysql-test/r/log_tables_upgrade.result
@@ -42,6 +42,7 @@ mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
+mysql.transaction_registry OK
mysql.user OK
Phase 2/7: Installing used storage engines... Skipped
Phase 3/7: Fixing views
diff --git a/mysql-test/r/lowercase_table_grant.result b/mysql-test/r/lowercase_table_grant.result
index 009965c0c8e..c12592887dc 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 Truncate_versioning_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 Truncate_versioning_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/mysql_upgrade-6984.result b/mysql-test/r/mysql_upgrade-6984.result
index 59c9a865b7c..6c711b4847f 100644
--- a/mysql-test/r/mysql_upgrade-6984.result
+++ b/mysql-test/r/mysql_upgrade-6984.result
@@ -33,6 +33,9 @@ mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
+mysql.transaction_registry
+Error : Unknown storage engine 'InnoDB'
+error : Corrupt
mysql.user OK
Repairing tables
@@ -42,6 +45,9 @@ error : Corrupt
mysql.innodb_table_stats
Error : Unknown storage engine 'InnoDB'
error : Corrupt
+mysql.transaction_registry
+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 a6a5da8f8c8..5da7e3149ec 100644
--- a/mysql-test/r/mysql_upgrade.result
+++ b/mysql-test/r/mysql_upgrade.result
@@ -30,6 +30,7 @@ mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
+mysql.transaction_registry OK
mysql.user OK
Phase 2/7: Installing used storage engines... Skipped
Phase 3/7: Fixing views
@@ -78,6 +79,7 @@ mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
+mysql.transaction_registry OK
mysql.user OK
Phase 2/7: Installing used storage engines... Skipped
Phase 3/7: Fixing views
@@ -126,6 +128,7 @@ mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
+mysql.transaction_registry OK
mysql.user OK
Phase 2/7: Installing used storage engines... Skipped
Phase 3/7: Fixing views
@@ -179,6 +182,7 @@ mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
+mysql.transaction_registry OK
mysql.user OK
Phase 2/7: Installing used storage engines... Skipped
Phase 3/7: Fixing views
@@ -233,6 +237,7 @@ mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
+mysql.transaction_registry OK
mysql.user OK
Phase 2/7: Installing used storage engines... Skipped
Phase 3/7: Fixing views
@@ -290,6 +295,7 @@ mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
+mysql.transaction_registry OK
mysql.user OK
Phase 2/7: Installing used storage engines... Skipped
Phase 3/7: Fixing views
@@ -342,6 +348,7 @@ mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
+mysql.transaction_registry OK
mysql.user OK
Phase 2/7: Installing used storage engines... Skipped
Phase 3/7: Fixing views... Skipped
@@ -386,6 +393,7 @@ mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
+mysql.transaction_registry OK
mysql.user OK
Phase 2/7: Installing used storage engines... Skipped
Phase 3/7: Fixing views
@@ -451,6 +459,7 @@ mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
+mysql.transaction_registry OK
mysql.user OK
Phase 2/7: Installing used storage engines... Skipped
Phase 3/7: Fixing views
@@ -533,6 +542,7 @@ mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
+mysql.transaction_registry OK
mysql.user OK
Phase 2/7: Installing used storage engines... Skipped
Phase 3/7: Fixing views
@@ -552,7 +562,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..8e051bb7c16 100644
--- a/mysql-test/r/mysql_upgrade_no_innodb.result
+++ b/mysql-test/r/mysql_upgrade_no_innodb.result
@@ -33,6 +33,9 @@ mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
+mysql.transaction_registry
+Error : Unknown storage engine 'InnoDB'
+error : Corrupt
mysql.user OK
Repairing tables
@@ -42,6 +45,9 @@ error : Corrupt
mysql.innodb_table_stats
Error : Unknown storage engine 'InnoDB'
error : Corrupt
+mysql.transaction_registry
+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 ef6657e0a0c..7b3b1610ee0 100644
--- a/mysql-test/r/mysql_upgrade_noengine.result
+++ b/mysql-test/r/mysql_upgrade_noengine.result
@@ -83,6 +83,7 @@ mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
+mysql.transaction_registry OK
mysql.user OK
Phase 2/7: Installing used storage engines... Skipped
Phase 3/7: Fixing views
@@ -171,6 +172,7 @@ mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
+mysql.transaction_registry OK
mysql.user OK
Phase 2/7: Installing used storage engines... Skipped
Phase 3/7: Fixing views
@@ -259,6 +261,7 @@ mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
+mysql.transaction_registry OK
mysql.user OK
Upgrading from a version before MariaDB-10.1
Phase 2/7: Installing used storage engines
diff --git a/mysql-test/r/mysql_upgrade_ssl.result b/mysql-test/r/mysql_upgrade_ssl.result
index 918a24ffc71..172a1401cdb 100644
--- a/mysql-test/r/mysql_upgrade_ssl.result
+++ b/mysql-test/r/mysql_upgrade_ssl.result
@@ -31,6 +31,7 @@ mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
+mysql.transaction_registry OK
mysql.user OK
Phase 2/7: Installing used storage engines... Skipped
Phase 3/7: Fixing views
diff --git a/mysql-test/r/mysql_upgrade_view.result b/mysql-test/r/mysql_upgrade_view.result
index dc31592566a..813138b57a8 100644
--- a/mysql-test/r/mysql_upgrade_view.result
+++ b/mysql-test/r/mysql_upgrade_view.result
@@ -97,6 +97,9 @@ mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
+mysql.transaction_registry
+Error : Unknown storage engine 'InnoDB'
+error : Corrupt
mysql.user OK
Repairing tables
@@ -106,6 +109,9 @@ error : Corrupt
mysql.innodb_table_stats
Error : Unknown storage engine 'InnoDB'
error : Corrupt
+mysql.transaction_registry
+Error : Unknown storage engine 'InnoDB'
+error : Corrupt
Phase 2/7: Installing used storage engines... Skipped
Phase 3/7: Fixing views
test.v1 OK
@@ -241,6 +247,9 @@ mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
+mysql.transaction_registry
+Error : Unknown storage engine 'InnoDB'
+error : Corrupt
mysql.user OK
Repairing tables
@@ -250,6 +259,9 @@ error : Corrupt
mysql.innodb_table_stats
Error : Unknown storage engine 'InnoDB'
error : Corrupt
+mysql.transaction_registry
+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
@@ -360,6 +372,9 @@ mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
+mysql.transaction_registry
+Error : Unknown storage engine 'InnoDB'
+error : Corrupt
mysql.user OK
Repairing tables
@@ -369,6 +384,9 @@ error : Corrupt
mysql.innodb_table_stats
Error : Unknown storage engine 'InnoDB'
error : Corrupt
+mysql.transaction_registry
+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 705683322f8..cbea1cf9def 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, "")
#<date> server id 1 end_log_pos 899 CRC32 XXX Table_map: `test`.`t1` mapped to number num
# at 899
-#<date> server id 1 end_log_pos 967 CRC32 XXX Write_compressed_rows: table id 30 flags: STMT_END_F
+#<date> 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 */
@@ -90,7 +90,7 @@ BEGIN
#Q> INSERT INTO t1 VALUES (11, 1, 2, 3, 4, 5, 6, 7, NULL)
#<date> server id 1 end_log_pos 1214 CRC32 XXX Table_map: `test`.`t1` mapped to number num
# at 1214
-#<date> server id 1 end_log_pos 1281 CRC32 XXX Write_compressed_rows: table id 30 flags: STMT_END_F
+#<date> 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 */
@@ -119,7 +119,7 @@ BEGIN
#Q> INSERT INTO t1 VALUES (12, 1, 2, 3, NULL, 5, 6, 7, "A")
#<date> server id 1 end_log_pos 1530 CRC32 XXX Table_map: `test`.`t1` mapped to number num
# at 1530
-#<date> server id 1 end_log_pos 1596 CRC32 XXX Write_compressed_rows: table id 30 flags: STMT_END_F
+#<date> 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 */
@@ -148,7 +148,7 @@ BEGIN
#Q> INSERT INTO t1 VALUES (13, 1, 2, 3, 0, 5, 6, 7, "A")
#<date> server id 1 end_log_pos 1842 CRC32 XXX Table_map: `test`.`t1` mapped to number num
# at 1842
-#<date> server id 1 end_log_pos 1909 CRC32 XXX Write_compressed_rows: table id 30 flags: STMT_END_F
+#<date> 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 */
@@ -177,7 +177,7 @@ BEGIN
#Q> INSERT INTO t2 SELECT * FROM t1
#<date> server id 1 end_log_pos 2134 CRC32 XXX Table_map: `test`.`t2` mapped to number num
# at 2134
-#<date> server id 1 end_log_pos 2225 CRC32 XXX Write_compressed_rows: table id 31 flags: STMT_END_F
+#<date> 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 */
@@ -239,7 +239,7 @@ BEGIN
#Q> UPDATE t2 SET f4=5 WHERE f4>0 or f4 is NULL
#<date> server id 1 end_log_pos 2462 CRC32 XXX Table_map: `test`.`t2` mapped to number num
# at 2462
-#<date> server id 1 end_log_pos 2561 CRC32 XXX Update_compressed_rows: table id 31 flags: STMT_END_F
+#<date> 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 */
@@ -320,7 +320,7 @@ BEGIN
#Q> DELETE FROM t1
#<date> server id 1 end_log_pos 2769 CRC32 XXX Table_map: `test`.`t1` mapped to number num
# at 2769
-#<date> server id 1 end_log_pos 2861 CRC32 XXX Delete_compressed_rows: table id 30 flags: STMT_END_F
+#<date> 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 */
@@ -382,7 +382,7 @@ BEGIN
#Q> DELETE FROM t2
#<date> server id 1 end_log_pos 3069 CRC32 XXX Table_map: `test`.`t2` mapped to number num
# at 3069
-#<date> server id 1 end_log_pos 3154 CRC32 XXX Delete_compressed_rows: table id 31 flags: STMT_END_F
+#<date> 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 a030f202f45..6417a528638 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, "")
#<date> server id 1 end_log_pos 946 CRC32 XXX Table_map: `test`.`t1` mapped to number num
# at 946
-#<date> server id 1 end_log_pos 1015 CRC32 XXX Write_rows: table id 30 flags: STMT_END_F
+#<date> 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 */
@@ -88,7 +88,7 @@ BEGIN
#Q> INSERT INTO t1 VALUES (11, 1, 2, 3, 4, 5, 6, 7, NULL)
#<date> server id 1 end_log_pos 1262 CRC32 XXX Table_map: `test`.`t1` mapped to number num
# at 1262
-#<date> server id 1 end_log_pos 1330 CRC32 XXX Write_rows: table id 30 flags: STMT_END_F
+#<date> 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 */
@@ -117,7 +117,7 @@ BEGIN
#Q> INSERT INTO t1 VALUES (12, 1, 2, 3, NULL, 5, 6, 7, "A")
#<date> server id 1 end_log_pos 1579 CRC32 XXX Table_map: `test`.`t1` mapped to number num
# at 1579
-#<date> server id 1 end_log_pos 1646 CRC32 XXX Write_rows: table id 30 flags: STMT_END_F
+#<date> 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 */
@@ -146,7 +146,7 @@ BEGIN
#Q> INSERT INTO t1 VALUES (13, 1, 2, 3, 0, 5, 6, 7, "A")
#<date> server id 1 end_log_pos 1892 CRC32 XXX Table_map: `test`.`t1` mapped to number num
# at 1892
-#<date> server id 1 end_log_pos 1962 CRC32 XXX Write_rows: table id 30 flags: STMT_END_F
+#<date> 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 */
@@ -175,7 +175,7 @@ BEGIN
#Q> INSERT INTO t2 SELECT * FROM t1
#<date> server id 1 end_log_pos 2187 CRC32 XXX Table_map: `test`.`t2` mapped to number num
# at 2187
-#<date> server id 1 end_log_pos 2354 CRC32 XXX Write_rows: table id 31 flags: STMT_END_F
+#<date> 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 */
@@ -237,7 +237,7 @@ BEGIN
#Q> UPDATE t2 SET f4=5 WHERE f4>0 or f4 is NULL
#<date> server id 1 end_log_pos 2591 CRC32 XXX Table_map: `test`.`t2` mapped to number num
# at 2591
-#<date> server id 1 end_log_pos 2665 CRC32 XXX Update_rows: table id 31 flags: STMT_END_F
+#<date> 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 */
@@ -273,7 +273,7 @@ BEGIN
#Q> DELETE FROM t1
#<date> server id 1 end_log_pos 2873 CRC32 XXX Table_map: `test`.`t1` mapped to number num
# at 2873
-#<date> server id 1 end_log_pos 2927 CRC32 XXX Delete_rows: table id 30 flags: STMT_END_F
+#<date> 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 */
@@ -303,7 +303,7 @@ BEGIN
#Q> DELETE FROM t2
#<date> server id 1 end_log_pos 3135 CRC32 XXX Table_map: `test`.`t2` mapped to number num
# at 3135
-#<date> server id 1 end_log_pos 3189 CRC32 XXX Delete_rows: table id 31 flags: STMT_END_F
+#<date> 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..7259b68be50 100644
--- a/mysql-test/r/mysqlcheck.result
+++ b/mysql-test/r/mysqlcheck.result
@@ -31,6 +31,7 @@ mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
+mysql.transaction_registry OK
mysql.user OK
mtr.global_suppressions Table is already up to date
mtr.test_suppressions Table is already up to date
@@ -65,6 +66,9 @@ mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
+mysql.transaction_registry
+note : Table does not support optimize, doing recreate + analyze instead
+status : OK
mysql.user OK
mysql.column_stats OK
mysql.columns_priv OK
@@ -93,6 +97,7 @@ mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
+mysql.transaction_registry OK
mysql.user OK
mysql.column_stats Table is already up to date
mysql.columns_priv Table is already up to date
@@ -125,6 +130,9 @@ mysql.time_zone_leap_second Table is already up to date
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.transaction_registry
+note : Table does not support optimize, doing recreate + analyze instead
+status : OK
mysql.user Table is already up to date
create table t1 (a int) engine=myisam;
create view v1 as select * from t1;
@@ -447,6 +455,7 @@ mysql.time_zone_leap_second Table is already up to date
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.transaction_registry OK
mysql.user Table is already up to date
mysqltest1.t1
warning : Table is marked as crashed
diff --git a/mysql-test/r/mysqld--help.result b/mysql-test/r/mysqld--help.result
index 0e9a0d3dc5d..2ca655939a9 100644
--- a/mysql-test/r/mysqld--help.result
+++ b/mysql-test/r/mysqld--help.result
@@ -1219,6 +1219,17 @@ The following options may be given as the first argument:
safe-replicable. Since 5.0, SYSDATE() returns a `dynamic'
value different for different invocations, even within
the same statement.
+ --system-versioning-alter-history=name
+ Versioning ALTER TABLE mode. ERROR: Fail ALTER with
+ error; KEEP: Keep historical system rows and subject them
+ to ALTER;
+ --system-versioning-innodb-algorithm-simple
+ Use simple algorithm of timestamp handling in InnoDB
+ instead of TRX_SEES
+ (Defaults to on; use --skip-system-versioning-innodb-algorithm-simple to disable.)
+ --system-versioning-transaction-registry
+ Enable or disable update of
+ `mysql`.`transaction_registry`
--table-cache=# Deprecated; use --table-open-cache instead.
--table-definition-cache=#
The number of cached table definitions
@@ -1647,6 +1658,9 @@ sync-master-info 10000
sync-relay-log 10000
sync-relay-log-info 10000
sysdate-is-now FALSE
+system-versioning-alter-history ERROR
+system-versioning-innodb-algorithm-simple TRUE
+system-versioning-transaction-registry FALSE
table-cache 431
table-definition-cache 400
table-open-cache 431
diff --git a/mysql-test/r/no_password_column-mdev-11170.result b/mysql-test/r/no_password_column-mdev-11170.result
index 81eecc95558..6b9c880ce5c 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
+Truncate_versioning_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/partition_alter.result b/mysql-test/r/partition_alter.result
index 6aa0039c8d2..e42604ba056 100644
--- a/mysql-test/r/partition_alter.result
+++ b/mysql-test/r/partition_alter.result
@@ -120,3 +120,10 @@ t1 CREATE TABLE `t1` (
PARTITION `p02` ENGINE = MyISAM,
PARTITION `p03` ENGINE = MyISAM)
drop table t1;
+create or replace table t1 (x int) partition by hash (x) (partition p1, partition p2);
+lock table t1 write;
+alter table t1 add partition (partition p1);
+ERROR HY000: Duplicate partition name p1
+alter table t1 add partition (partition p1);
+ERROR HY000: Duplicate partition name p1
+drop table t1;
diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result
index 51cdbb90df3..91b8cb8bc98 100644
--- a/mysql-test/r/ps.result
+++ b/mysql-test/r/ps.result
@@ -1207,22 +1207,25 @@ 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'
+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/sql_mode.result b/mysql-test/r/sql_mode.result
index c6c241413d6..c361f41154f 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 Truncate_versioning_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 1227896853d..3228a3d2782 100644
--- a/mysql-test/r/system_mysql_db.result
+++ b/mysql-test/r/system_mysql_db.result
@@ -29,6 +29,7 @@ time_zone_leap_second
time_zone_name
time_zone_transition
time_zone_transition_type
+transaction_registry
user
show create table db;
Table Create Table
@@ -55,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',
+ `Truncate_versioning_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 +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',
+ `Truncate_versioning_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,
@@ -152,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 1227896853d..c5115558a68 100644
--- a/mysql-test/r/system_mysql_db_fix40123.result
+++ b/mysql-test/r/system_mysql_db_fix40123.result
@@ -29,6 +29,7 @@ time_zone_leap_second
time_zone_name
time_zone_transition
time_zone_transition_type
+transaction_registry
user
show create table db;
Table Create Table
@@ -55,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',
+ `Truncate_versioning_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'
@@ -117,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',
+ `Truncate_versioning_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,
@@ -152,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 0ebc7934f76..cbada2c333e 100644
--- a/mysql-test/r/system_mysql_db_fix50030.result
+++ b/mysql-test/r/system_mysql_db_fix50030.result
@@ -29,6 +29,7 @@ time_zone_leap_second
time_zone_name
time_zone_transition
time_zone_transition_type
+transaction_registry
user
show create table db;
Table Create Table
@@ -55,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',
+ `Truncate_versioning_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'
@@ -117,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',
+ `Truncate_versioning_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,
@@ -152,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 1227896853d..c5115558a68 100644
--- a/mysql-test/r/system_mysql_db_fix50117.result
+++ b/mysql-test/r/system_mysql_db_fix50117.result
@@ -29,6 +29,7 @@ time_zone_leap_second
time_zone_name
time_zone_transition
time_zone_transition_type
+transaction_registry
user
show create table db;
Table Create Table
@@ -55,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',
+ `Truncate_versioning_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'
@@ -117,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',
+ `Truncate_versioning_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,
@@ -152,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/trigger.result b/mysql-test/r/trigger.result
index 091cbec4c73..8473b3bb90d 100644
--- a/mysql-test/r/trigger.result
+++ b/mysql-test/r/trigger.result
@@ -2125,7 +2125,7 @@ SHOW TRIGGERS IN db1;
Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation
trg1 INSERT t2 CREATE DEFINER=`root`@`localhost` TRIGGER trg1 BEFORE INSERT ON t2 FOR EACH ROW INSERTINTOt1 VALUES (1) BEFORE # STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION latin1 latin1_swedish_ci latin1_swedish_ci
INSERT INTO t2 VALUES (1);
-ERROR 42000: Trigger 'trg1' has an error in its body: '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 '(1)' at line 1'
+ERROR 42000: Trigger 'trg1' has an error in its body: '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 'VALUES (1)' at line 1'
SELECT * FROM t1;
b
# Work around Bug#45235
diff --git a/mysql-test/suite/binlog/r/binlog_base64_flag.result b/mysql-test/suite/binlog/r/binlog_base64_flag.result
index db7b175d6bd..66cee19f13f 100644
--- a/mysql-test/suite/binlog/r/binlog_base64_flag.result
+++ b/mysql-test/suite/binlog/r/binlog_base64_flag.result
@@ -9,7 +9,7 @@ BINLOG '
SVtYRxMBAAAAKQAAADQBAAAAABAAAAAAAAAABHRlc3QAAnQxAAEDAAE=
SVtYRxcBAAAAIgAAAFYBAAAQABAAAAAAAAEAAf/+AgAAAA==
';
-ERROR HY000: The BINLOG statement of type `Table_map` was not preceded by a format description BINLOG statement
+ERROR HY000: The BINLOG statement of type Table_map was not preceded by a format description BINLOG statement
select * from t1;
a
1
diff --git a/mysql-test/suite/encryption/r/encrypt_and_grep.result b/mysql-test/suite/encryption/r/encrypt_and_grep.result
index 05ebefd28b5..cbc05dc7cc6 100644
--- a/mysql-test/suite/encryption/r/encrypt_and_grep.result
+++ b/mysql-test/suite/encryption/r/encrypt_and_grep.result
@@ -15,6 +15,7 @@ SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_
NAME
mysql/innodb_table_stats
mysql/innodb_index_stats
+mysql/transaction_registry
test/t1
test/t2
innodb_system
@@ -33,6 +34,7 @@ SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_
NAME
mysql/innodb_table_stats
mysql/innodb_index_stats
+mysql/transaction_registry
test/t2
test/t3
innodb_system
@@ -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/transaction_registry
test/t1
test/t2
innodb_system
diff --git a/mysql-test/suite/encryption/r/innodb-spatial-index.result b/mysql-test/suite/encryption/r/innodb-spatial-index.result
index d8f76988f9e..e8e133c61a1 100644
--- a/mysql-test/suite/encryption/r/innodb-spatial-index.result
+++ b/mysql-test/suite/encryption/r/innodb-spatial-index.result
@@ -38,6 +38,7 @@ SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_
NAME
mysql/innodb_table_stats
mysql/innodb_index_stats
+mysql/transaction_registry
test/t1
test/t2
innodb_system
diff --git a/mysql-test/suite/encryption/r/innodb_encryption.result b/mysql-test/suite/encryption/r/innodb_encryption.result
index 72f2632ba26..ee3774bcee0 100644
--- a/mysql-test/suite/encryption/r/innodb_encryption.result
+++ b/mysql-test/suite/encryption/r/innodb_encryption.result
@@ -14,6 +14,7 @@ SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_
NAME
mysql/innodb_table_stats
mysql/innodb_index_stats
+mysql/transaction_registry
innodb_system
# Success!
# Now turn off encryption and wait for threads to decrypt everything
@@ -23,6 +24,7 @@ SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_
NAME
mysql/innodb_table_stats
mysql/innodb_index_stats
+mysql/transaction_registry
innodb_system
SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0;
NAME
@@ -37,6 +39,7 @@ SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_
NAME
mysql/innodb_table_stats
mysql/innodb_index_stats
+mysql/transaction_registry
innodb_system
SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0;
NAME
@@ -50,6 +53,7 @@ SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_
NAME
mysql/innodb_table_stats
mysql/innodb_index_stats
+mysql/transaction_registry
innodb_system
# Success!
# Restart mysqld --innodb_encrypt_tables=0 --innodb_encryption_threads=0
@@ -64,6 +68,7 @@ SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_
NAME
mysql/innodb_table_stats
mysql/innodb_index_stats
+mysql/transaction_registry
innodb_system
SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0;
NAME
diff --git a/mysql-test/suite/encryption/r/innodb_lotoftables.result b/mysql-test/suite/encryption/r/innodb_lotoftables.result
index da07a52f8c3..9dadf13f039 100644
--- a/mysql-test/suite/encryption/r/innodb_lotoftables.result
+++ b/mysql-test/suite/encryption/r/innodb_lotoftables.result
@@ -10,13 +10,13 @@ create database innodb_encrypted_1;
use innodb_encrypted_1;
show status like 'innodb_pages0_read%';
Variable_name Value
-Innodb_pages0_read 3
+Innodb_pages0_read 4
set autocommit=0;
set autocommit=1;
commit work;
show status like 'innodb_pages0_read%';
Variable_name Value
-Innodb_pages0_read 3
+Innodb_pages0_read 4
# should be empty
SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE NAME LIKE 'innodb_encrypted%';
NAME
@@ -24,13 +24,13 @@ create database innodb_encrypted_2;
use innodb_encrypted_2;
show status like 'innodb_pages0_read%';
Variable_name Value
-Innodb_pages0_read 3
+Innodb_pages0_read 4
set autocommit=0;
commit work;
set autocommit=1;
show status like 'innodb_pages0_read%';
Variable_name Value
-Innodb_pages0_read 3
+Innodb_pages0_read 4
# should contain 100 tables
SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 AND NAME LIKE 'innodb_encrypted%' ORDER BY NAME;
NAME
@@ -141,13 +141,13 @@ create database innodb_encrypted_3;
use innodb_encrypted_3;
show status like 'innodb_pages0_read%';
Variable_name Value
-Innodb_pages0_read 3
+Innodb_pages0_read 4
set autocommit=0;
commit work;
set autocommit=1;
show status like 'innodb_pages0_read%';
Variable_name Value
-Innodb_pages0_read 3
+Innodb_pages0_read 4
# should contain 100 tables
SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 AND NAME LIKE 'innodb_encrypted%' ORDER BY NAME;
NAME
@@ -357,7 +357,7 @@ innodb_encrypted_3/t_99
use test;
show status like 'innodb_pages0_read%';
Variable_name Value
-Innodb_pages0_read 3
+Innodb_pages0_read 4
SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 AND NAME LIKE 'innodb_encrypted%' ORDER BY NAME;
NAME
innodb_encrypted_2/t_1
@@ -770,53 +770,53 @@ innodb_encrypted_3/t_98
innodb_encrypted_3/t_99
show status like 'innodb_pages0_read%';
Variable_name Value
-Innodb_pages0_read 3
+Innodb_pages0_read 4
# Success!
# Restart mysqld --innodb_encrypt_tables=0 --innodb_encryption_threads=0
# Restart Success!
show status like 'innodb_pages0_read%';
Variable_name Value
-Innodb_pages0_read 303
+Innodb_pages0_read 304
show status like 'innodb_pages0_read%';
Variable_name Value
-Innodb_pages0_read 303
+Innodb_pages0_read 304
use test;
show status like 'innodb_pages0_read%';
Variable_name Value
-Innodb_pages0_read 303
+Innodb_pages0_read 304
use innodb_encrypted_1;
show status like 'innodb_pages0_read%';
Variable_name Value
-Innodb_pages0_read 303
+Innodb_pages0_read 304
use innodb_encrypted_2;
show status like 'innodb_pages0_read%';
Variable_name Value
-Innodb_pages0_read 303
+Innodb_pages0_read 304
use innodb_encrypted_3;
show status like 'innodb_pages0_read%';
Variable_name Value
-Innodb_pages0_read 303
+Innodb_pages0_read 304
use innodb_encrypted_1;
show status like 'innodb_pages0_read%';
Variable_name Value
-Innodb_pages0_read 303
+Innodb_pages0_read 304
show status like 'innodb_pages0_read%';
Variable_name Value
-Innodb_pages0_read 303
+Innodb_pages0_read 304
use innodb_encrypted_2;
show status like 'innodb_pages0_read%';
Variable_name Value
-Innodb_pages0_read 303
+Innodb_pages0_read 304
show status like 'innodb_pages0_read%';
Variable_name Value
-Innodb_pages0_read 303
+Innodb_pages0_read 304
use innodb_encrypted_3;
show status like 'innodb_pages0_read%';
Variable_name Value
-Innodb_pages0_read 303
+Innodb_pages0_read 304
show status like 'innodb_pages0_read%';
Variable_name Value
-Innodb_pages0_read 303
+Innodb_pages0_read 304
SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 AND NAME LIKE 'innodb_encrypted%' ORDER BY NAME;
NAME
innodb_encrypted_3/t_1
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/innodb_views.result b/mysql-test/suite/funcs_1/r/innodb_views.result
index 01ad3e3dda7..24672a20adc 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/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.result b/mysql-test/suite/funcs_1/r/is_columns.result
index 982f4de5116..f1c784e2839 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 4305c40770c..cfbf06a4ed2 100644
--- a/mysql-test/suite/funcs_1/r/is_columns_mysql.result
+++ b/mysql-test/suite/funcs_1/r/is_columns_mysql.result
@@ -40,6 +40,7 @@ def mysql db References_priv 11 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general
def mysql db Select_priv 4 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL
def mysql db Show_view_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 db Trigger_priv 22 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') select,insert,update,references NEVER NULL
+def mysql db Truncate_versioning_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 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 db User 3 '' NO char 80 240 NULL NULL NULL utf8 utf8_bin char(80) PRI select,insert,update,references NEVER NULL
def mysql event body 3 NULL NO longblob 4294967295 4294967295 NULL NULL NULL NULL NULL longblob select,insert,update,references NEVER NULL
@@ -200,7 +201,7 @@ def mysql tables_priv Db 2 '' NO char 64 192 NULL NULL NULL utf8 utf8_bin char(6
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
@@ -220,16 +221,21 @@ def mysql time_zone_transition_type Is_DST 4 0 NO tinyint NULL NULL 3 0 NULL NUL
def mysql time_zone_transition_type Offset 3 0 NO int NULL NULL 10 0 NULL NULL NULL int(11) select,insert,update,references NEVER NULL
def mysql time_zone_transition_type Time_zone_id 1 NULL NO int NULL NULL 10 0 NULL NULL NULL int(10) unsigned PRI select,insert,update,references NEVER NULL
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 transaction_registry begin_timestamp 3 '0000-00-00 00:00:00.000000' NO timestamp NULL NULL NULL NULL 6 NULL NULL timestamp(6) MUL select,insert,update,references NEVER NULL
+def mysql transaction_registry commit_id 2 NULL NO bigint NULL NULL 20 0 NULL NULL NULL bigint(20) unsigned UNI select,insert,update,references NEVER NULL
+def mysql transaction_registry commit_timestamp 4 '0000-00-00 00:00:00.000000' NO timestamp NULL NULL NULL NULL 6 NULL NULL timestamp(6) MUL select,insert,update,references NEVER NULL
+def mysql transaction_registry isolation_level 5 NULL NO enum 16 48 NULL NULL NULL utf8 utf8_bin enum('READ-UNCOMMITTED','READ-COMMITTED','REPEATABLE-READ','SERIALIZABLE') select,insert,update,references NEVER NULL
+def mysql transaction_registry transaction_id 1 NULL NO bigint NULL NULL 20 0 NULL NULL NULL bigint(20) 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 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
@@ -239,16 +245,16 @@ def mysql user Grant_priv 14 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci
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
@@ -258,14 +264,15 @@ def mysql user Select_priv 4 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci
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 Truncate_versioning_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 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
##########################################################################
# Show the quotient of CHARACTER_OCTET_LENGTH and CHARACTER_MAXIMUM_LENGTH
##########################################################################
@@ -378,6 +385,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 Truncate_versioning_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
@@ -537,7 +545,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)
@@ -556,6 +564,11 @@ NULL mysql time_zone_transition_type Transition_type_id int NULL NULL NULL NULL
NULL mysql time_zone_transition_type Offset int NULL NULL NULL NULL int(11)
NULL mysql time_zone_transition_type Is_DST tinyint NULL NULL NULL NULL tinyint(3) unsigned
3.0000 mysql time_zone_transition_type Abbreviation char 8 24 utf8 utf8_general_ci char(8)
+NULL mysql transaction_registry transaction_id bigint NULL NULL NULL NULL bigint(20) unsigned
+NULL mysql transaction_registry commit_id bigint NULL NULL NULL NULL bigint(20) unsigned
+NULL mysql transaction_registry begin_timestamp timestamp NULL NULL NULL NULL timestamp(6)
+NULL mysql transaction_registry commit_timestamp timestamp NULL NULL NULL NULL timestamp(6)
+3.0000 mysql transaction_registry isolation_level enum 16 48 utf8 utf8_bin enum('READ-UNCOMMITTED','READ-COMMITTED','REPEATABLE-READ','SERIALIZABLE')
3.0000 mysql user Host char 60 180 utf8 utf8_bin char(60)
3.0000 mysql user User char 80 240 utf8 utf8_bin char(80)
1.0000 mysql user Password char 41 41 latin1 latin1_bin char(41)
@@ -588,6 +601,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 Truncate_versioning_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_columns_mysql_embedded.result b/mysql-test/suite/funcs_1/r/is_columns_mysql_embedded.result
index 2f1c9188989..f75513112e8 100644
--- a/mysql-test/suite/funcs_1/r/is_columns_mysql_embedded.result
+++ b/mysql-test/suite/funcs_1/r/is_columns_mysql_embedded.result
@@ -40,6 +40,7 @@ def mysql db References_priv 11 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general
def mysql db Select_priv 4 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
def mysql db Show_view_priv 17 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
def mysql db Trigger_priv 22 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
+def mysql db Truncate_versioning_priv 23 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
def mysql db Update_priv 6 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
def mysql db User 3 '' NO char 80 240 NULL NULL NULL utf8 utf8_bin char(80) PRI NEVER NULL
def mysql event body 3 NULL NO longblob 4294967295 4294967295 NULL NULL NULL NULL NULL longblob NEVER NULL
@@ -186,7 +187,7 @@ def mysql tables_priv Db 2 '' NO char 64 192 NULL NULL NULL utf8 utf8_bin char(6
def mysql tables_priv Grantor 5 '' NO char 141 423 NULL NULL NULL utf8 utf8_bin char(141) MUL NEVER NULL
def mysql tables_priv Host 1 '' NO char 60 180 NULL NULL NULL utf8 utf8_bin char(60) PRI NEVER NULL
def mysql tables_priv Table_name 4 '' NO char 64 192 NULL NULL NULL utf8 utf8_bin char(64) PRI 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') 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') NEVER NULL
def mysql tables_priv Timestamp 6 current_timestamp() NO timestamp NULL NULL NULL NULL 0 NULL NULL timestamp on update current_timestamp() NEVER NULL
def mysql tables_priv User 3 '' NO char 80 240 NULL NULL NULL utf8 utf8_bin char(80) PRI NEVER NULL
def mysql table_stats cardinality 3 NULL YES bigint NULL NULL 20 0 NULL NULL NULL bigint(21) unsigned NEVER NULL
@@ -208,14 +209,14 @@ 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 NEVER NULL
def mysql user Alter_priv 17 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
def mysql user Alter_routine_priv 28 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
-def mysql user authentication_string 42 NULL NO text 65535 65535 NULL NULL NULL utf8 utf8_bin text NEVER NULL
+def mysql user authentication_string 43 NULL NO text 65535 65535 NULL NULL NULL utf8 utf8_bin text NEVER NULL
def mysql user Create_priv 8 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
def mysql user Create_routine_priv 27 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
def mysql user Create_tablespace_priv 32 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') 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') NEVER NULL
def mysql user Create_user_priv 29 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
def mysql user Create_view_priv 25 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
-def mysql user default_role 45 '' NO char 80 240 NULL NULL NULL utf8 utf8_bin char(80) NEVER NULL
+def mysql user default_role 46 '' NO char 80 240 NULL NULL NULL utf8 utf8_bin char(80) NEVER NULL
def mysql user Delete_priv 7 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
def mysql user Drop_priv 9 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
def mysql user Event_priv 30 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
@@ -225,16 +226,16 @@ def mysql user Grant_priv 14 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci
def mysql user Host 1 '' NO char 60 180 NULL NULL NULL utf8 utf8_bin char(60) PRI NEVER NULL
def mysql user Index_priv 16 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
def mysql user Insert_priv 5 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
-def mysql user is_role 44 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
+def mysql user is_role 45 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
def mysql user Lock_tables_priv 21 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
-def mysql user max_connections 39 0 NO int NULL NULL 10 0 NULL NULL NULL int(11) unsigned NEVER NULL
-def mysql user max_questions 37 0 NO int NULL NULL 10 0 NULL NULL NULL int(11) unsigned NEVER NULL
-def mysql user max_statement_time 46 0.000000 NO decimal NULL NULL 12 6 NULL NULL NULL decimal(12,6) NEVER NULL
-def mysql user max_updates 38 0 NO int NULL NULL 10 0 NULL NULL NULL int(11) unsigned NEVER NULL
-def mysql user max_user_connections 40 0 NO int NULL NULL 10 0 NULL NULL NULL int(11) NEVER NULL
+def mysql user max_connections 40 0 NO int NULL NULL 10 0 NULL NULL NULL int(11) unsigned NEVER NULL
+def mysql user max_questions 38 0 NO int NULL NULL 10 0 NULL NULL NULL int(11) unsigned NEVER NULL
+def mysql user max_statement_time 47 0.000000 NO decimal NULL NULL 12 6 NULL NULL NULL decimal(12,6) NEVER NULL
+def mysql user max_updates 39 0 NO int NULL NULL 10 0 NULL NULL NULL int(11) unsigned NEVER NULL
+def mysql user max_user_connections 41 0 NO int NULL NULL 10 0 NULL NULL NULL int(11) NEVER NULL
def mysql user Password 3 '' NO char 41 41 NULL NULL NULL latin1 latin1_bin char(41) NEVER NULL
-def mysql user password_expired 43 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
-def mysql user plugin 41 '' NO char 64 64 NULL NULL NULL latin1 latin1_swedish_ci char(64) NEVER NULL
+def mysql user password_expired 44 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
+def mysql user plugin 42 '' NO char 64 64 NULL NULL NULL latin1 latin1_swedish_ci char(64) NEVER NULL
def mysql user Process_priv 12 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
def mysql user References_priv 15 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
def mysql user Reload_priv 10 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
@@ -244,17 +245,19 @@ def mysql user Select_priv 4 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci
def mysql user Show_db_priv 18 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
def mysql user Show_view_priv 26 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
def mysql user Shutdown_priv 11 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
-def mysql user ssl_cipher 34 NULL NO blob 65535 65535 NULL NULL NULL NULL NULL blob NEVER NULL
-def mysql user ssl_type 33 '' NO enum 9 27 NULL NULL NULL utf8 utf8_general_ci enum('','ANY','X509','SPECIFIED') NEVER NULL
+def mysql user ssl_cipher 35 NULL NO blob 65535 65535 NULL NULL NULL NULL NULL blob NEVER NULL
+def mysql user ssl_type 34 '' NO enum 9 27 NULL NULL NULL utf8 utf8_general_ci enum('','ANY','X509','SPECIFIED') NEVER NULL
def mysql user Super_priv 19 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
def mysql user Trigger_priv 31 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
+def mysql user Truncate_versioning_priv 33 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
def mysql user Update_priv 6 'N' NO enum 1 3 NULL NULL NULL utf8 utf8_general_ci enum('N','Y') NEVER NULL
def mysql user User 2 '' NO char 80 240 NULL NULL NULL utf8 utf8_bin char(80) PRI NEVER NULL
-def mysql user x509_issuer 35 NULL NO blob 65535 65535 NULL NULL NULL NULL NULL blob NEVER NULL
-def mysql user x509_subject 36 NULL NO blob 65535 65535 NULL NULL NULL NULL NULL blob NEVER NULL
+def mysql user x509_issuer 36 NULL NO blob 65535 65535 NULL NULL NULL NULL NULL blob NEVER NULL
+def mysql user x509_subject 37 NULL NO blob 65535 65535 NULL NULL NULL NULL NULL blob NEVER NULL
Warnings:
Warning 1286 Unknown storage engine 'InnoDB'
Warning 1286 Unknown storage engine 'InnoDB'
+Warning 1286 Unknown storage engine 'InnoDB'
##########################################################################
# Show the quotient of CHARACTER_OCTET_LENGTH and CHARACTER_MAXIMUM_LENGTH
##########################################################################
@@ -279,6 +282,7 @@ COL_CML DATA_TYPE CHARACTER_SET_NAME COLLATION_NAME
Warnings:
Warning 1286 Unknown storage engine 'InnoDB'
Warning 1286 Unknown storage engine 'InnoDB'
+Warning 1286 Unknown storage engine 'InnoDB'
SELECT DISTINCT
CHARACTER_OCTET_LENGTH / CHARACTER_MAXIMUM_LENGTH AS COL_CML,
DATA_TYPE,
@@ -299,6 +303,7 @@ COL_CML DATA_TYPE CHARACTER_SET_NAME COLLATION_NAME
Warnings:
Warning 1286 Unknown storage engine 'InnoDB'
Warning 1286 Unknown storage engine 'InnoDB'
+Warning 1286 Unknown storage engine 'InnoDB'
SELECT DISTINCT
CHARACTER_OCTET_LENGTH / CHARACTER_MAXIMUM_LENGTH AS COL_CML,
DATA_TYPE,
@@ -320,6 +325,7 @@ NULL tinyint NULL NULL
Warnings:
Warning 1286 Unknown storage engine 'InnoDB'
Warning 1286 Unknown storage engine 'InnoDB'
+Warning 1286 Unknown storage engine 'InnoDB'
--> CHAR(0) is allowed (see manual), and here both CHARACHTER_* values
--> are 0, which is intended behavior, and the result of 0 / 0 IS NULL
SELECT CHARACTER_OCTET_LENGTH / CHARACTER_MAXIMUM_LENGTH AS COL_CML,
@@ -376,6 +382,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 Truncate_versioning_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
@@ -521,7 +528,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)
@@ -572,6 +579,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 Truncate_versioning_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
@@ -589,3 +597,4 @@ NULL mysql user max_statement_time decimal NULL NULL NULL NULL decimal(12,6)
Warnings:
Warning 1286 Unknown storage engine 'InnoDB'
Warning 1286 Unknown storage engine 'InnoDB'
+Warning 1286 Unknown storage engine 'InnoDB'
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 933a8e537f2..5c126a48419 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
@@ -142,6 +142,8 @@ def mysql PRIMARY def mysql time_zone_transition Time_zone_id
def mysql PRIMARY def mysql time_zone_transition Transition_time
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 commit_id def mysql transaction_registry commit_id
+def mysql PRIMARY def mysql transaction_registry transaction_id
def mysql PRIMARY def mysql user Host
def mysql PRIMARY def mysql user User
########################################################################################
diff --git a/mysql-test/suite/funcs_1/r/is_key_column_usage_embedded.result b/mysql-test/suite/funcs_1/r/is_key_column_usage_embedded.result
index 62e566ca89f..d41f7395483 100644
--- a/mysql-test/suite/funcs_1/r/is_key_column_usage_embedded.result
+++ b/mysql-test/suite/funcs_1/r/is_key_column_usage_embedded.result
@@ -142,6 +142,8 @@ def mysql PRIMARY def mysql time_zone_transition Time_zone_id
def mysql PRIMARY def mysql time_zone_transition Transition_time
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 commit_id def mysql transaction_registry commit_id
+def mysql PRIMARY def mysql transaction_registry transaction_id
def mysql PRIMARY def mysql user Host
def mysql PRIMARY def mysql user User
########################################################################################
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_statistics.result b/mysql-test/suite/funcs_1/r/is_statistics.result
index a07d9d8d3c3..419eb0b4b4c 100644
--- a/mysql-test/suite/funcs_1/r/is_statistics.result
+++ b/mysql-test/suite/funcs_1/r/is_statistics.result
@@ -155,6 +155,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..31fb460f9aa 100644
--- a/mysql-test/suite/funcs_1/r/is_statistics_mysql.result
+++ b/mysql-test/suite/funcs_1/r/is_statistics_mysql.result
@@ -77,6 +77,11 @@ def mysql time_zone_transition 0 mysql PRIMARY 1 Time_zone_id A #CARD# NULL NULL
def mysql time_zone_transition 0 mysql PRIMARY 2 Transition_time A #CARD# NULL NULL BTREE
def mysql time_zone_transition_type 0 mysql PRIMARY 1 Time_zone_id A #CARD# NULL NULL BTREE
def mysql time_zone_transition_type 0 mysql PRIMARY 2 Transition_type_id A #CARD# NULL NULL BTREE
+def mysql transaction_registry 1 mysql begin_timestamp 1 begin_timestamp A #CARD# NULL NULL BTREE
+def mysql transaction_registry 0 mysql commit_id 1 commit_id A #CARD# NULL NULL BTREE
+def mysql transaction_registry 1 mysql commit_timestamp 1 commit_timestamp A #CARD# NULL NULL BTREE
+def mysql transaction_registry 1 mysql commit_timestamp 2 transaction_id A #CARD# NULL NULL BTREE
+def mysql transaction_registry 0 mysql PRIMARY 1 transaction_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
connect testuser1,localhost,testuser1,,db_datadict;
diff --git a/mysql-test/suite/funcs_1/r/is_statistics_mysql_embedded.result b/mysql-test/suite/funcs_1/r/is_statistics_mysql_embedded.result
index cbc9a8f17ce..c81052321f8 100644
--- a/mysql-test/suite/funcs_1/r/is_statistics_mysql_embedded.result
+++ b/mysql-test/suite/funcs_1/r/is_statistics_mysql_embedded.result
@@ -77,6 +77,11 @@ def mysql time_zone_transition 0 mysql PRIMARY 1 Time_zone_id A #CARD# NULL NULL
def mysql time_zone_transition 0 mysql PRIMARY 2 Transition_time A #CARD# NULL NULL BTREE
def mysql time_zone_transition_type 0 mysql PRIMARY 1 Time_zone_id A #CARD# NULL NULL BTREE
def mysql time_zone_transition_type 0 mysql PRIMARY 2 Transition_type_id A #CARD# NULL NULL BTREE
+def mysql transaction_registry 1 mysql begin_timestamp 1 begin_timestamp A #CARD# NULL NULL BTREE
+def mysql transaction_registry 0 mysql commit_id 1 commit_id A #CARD# NULL NULL BTREE
+def mysql transaction_registry 1 mysql commit_timestamp 1 commit_timestamp A #CARD# NULL NULL BTREE
+def mysql transaction_registry 1 mysql commit_timestamp 2 transaction_id A #CARD# NULL NULL BTREE
+def mysql transaction_registry 0 mysql PRIMARY 1 transaction_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
connect testuser1,localhost,testuser1,,db_datadict;
@@ -154,6 +159,11 @@ def mysql time_zone_transition 0 mysql PRIMARY 1 Time_zone_id A #CARD# NULL NULL
def mysql time_zone_transition 0 mysql PRIMARY 2 Transition_time A #CARD# NULL NULL BTREE
def mysql time_zone_transition_type 0 mysql PRIMARY 1 Time_zone_id A #CARD# NULL NULL BTREE
def mysql time_zone_transition_type 0 mysql PRIMARY 2 Transition_type_id A #CARD# NULL NULL BTREE
+def mysql transaction_registry 1 mysql begin_timestamp 1 begin_timestamp A #CARD# NULL NULL BTREE
+def mysql transaction_registry 0 mysql commit_id 1 commit_id A #CARD# NULL NULL BTREE
+def mysql transaction_registry 1 mysql commit_timestamp 1 commit_timestamp A #CARD# NULL NULL BTREE
+def mysql transaction_registry 1 mysql commit_timestamp 2 transaction_id A #CARD# NULL NULL BTREE
+def mysql transaction_registry 0 mysql PRIMARY 1 transaction_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
connection default;
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 2f3afaaa0ad..d968d3b65de 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,8 @@ def mysql PRIMARY mysql time_zone_leap_second
def mysql PRIMARY mysql time_zone_name
def mysql PRIMARY mysql time_zone_transition
def mysql PRIMARY mysql time_zone_transition_type
+def mysql commit_id mysql transaction_registry
+def mysql PRIMARY mysql transaction_registry
def mysql PRIMARY mysql user
#########################################################################################
# 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..b56c5115f16 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
@@ -37,6 +37,8 @@ def mysql PRIMARY mysql time_zone_leap_second PRIMARY KEY
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 commit_id mysql transaction_registry UNIQUE
+def mysql PRIMARY mysql transaction_registry PRIMARY KEY
def mysql PRIMARY mysql user PRIMARY KEY
connect testuser1,localhost,testuser1,,db_datadict;
SELECT * FROM information_schema.table_constraints
diff --git a/mysql-test/suite/funcs_1/r/is_table_constraints_mysql_embedded.result b/mysql-test/suite/funcs_1/r/is_table_constraints_mysql_embedded.result
index 58a2373b66d..b40bc0ea0c7 100644
--- a/mysql-test/suite/funcs_1/r/is_table_constraints_mysql_embedded.result
+++ b/mysql-test/suite/funcs_1/r/is_table_constraints_mysql_embedded.result
@@ -37,6 +37,8 @@ def mysql PRIMARY mysql time_zone_leap_second PRIMARY KEY
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 commit_id mysql transaction_registry UNIQUE
+def mysql PRIMARY mysql transaction_registry PRIMARY KEY
def mysql PRIMARY mysql user PRIMARY KEY
connect testuser1,localhost,testuser1,,db_datadict;
SELECT * FROM information_schema.table_constraints
@@ -73,6 +75,8 @@ def mysql PRIMARY mysql time_zone_leap_second PRIMARY KEY
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 commit_id mysql transaction_registry UNIQUE
+def mysql PRIMARY mysql transaction_registry PRIMARY KEY
def mysql PRIMARY mysql user PRIMARY KEY
connection default;
disconnect testuser1;
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_tables_mysql.result b/mysql-test/suite/funcs_1/r/is_tables_mysql.result
index 8e0c9b64dab..721ac70026f 100644
--- a/mysql-test/suite/funcs_1/r/is_tables_mysql.result
+++ b/mysql-test/suite/funcs_1/r/is_tables_mysql.result
@@ -679,6 +679,29 @@ user_comment Time zone transition types
Separator -----------------------------------------------------
TABLE_CATALOG def
TABLE_SCHEMA mysql
+TABLE_NAME transaction_registry
+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 -----------------------------------------------------
+TABLE_CATALOG def
+TABLE_SCHEMA mysql
TABLE_NAME user
TABLE_TYPE BASE TABLE
ENGINE MYISAM_OR_MARIA
diff --git a/mysql-test/suite/funcs_1/r/is_tables_mysql_embedded.result b/mysql-test/suite/funcs_1/r/is_tables_mysql_embedded.result
index f40294491cc..c21bdf43de4 100644
--- a/mysql-test/suite/funcs_1/r/is_tables_mysql_embedded.result
+++ b/mysql-test/suite/funcs_1/r/is_tables_mysql_embedded.result
@@ -679,6 +679,29 @@ user_comment Time zone transition types
Separator -----------------------------------------------------
TABLE_CATALOG def
TABLE_SCHEMA mysql
+TABLE_NAME transaction_registry
+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 -----------------------------------------------------
+TABLE_CATALOG def
+TABLE_SCHEMA mysql
TABLE_NAME user
TABLE_TYPE BASE TABLE
ENGINE MYISAM_OR_MARIA
@@ -1383,6 +1406,29 @@ user_comment Time zone transition types
Separator -----------------------------------------------------
TABLE_CATALOG def
TABLE_SCHEMA mysql
+TABLE_NAME transaction_registry
+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 -----------------------------------------------------
+TABLE_CATALOG def
+TABLE_SCHEMA mysql
TABLE_NAME user
TABLE_TYPE BASE TABLE
ENGINE MYISAM_OR_MARIA
diff --git a/mysql-test/suite/funcs_1/r/is_triggers.result b/mysql-test/suite/funcs_1/r/is_triggers.result
index 347bf02238a..1ea7263eb8f 100644
--- a/mysql-test/suite/funcs_1/r/is_triggers.result
+++ b/mysql-test/suite/funcs_1/r/is_triggers.result
@@ -145,7 +145,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..1582ec6dc96 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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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
+Truncate_versioning_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/memory_views.result b/mysql-test/suite/funcs_1/r/memory_views.result
index de0acb3a9f3..e5179716c69 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_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/funcs_1/r/myisam_views-big.result b/mysql-test/suite/funcs_1/r/myisam_views-big.result
index 2a547ddf256..9cceccfd10f 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 dc9c31566d2..e5e009a86de 100644
--- a/mysql-test/suite/funcs_1/r/storedproc.result
+++ b/mysql-test/suite/funcs_1/r/storedproc.result
@@ -2775,7 +2775,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 values()
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 'values()
SELECT * from t1 where f2=f1' at line 1
CREATE PROCEDURE varbinary()
SELECT * from t1 where f2=f1;
@@ -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;
@@ -9150,7 +9150,7 @@ CREATE PROCEDURE sp1()
BEGIN
declare values 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 'values char;
END' at line 3
DROP PROCEDURE IF EXISTS sp1;
Warnings:
@@ -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:
@@ -11494,9 +11494,8 @@ BEGIN
declare values condition for sqlstate '02000';
declare exit handler for values 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 values set @var2 = 1;
-E' 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 'values condition for sqlstate '02000';
+declare exit handler for values set @var2' at line 3
DROP PROCEDURE IF EXISTS sp1;
Warnings:
Note 1305 PROCEDURE db_storedproc.sp1 does not exist
@@ -11575,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
@@ -13609,7 +13607,7 @@ CREATE PROCEDURE sp1( )
BEGIN
declare values 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 'values handler for sqlstate '02000' set @var2 = 1;
END' at line 3
DROP PROCEDURE IF EXISTS sp1;
Warnings:
@@ -13681,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/r/innodb-index-online-fk.result b/mysql-test/suite/innodb/r/innodb-index-online-fk.result
index 359ce4a717c..38930c0c07e 100644
--- a/mysql-test/suite/innodb/r/innodb-index-online-fk.result
+++ b/mysql-test/suite/innodb/r/innodb-index-online-fk.result
@@ -126,6 +126,7 @@ SYS_TABLESPACES
SYS_VIRTUAL
mysql/innodb_index_stats
mysql/innodb_table_stats
+mysql/transaction_registry
test/child
test/parent
INSERT INTO child VALUES(5,4);
@@ -317,6 +318,7 @@ SYS_TABLESPACES
SYS_VIRTUAL
mysql/innodb_index_stats
mysql/innodb_table_stats
+mysql/transaction_registry
test/child
test/parent
ALTER TABLE child ADD PRIMARY KEY idx (a3), CHANGE a1 a3 INT,
@@ -342,6 +344,7 @@ SYS_TABLESPACES
SYS_VIRTUAL
mysql/innodb_index_stats
mysql/innodb_table_stats
+mysql/transaction_registry
test/child
test/parent
SHOW CREATE TABLE child;
@@ -378,6 +381,7 @@ SYS_TABLESPACES
SYS_VIRTUAL
mysql/innodb_index_stats
mysql/innodb_table_stats
+mysql/transaction_registry
test/child
test/parent
SHOW CREATE TABLE child;
@@ -414,6 +418,7 @@ SYS_TABLESPACES
SYS_VIRTUAL
mysql/innodb_index_stats
mysql/innodb_table_stats
+mysql/transaction_registry
test/child
test/parent
SHOW CREATE TABLE child;
diff --git a/mysql-test/suite/innodb/r/instant_alter_debug.result b/mysql-test/suite/innodb/r/instant_alter_debug.result
index 99a263ae95f..ebc76b31f8b 100644
--- a/mysql-test/suite/innodb/r/instant_alter_debug.result
+++ b/mysql-test/suite/innodb/r/instant_alter_debug.result
@@ -35,7 +35,7 @@ ALTER TABLE t4 ADD COLUMN b INT;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
LEFT JOIN t4 ON (NUMERIC_SCALE = pk);
COUNT(*)
-1735
+1742
SET DEBUG_SYNC='innodb_inplace_alter_table_enter SIGNAL enter WAIT_FOR delete';
ALTER TABLE t4 ADD COLUMN c INT;
connect dml,localhost,root,,;
diff --git a/mysql-test/suite/innodb/r/row_format_redundant.result b/mysql-test/suite/innodb/r/row_format_redundant.result
index a2d5bbef8df..6deecd10ada 100644
--- a/mysql-test/suite/innodb/r/row_format_redundant.result
+++ b/mysql-test/suite/innodb/r/row_format_redundant.result
@@ -72,7 +72,7 @@ DROP TABLE t1;
Warnings:
Warning 1932 Table 'test.t1' doesn't exist in engine
DROP TABLE t2,t3;
-FOUND 49 /\[ERROR\] InnoDB: Table `test`\.`t1` in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=1 SYS_TABLES\.MIX_LEN=255\b/ in mysqld.1.err
+FOUND 49 /\[ERROR\] InnoDB: Table `test`\.`t1` in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=1 SYS_TABLES\.MIX_LEN=511\b/ in mysqld.1.err
ib_buffer_pool
ib_logfile0
ib_logfile1
diff --git a/mysql-test/suite/innodb/t/ibuf_not_empty.test b/mysql-test/suite/innodb/t/ibuf_not_empty.test
index a1a2da1f903..5adbfb72550 100644
--- a/mysql-test/suite/innodb/t/ibuf_not_empty.test
+++ b/mysql-test/suite/innodb/t/ibuf_not_empty.test
@@ -9,6 +9,8 @@
--disable_query_log
call mtr.add_suppression("InnoDB: Failed to find tablespace for table `test`\\.`t1` in the cache\\. Attempting to load the tablespace with space id");
call mtr.add_suppression("InnoDB: Allocated tablespace ID \\d+ for test.t1, old maximum was");
+call mtr.add_suppression("InnoDB: Failed to find tablespace for table `mysql`\\.`transaction_registry` in the cache\\. Attempting to load the tablespace with space id");
+call mtr.add_suppression("InnoDB: Allocated tablespace ID \\d+ for mysql.transaction_registry, old maximum was");
--enable_query_log
CREATE TABLE t1(
diff --git a/mysql-test/suite/innodb/t/innodb_force_recovery.test b/mysql-test/suite/innodb/t/innodb_force_recovery.test
index f9af16f6609..9dae9f8e7c9 100644
--- a/mysql-test/suite/innodb/t/innodb_force_recovery.test
+++ b/mysql-test/suite/innodb/t/innodb_force_recovery.test
@@ -7,6 +7,7 @@
--disable_query_log
call mtr.add_suppression("InnoDB: Failed to find tablespace for table .* in the cache. Attempting to load the tablespace with space id");
call mtr.add_suppression("InnoDB: Allocated tablespace ID \\d+ for test.t[12], old maximum was");
+call mtr.add_suppression("InnoDB: Allocated tablespace ID \\d+ for mysql.transaction_registry, old maximum was");
--enable_query_log
create table t1(f1 int not null, f2 int not null, index idx(f2))engine=innodb;
diff --git a/mysql-test/suite/innodb/t/log_corruption.test b/mysql-test/suite/innodb/t/log_corruption.test
index 0d699cebb8f..20763d26bdc 100644
--- a/mysql-test/suite/innodb/t/log_corruption.test
+++ b/mysql-test/suite/innodb/t/log_corruption.test
@@ -16,6 +16,7 @@ call mtr.add_suppression("InnoDB: Log scan aborted at LSN");
call mtr.add_suppression("InnoDB: Missing MLOG_FILE_NAME or MLOG_FILE_DELETE before MLOG_CHECKPOINT for tablespace 42\\r?$");
call mtr.add_suppression("InnoDB: Obtaining redo log encryption key version 1 failed");
call mtr.add_suppression("InnoDB: Decrypting checkpoint failed");
+call mtr.add_suppression("`mysql\\.transaction_registry` does not exist");
--enable_query_log
let bugdir= $MYSQLTEST_VARDIR/tmp/log_corruption;
diff --git a/mysql-test/suite/innodb/t/row_format_redundant.test b/mysql-test/suite/innodb/t/row_format_redundant.test
index af3fe3b52cf..81541fb0582 100644
--- a/mysql-test/suite/innodb/t/row_format_redundant.test
+++ b/mysql-test/suite/innodb/t/row_format_redundant.test
@@ -4,7 +4,7 @@
--disable_query_log
call mtr.add_suppression("InnoDB: Table `mysql`\\.`innodb_table_stats` not found");
-call mtr.add_suppression("InnoDB: Table `test`.`t1` in InnoDB data dictionary contains invalid flags. SYS_TABLES\\.TYPE=1 SYS_TABLES\\.MIX_LEN=255\\r?$");
+call mtr.add_suppression("InnoDB: Table `test`.`t1` in InnoDB data dictionary contains invalid flags. SYS_TABLES\\.TYPE=1 SYS_TABLES\\.MIX_LEN=511\\r?$");
call mtr.add_suppression("InnoDB: Parent table of FTS auxiliary table test/FTS_.* not found");
call mtr.add_suppression("InnoDB: Cannot open table test/t1 from the internal data dictionary");
call mtr.add_suppression("InnoDB: Table `test`.`t1` does not exist in the InnoDB internal data dictionary though MariaDB is trying to (rename|drop)");
@@ -115,7 +115,7 @@ for (my $offset= 0x65; $offset;
if ($i == 7 && $name =~ '^test/t[123]')
{
print "corrupted SYS_TABLES.MIX_LEN for $name\n";
- substr($page,$offset+$start,$end-$start)= pack("N", 255);
+ substr($page,$offset+$start,$end-$start)= pack("N", 511);
}
$start= $end & 0x7f;
}
@@ -141,7 +141,7 @@ RENAME TABLE t1 TO tee_one;
DROP TABLE t1;
DROP TABLE t2,t3;
---let SEARCH_PATTERN= \[ERROR\] InnoDB: Table `test`\.`t1` in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=1 SYS_TABLES\.MIX_LEN=255\b
+--let SEARCH_PATTERN= \[ERROR\] InnoDB: Table `test`\.`t1` in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=1 SYS_TABLES\.MIX_LEN=511\b
--source include/search_pattern_in_file.inc
--let $restart_parameters=
diff --git a/mysql-test/suite/innodb_fts/r/fulltext.result b/mysql-test/suite/innodb_fts/r/fulltext.result
index 42e294b3293..fcf196a0631 100644
--- a/mysql-test/suite/innodb_fts/r/fulltext.result
+++ b/mysql-test/suite/innodb_fts/r/fulltext.result
@@ -56,7 +56,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/innodb_zip/r/16k.result b/mysql-test/suite/innodb_zip/r/16k.result
index c1efeea329b..e7def759e87 100644
--- a/mysql-test/suite/innodb_zip/r/16k.result
+++ b/mysql-test/suite/innodb_zip/r/16k.result
@@ -18,6 +18,10 @@ AND t.name LIKE 'mysql%'
table_name n_cols table_flags index_name root_page type n_fields merge_threshold
mysql/innodb_index_stats 11 33 PRIMARY 3 3 4 50
mysql/innodb_table_stats 9 33 PRIMARY 3 3 2 50
+mysql/transaction_registry 8 33 PRIMARY 3 3 1 50
+mysql/transaction_registry 8 33 commit_id 4 2 1 50
+mysql/transaction_registry 8 33 begin_timestamp 5 0 1 50
+mysql/transaction_registry 8 33 commit_timestamp 6 0 2 50
CREATE TABLE t1 (a INT KEY, b TEXT) ROW_FORMAT=REDUNDANT ENGINE=innodb;
CREATE TABLE t2 (a INT KEY, b TEXT) ROW_FORMAT=COMPACT ENGINE=innodb;
CREATE TABLE t3 (a INT KEY, b TEXT) ROW_FORMAT=COMPRESSED ENGINE=innodb;
diff --git a/mysql-test/suite/mariabackup/system_versioning.result b/mysql-test/suite/mariabackup/system_versioning.result
new file mode 100644
index 00000000000..3b3cd8f938c
--- /dev/null
+++ b/mysql-test/suite/mariabackup/system_versioning.result
@@ -0,0 +1,53 @@
+create table t (a int) with system versioning;
+insert into t values (1);
+update t set a=2;
+insert into t values (3);
+# shutdown server
+# remove datadir
+# xtrabackup move back
+# restart server
+show create table t;
+Table Create Table
+t CREATE TABLE `t` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=INNODB_OR_MYISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+select * from t;
+a
+2
+select a from t for system_time all;
+a
+2
+1
+set global system_versioning_transaction_registry=on;
+Warnings:
+Warning 4143 Transaction-based system versioning is EXPERIMENTAL and is subject to change in future.
+create or replace table t (
+a int,
+s bigint unsigned as row start invisible,
+e bigint unsigned as row end invisible,
+period for system_time(s, e)
+) with system versioning engine=innodb;
+insert into t values (1);
+update t set a=2;
+insert into t values (3);
+# shutdown server
+# remove datadir
+# xtrabackup move back
+# restart server
+show create table t;
+Table Create Table
+t CREATE TABLE `t` (
+ `a` int(11) DEFAULT NULL,
+ `s` bigint(20) unsigned GENERATED ALWAYS AS ROW START INVISIBLE,
+ `e` bigint(20) unsigned GENERATED ALWAYS AS ROW END INVISIBLE,
+ PERIOD FOR SYSTEM_TIME (`s`, `e`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+select * from t;
+a
+2
+select a from t for system_time all;
+a
+2
+1
+drop table t;
+set global system_versioning_transaction_registry=off;
diff --git a/mysql-test/suite/mariabackup/system_versioning.test b/mysql-test/suite/mariabackup/system_versioning.test
new file mode 100644
index 00000000000..99392c3fc5b
--- /dev/null
+++ b/mysql-test/suite/mariabackup/system_versioning.test
@@ -0,0 +1,52 @@
+create table t (a int) with system versioning;
+insert into t values (1);
+update t set a=2;
+
+let $targetdir=$MYSQLTEST_VARDIR/tmp/backup;
+
+--disable_result_log
+exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir;
+--enable_result_log
+
+insert into t values (3);
+
+--disable_result_log
+exec $XTRABACKUP --prepare --target-dir=$targetdir;
+-- source include/restart_and_restore.inc
+--enable_result_log
+
+--replace_result InnoDB INNODB_OR_MYISAM MyISAM INNODB_OR_MYISAM
+show create table t;
+select * from t;
+select a from t for system_time all;
+
+rmdir $targetdir;
+
+set global system_versioning_transaction_registry=on;
+create or replace table t (
+ a int,
+ s bigint unsigned as row start invisible,
+ e bigint unsigned as row end invisible,
+ period for system_time(s, e)
+) with system versioning engine=innodb;
+insert into t values (1);
+update t set a=2;
+
+--disable_result_log
+exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir;
+--enable_result_log
+
+insert into t values (3);
+
+--disable_result_log
+exec $XTRABACKUP --prepare --target-dir=$targetdir;
+-- source include/restart_and_restore.inc
+--enable_result_log
+
+show create table t;
+select * from t;
+select a from t for system_time all;
+
+drop table t;
+set global system_versioning_transaction_registry=off;
+rmdir $targetdir;
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..4024d683980 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 Truncate_versioning_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 Truncate_versioning_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..a63193a8028 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 Truncate_versioning_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/sys_vars/r/sysvars_server_embedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result
index d087df07278..c8073332276 100644
--- a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result
+++ b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result
@@ -4058,6 +4058,62 @@ NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
+VARIABLE_NAME SYSTEM_VERSIONING_ALTER_HISTORY
+SESSION_VALUE ERROR
+GLOBAL_VALUE ERROR
+GLOBAL_VALUE_ORIGIN COMPILE-TIME
+DEFAULT_VALUE ERROR
+VARIABLE_SCOPE SESSION
+VARIABLE_TYPE ENUM
+VARIABLE_COMMENT Versioning ALTER TABLE mode. ERROR: Fail ALTER with error; KEEP: Keep historical system rows and subject them to ALTER;
+NUMERIC_MIN_VALUE NULL
+NUMERIC_MAX_VALUE NULL
+NUMERIC_BLOCK_SIZE NULL
+ENUM_VALUE_LIST ERROR,KEEP
+READ_ONLY NO
+COMMAND_LINE_ARGUMENT REQUIRED
+VARIABLE_NAME SYSTEM_VERSIONING_ASOF
+SESSION_VALUE DEFAULT
+GLOBAL_VALUE DEFAULT
+GLOBAL_VALUE_ORIGIN COMPILE-TIME
+DEFAULT_VALUE DEFAULT
+VARIABLE_SCOPE SESSION
+VARIABLE_TYPE VARCHAR
+VARIABLE_COMMENT Default value for the FOR SYSTEM_TIME AS OF clause
+NUMERIC_MIN_VALUE NULL
+NUMERIC_MAX_VALUE NULL
+NUMERIC_BLOCK_SIZE NULL
+ENUM_VALUE_LIST DEFAULT
+READ_ONLY NO
+COMMAND_LINE_ARGUMENT NULL
+VARIABLE_NAME SYSTEM_VERSIONING_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 SYSTEM_VERSIONING_TRANSACTION_REGISTRY
+SESSION_VALUE NULL
+GLOBAL_VALUE OFF
+GLOBAL_VALUE_ORIGIN COMPILE-TIME
+DEFAULT_VALUE OFF
+VARIABLE_SCOPE GLOBAL
+VARIABLE_TYPE BOOLEAN
+VARIABLE_COMMENT Enable or disable update of `mysql`.`transaction_registry`
+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 TABLE_DEFINITION_CACHE
SESSION_VALUE NULL
GLOBAL_VALUE 400
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 8b1ce78f960..0ebf5d71f4e 100644
--- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
+++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
@@ -5010,6 +5010,62 @@ NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
+VARIABLE_NAME SYSTEM_VERSIONING_ALTER_HISTORY
+SESSION_VALUE ERROR
+GLOBAL_VALUE ERROR
+GLOBAL_VALUE_ORIGIN COMPILE-TIME
+DEFAULT_VALUE ERROR
+VARIABLE_SCOPE SESSION
+VARIABLE_TYPE ENUM
+VARIABLE_COMMENT Versioning ALTER TABLE mode. ERROR: Fail ALTER with error; KEEP: Keep historical system rows and subject them to ALTER;
+NUMERIC_MIN_VALUE NULL
+NUMERIC_MAX_VALUE NULL
+NUMERIC_BLOCK_SIZE NULL
+ENUM_VALUE_LIST ERROR,KEEP
+READ_ONLY NO
+COMMAND_LINE_ARGUMENT REQUIRED
+VARIABLE_NAME SYSTEM_VERSIONING_ASOF
+SESSION_VALUE DEFAULT
+GLOBAL_VALUE DEFAULT
+GLOBAL_VALUE_ORIGIN COMPILE-TIME
+DEFAULT_VALUE DEFAULT
+VARIABLE_SCOPE SESSION
+VARIABLE_TYPE VARCHAR
+VARIABLE_COMMENT Default value for the FOR SYSTEM_TIME AS OF clause
+NUMERIC_MIN_VALUE NULL
+NUMERIC_MAX_VALUE NULL
+NUMERIC_BLOCK_SIZE NULL
+ENUM_VALUE_LIST DEFAULT
+READ_ONLY NO
+COMMAND_LINE_ARGUMENT NULL
+VARIABLE_NAME SYSTEM_VERSIONING_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 SYSTEM_VERSIONING_TRANSACTION_REGISTRY
+SESSION_VALUE NULL
+GLOBAL_VALUE OFF
+GLOBAL_VALUE_ORIGIN COMPILE-TIME
+DEFAULT_VALUE OFF
+VARIABLE_SCOPE GLOBAL
+VARIABLE_TYPE BOOLEAN
+VARIABLE_COMMENT Enable or disable update of `mysql`.`transaction_registry`
+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 TABLE_DEFINITION_CACHE
SESSION_VALUE NULL
GLOBAL_VALUE 400
diff --git a/mysql-test/suite/versioning/common.inc b/mysql-test/suite/versioning/common.inc
new file mode 100644
index 00000000000..cbc515241b0
--- /dev/null
+++ b/mysql-test/suite/versioning/common.inc
@@ -0,0 +1,127 @@
+--disable_query_log
+source include/have_innodb.inc;
+
+set @@session.time_zone='+00:00';
+select ifnull(max(transaction_id), 0) into @start_trx_id from mysql.transaction_registry;
+set @test_start=now(6);
+
+delimiter ~~;
+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 > @test_start as C,
+ commit_timestamp >= begin_timestamp as D
+ from mysql.transaction_registry
+ where transaction_id > @start_trx_id;
+ select ifnull(max(transaction_id), 0)
+ into @start_trx_id
+ from mysql.transaction_registry;
+end~~
+
+create function if not exists default_engine()
+returns varchar(255)
+deterministic
+begin
+ declare e varchar(255);
+ select engine from information_schema.engines where support='DEFAULT' into e;
+ return e;
+end~~
+
+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 function if not exists sys_datatype(engine varchar(255))
+returns varchar(255)
+deterministic
+begin
+ if engine = 'InnoDB' then
+ return 'bigint(20) unsigned';
+ elseif engine = 'MyISAM' then
+ return 'timestamp(6)';
+ end if;
+ return NULL;
+end~~
+
+create function if not exists current_row(sys_trx_end varbinary(255))
+returns int
+deterministic
+begin
+ declare continue handler for sqlwarning begin end;
+ return sys_trx_end = timestamp'2038-01-19 03:14:07.999999'
+ or sys_trx_end = 18446744073709551615;
+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 verify_vtq_dummy(recs int)
+begin
+ declare i int default 1;
+ 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~~
+
+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()`;
+let $non_default_engine= `select non_default_engine()`;
+let $sys_datatype= timestamp(6);
+let $sys_datatype_expl= timestamp(6);
+let $sys_datatype_uc= TIMESTAMP(6);
+let $sys_datatype_expl_uc= TIMESTAMP(6);
+
+let $non_sys_datatype= `select sys_datatype(non_default_engine())`;
+let $non_sys_datatype_uc= `select upper(sys_datatype(non_default_engine()))`;
+let $sys_datatype_null= $sys_datatype NULL DEFAULT NULL;
+let $sys_datatype_default_null= $sys_datatype DEFAULT NULL;
+let $sys_datatype_not_null= $sys_datatype NOT NULL DEFAULT '0000-00-00 00:00:00.000000';
+let $non_sys_datatype_null= $non_sys_datatype NULL;
+
+if ($MTR_COMBINATION_MYISAM)
+{
+ --let $MTR_COMBINATION_TIMESTAMP= 1
+}
+if ($MTR_COMBINATION_TRX_ID)
+{
+ let $sys_datatype_expl= bigint(20) unsigned;
+ let $sys_datatype_expl_uc= BIGINT(20) UNSIGNED;
+}
+--enable_query_log
diff --git a/mysql-test/suite/versioning/common.opt b/mysql-test/suite/versioning/common.opt
new file mode 100644
index 00000000000..391f1a5cba9
--- /dev/null
+++ b/mysql-test/suite/versioning/common.opt
@@ -0,0 +1,2 @@
+--system-versioning-transaction-registry=1
+--plugin-load-add=test_versioning
diff --git a/mysql-test/suite/versioning/common_finish.inc b/mysql-test/suite/versioning/common_finish.inc
new file mode 100644
index 00000000000..1059bb1251d
--- /dev/null
+++ b/mysql-test/suite/versioning/common_finish.inc
@@ -0,0 +1,11 @@
+--disable_query_log
+drop procedure verify_vtq;
+drop procedure verify_vtq_dummy;
+drop function default_engine;
+drop function non_default_engine;
+drop function sys_commit_ts;
+drop function sys_datatype;
+drop function current_row;
+drop procedure concat_exec2;
+drop procedure concat_exec3;
+--enable_query_log
diff --git a/mysql-test/suite/handler/disabled.def b/mysql-test/suite/versioning/disabled.def
index 888298bbb09..e0f1483d0ef 100644
--- a/mysql-test/suite/handler/disabled.def
+++ b/mysql-test/suite/versioning/disabled.def
@@ -9,3 +9,7 @@
# Do not use any TAB characters for whitespace.
#
##############################################################################
+ddl : DDL Survival WIP
+vtmd : DDL Survival WIP
+vtmd_show : DDL Survival WIP
+cte: MDEV-14820
diff --git a/mysql-test/suite/versioning/engines.combinations b/mysql-test/suite/versioning/engines.combinations
new file mode 100644
index 00000000000..561c5656929
--- /dev/null
+++ b/mysql-test/suite/versioning/engines.combinations
@@ -0,0 +1,8 @@
+[timestamp]
+default-storage-engine=innodb
+
+[trx_id]
+default-storage-engine=innodb
+
+[myisam]
+default-storage-engine=myisam
diff --git a/mysql-test/suite/versioning/engines.inc b/mysql-test/suite/versioning/engines.inc
new file mode 100644
index 00000000000..c841fece702
--- /dev/null
+++ b/mysql-test/suite/versioning/engines.inc
@@ -0,0 +1 @@
+--source include/have_innodb.inc
diff --git a/mysql-test/suite/versioning/key_type.combinations b/mysql-test/suite/versioning/key_type.combinations
new file mode 100644
index 00000000000..1929aee9a84
--- /dev/null
+++ b/mysql-test/suite/versioning/key_type.combinations
@@ -0,0 +1,2 @@
+[unique]
+[pk]
diff --git a/mysql-test/suite/versioning/key_type.inc b/mysql-test/suite/versioning/key_type.inc
new file mode 100644
index 00000000000..648430771cf
--- /dev/null
+++ b/mysql-test/suite/versioning/key_type.inc
@@ -0,0 +1,23 @@
+--disable_query_log
+if ($MTR_COMBINATION_UNIQUE)
+{
+ set @KEY_TYPE= 'unique';
+}
+if ($MTR_COMBINATION_PK)
+{
+ set @KEY_TYPE= 'primary key';
+}
+
+delimiter ~~;
+create procedure create_table(name varchar(255), cols varchar(255))
+begin
+ if (cols is null or cols = '') then
+ set cols= '';
+ else
+ set cols= concat(', ', cols);
+ end if;
+ set @str= concat('create or replace table ', name, '(id int ', @KEY_TYPE, cols, ') with system versioning');
+ prepare stmt from @str; execute stmt; drop prepare stmt;
+end~~
+delimiter ;~~
+--enable_query_log
diff --git a/mysql-test/suite/versioning/r/alter.result b/mysql-test/suite/versioning/r/alter.result
new file mode 100644
index 00000000000..c9a0c81956c
--- /dev/null
+++ b/mysql-test/suite/versioning/r/alter.result
@@ -0,0 +1,469 @@
+select @@system_versioning_alter_history;
+@@system_versioning_alter_history
+ERROR
+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 drop system versioning;
+ERROR HY000: Table `t` is not system-versioned
+alter table t add system versioning;
+show create table t;
+Table Create Table
+t CREATE TABLE `t` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+alter table t add column y int;
+ERROR HY000: Not allowed for system-versioned `test`.`t`. Change @@system_versioning_alter_history to proceed with ALTER.
+alter table t engine innodb;
+ERROR HY000: Not allowed for system-versioned `test`.`t`. Change to/from native system versioning engine is prohibited.
+alter table t drop system versioning;
+show create table t;
+Table Create Table
+t CREATE TABLE `t` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+set system_versioning_alter_history= keep;
+alter table t
+add column trx_start bigint(20) unsigned as row start invisible,
+add column trx_end bigint(20) unsigned as row end invisible,
+add period for system_time(trx_start, trx_end),
+add system versioning;
+ERROR HY000: `trx_start` must be of type TIMESTAMP(6) for system-versioned table `t`
+alter table t
+add column trx_start timestamp as row start invisible,
+add column trx_end timestamp as row end invisible,
+add period for system_time(trx_start, trx_end),
+add system versioning;
+ERROR HY000: `trx_start` must be of type TIMESTAMP(6) for system-versioned table `t`
+alter table t
+add column trx_start timestamp(6) not null as row start invisible,
+add column trx_end timestamp(6) not null as row end invisible,
+add period for system_time(trx_start, trx_end),
+add 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 'as row start invisible,
+add column trx_end timestamp(6) not null as row end invi' at line 2
+alter table t
+add column trx_start timestamp(6) as row start invisible,
+add column trx_end timestamp(6) as row end invisible,
+add period for system_time(trx_start, trx_end),
+add system versioning;
+show create table t;
+Table Create Table
+t CREATE TABLE `t` (
+ `a` int(11) DEFAULT NULL,
+ `trx_start` timestamp(6) GENERATED ALWAYS AS ROW START INVISIBLE,
+ `trx_end` timestamp(6) GENERATED ALWAYS AS ROW END INVISIBLE,
+ 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 drop 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 system versioning;
+show create table t;
+Table Create Table
+t CREATE TABLE `t` (
+ `a` int(11) DEFAULT NULL
+) 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
+) 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
+) 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
+) 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
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+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
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+create or replace table t (
+a int,
+row_start timestamp(6) as row start invisible,
+row_end timestamp(6) as row end invisible,
+period for system_time(row_start, row_end))
+with system versioning;
+select * from t for system_time all;
+a
+alter table t drop column row_start;
+alter table t drop column row_end;
+select * from t for system_time all;
+a
+alter table t drop column row_start;
+ERROR 42000: Can't DROP COLUMN `row_start`; check that it exists
+alter table t drop column row_end;
+ERROR 42000: Can't DROP COLUMN `row_end`; check that it exists
+create or replace table t (
+a int,
+row_start timestamp(6) as row start invisible,
+row_end timestamp(6) as row end invisible,
+period for system_time(row_start, row_end))
+with system versioning;
+select * from t for system_time all;
+a
+alter table t drop column row_start, drop column row_end;
+select * from t for system_time all;
+a
+create or replace table t(
+a int
+);
+insert into t values(1);
+alter table t add system versioning;
+show create table t;
+Table Create Table
+t CREATE TABLE `t` (
+ `a` int(11) DEFAULT NULL
+) 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 row_start from t where a=3 into @tm;
+alter table t add column b int;
+select @tm=row_start from t where a=3;
+@tm=row_start
+1
+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 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 drop 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: Table `t` is not system-versioned
+alter table t modify a int without system versioning;
+ERROR HY000: Table `t` is not system-versioned
+alter table t add 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
+) 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
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+create or replace table t(
+a int
+) engine=innodb;
+alter table t
+add column trx_start timestamp(6) as row start invisible,
+add column trx_end timestamp(6) as row end invisible,
+add period for system_time(trx_start, trx_end),
+add system versioning;
+show create table t;
+Table Create Table
+t CREATE TABLE `t` (
+ `a` int(11) DEFAULT NULL,
+ `trx_start` timestamp(6) GENERATED ALWAYS AS ROW START INVISIBLE,
+ `trx_end` timestamp(6) GENERATED ALWAYS AS ROW END INVISIBLE,
+ PERIOD FOR SYSTEM_TIME (`trx_start`, `trx_end`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+# Issue #211: drop of system columns required before drop system versioning
+alter table t drop column trx_start, drop column trx_end;
+show create table t;
+Table Create Table
+t CREATE TABLE `t` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+alter table t drop system versioning;
+insert into t values(1);
+call verify_vtq;
+No A B C D
+alter table t
+add column trx_start bigint(20) unsigned as row start invisible,
+add column trx_end bigint(20) unsigned as row end invisible,
+add period for system_time(trx_start, trx_end),
+add system versioning;
+call verify_vtq;
+No A B C D
+1 1 1 1 1
+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 INVISIBLE,
+ `trx_end` bigint(20) unsigned GENERATED ALWAYS AS ROW END INVISIBLE,
+ 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;
+call verify_vtq;
+No A B C D
+alter table t drop system versioning, algorithm=copy;
+call verify_vtq;
+No A B C D
+alter table t add system versioning, algorithm=copy;
+call verify_vtq;
+No A B C D
+show create table t;
+Table Create Table
+t CREATE TABLE `t` (
+ `a` int(11) DEFAULT NULL
+) 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
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+select * from t;
+a b
+2 NULL
+call verify_vtq;
+No A B C D
+alter table t drop column b, algorithm=copy;
+show create table t;
+Table Create Table
+t CREATE TABLE `t` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+select * from t for system_time all;
+a
+2
+1
+call verify_vtq;
+No A B C D
+alter table t drop 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
+create or replace table t (a int);
+insert t values (1),(2),(3),(4);
+alter table t add b int auto_increment null unique;
+select * from t;
+a b
+1 1
+2 2
+3 3
+4 4
+drop 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 not null unique;
+Got one of the listed errors
+alter table t add b int auto_increment unique;
+Got one of the listed errors
+alter table t add b int auto_increment null unique;
+select * from t;
+a b
+3 1
+select * from t for system_time all;
+a b
+1 NULL
+2 NULL
+3 1
+insert into t values (4, 0);
+select * from t for system_time all;
+a b
+1 NULL
+2 NULL
+3 1
+4 4
+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 not null unique;
+Got one of the listed errors
+alter table t add b int auto_increment unique;
+Got one of the listed errors
+alter table t add b int auto_increment null unique;
+select * from t;
+a b
+3 1
+select * from t for system_time all;
+a b
+1 NULL
+2 NULL
+3 1
+insert into t values (4, 0);
+select * from t for system_time all;
+a b
+1 NULL
+2 NULL
+3 1
+4 2
+create or replace table t (
+a int,
+row_start timestamp(6) as row start invisible,
+row_end timestamp(6) as row end invisible,
+period for system_time(row_start, row_end)
+) with system versioning;
+alter table t change column row_start asdf timestamp(6);
+ERROR HY000: Can not change system versioning field `row_start`
+insert into t values (1);
+alter table t modify column row_start bigint unsigned;
+ERROR HY000: Can not change system versioning field `row_start`
+create or replace table t (
+a int,
+row_start timestamp(6) as row start invisible,
+row_end timestamp(6) as row end invisible,
+period for system_time(row_start, row_end)
+) with system versioning;
+select * from t;
+a
+alter table t drop system versioning;
+ERROR HY000: System versioning field `row_start` exists
+alter table t drop column row_start;
+select * from t;
+a
+alter table t drop system versioning;
+ERROR HY000: System versioning field `row_end` exists
+alter table t drop column row_end;
+select * from t;
+a
+alter table t drop system versioning;
+show create table t;
+Table Create Table
+t CREATE TABLE `t` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+set system_versioning_alter_history= SURVIVE;
+ERROR 42000: Variable 'system_versioning_alter_history' can't be set to the value of 'SURVIVE'
+set system_versioning_alter_history= DROP;
+ERROR 42000: Variable 'system_versioning_alter_history' can't be set to the value of 'DROP'
+create or replace table t (a int) with system versioning;
+alter table t add system versioning;
+ERROR HY000: Table `t` is already system-versioned
+alter table t add system versioning, drop system versioning;
+ERROR HY000: Table `t` is already system-versioned
+set @@system_versioning_alter_history=keep;
+create or replace table t(x int, y int) with system versioning engine=innodb;
+alter table t modify y int without system versioning;
+insert into t values(1, 1);
+update t set y=2;
+# MDEV-14681 Bogus ER_UNSUPPORTED_EXTENSION
+create or replace table t1 (pk int auto_increment unique) with system versioning;
+insert into t1 values (1);
+delete from t1;
+alter table t1 engine=myisam;
+# MDEV-14692 crash in MDL_context::upgrade_shared_lock()
+create or replace temporary table t (a int);
+alter table t change column if exists b c bigint unsigned generated always as row start;
+ERROR HY000: System versioning prohibited for TEMPORARY tables
+alter table t change column if exists b c bigint unsigned generated always as row end;
+ERROR HY000: System versioning prohibited for TEMPORARY tables
+alter table t add system versioning;
+ERROR HY000: System versioning prohibited for TEMPORARY tables
+drop table t;
+# MDEV-14744 trx_id-based and transaction-based mixup in assertion
+create or replace table t (c text) engine=innodb with system versioning;
+show create table t;
+Table Create Table
+t CREATE TABLE `t` (
+ `c` text DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+alter table t add fulltext key (c);
+Warnings:
+Warning 124 InnoDB rebuilding table to add column FTS_DOC_ID
+create or replace table t (a int) with system versioning;
+alter table t drop column a;
+ERROR HY000: Table `t` must have at least one versioned column
+alter table t drop column a, drop column a;
+ERROR 42000: Can't DROP COLUMN `a`; check that it exists
+create or replace table t1 (row_start int);
+alter table t1 with system versioning;
+ERROR 42S21: Duplicate column name 'row_start'
+create or replace table t1 (row_end int);
+alter table t1 with system versioning;
+ERROR 42S21: Duplicate column name 'row_end'
+create or replace table t1 (a int, row_start int) with system versioning;
+ERROR 42S21: Duplicate column name 'row_start'
+create or replace table t1 (a int) with system versioning;
+set statement system_versioning_alter_history=keep for
+alter table t1 add column row_start int;
+ERROR 42S21: Duplicate column name 'row_start'
+set statement system_versioning_alter_history=keep for
+alter table t1 add column row_start timestamp(6);
+ERROR 42S21: Duplicate column name 'row_start'
+drop database test;
+create database test;
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..1f43595848b
--- /dev/null
+++ b/mysql-test/suite/versioning/r/auto_increment.result
@@ -0,0 +1,119 @@
+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, ' as row start invisible,
+ sys_end ', sys_type, ' as row end invisible,
+ 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 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
+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;
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..e2bd0f21b64
--- /dev/null
+++ b/mysql-test/suite/versioning/r/commit_id.result
@@ -0,0 +1,98 @@
+create table t1(
+id int auto_increment primary key,
+sys_trx_start bigint unsigned as row start invisible,
+sys_trx_end bigint unsigned as row end invisible,
+period for system_time (sys_trx_start, sys_trx_end)
+)
+with system versioning
+engine innodb;
+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 transaction_id = @tx0 from mysql.transaction_registry
+order by transaction_id desc 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 transaction_id = @tx1 from mysql.transaction_registry
+order by transaction_id desc 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 transaction_id = @tx2 from mysql.transaction_registry
+order by transaction_id desc limit 1;
+transaction_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
+set transaction isolation level read uncommitted;
+insert into t1 values ();
+select sys_trx_start from t1 where id = last_insert_id() into @tx3;
+select isolation_level = 'READ-UNCOMMITTED' from mysql.transaction_registry 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 isolation_level = 'READ-COMMITTED' from mysql.transaction_registry 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 isolation_level = 'SERIALIZABLE' from mysql.transaction_registry 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 isolation_level = 'REPEATABLE-READ' from mysql.transaction_registry where transaction_id = @tx6;
+isolation_level = 'REPEATABLE-READ'
+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
+8 1 1 1 1
diff --git a/mysql-test/suite/versioning/r/create.result b/mysql-test/suite/versioning/r/create.result
new file mode 100644
index 00000000000..3cf159ac3d0
--- /dev/null
+++ b/mysql-test/suite/versioning/r/create.result
@@ -0,0 +1,473 @@
+drop table if exists t1;
+create table t1 (
+x1 int unsigned,
+Sys_start SYS_DATATYPE as row start invisible comment 'start',
+Sys_end SYS_DATATYPE as row end invisible 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_DATATYPE GENERATED ALWAYS AS ROW START INVISIBLE COMMENT 'start',
+ `Sys_end` SYS_DATATYPE GENERATED ALWAYS AS ROW END INVISIBLE COMMENT 'end',
+ PERIOD FOR SYSTEM_TIME (`Sys_start`, `Sys_end`)
+) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+select table_catalog,table_schema,table_name,table_type,version,table_rows,avg_row_length,data_free,auto_increment,check_time,table_collation,checksum,create_options,table_comment from information_schema.tables where table_name='t1';
+table_catalog def
+table_schema test
+table_name t1
+table_type SYSTEM VERSIONED
+version 10
+table_rows 0
+avg_row_length 0
+data_free 0
+auto_increment NULL
+check_time NULL
+table_collation latin1_swedish_ci
+checksum NULL
+create_options
+table_comment
+select table_catalog,table_schema,table_name,column_name,ordinal_position,column_default,character_maximum_length,character_octet_length,character_set_name,collation_name,column_key,extra,privileges,column_comment,is_generated,generation_expression from information_schema.columns where table_name='t1';
+table_catalog def
+table_schema test
+table_name t1
+column_name x1
+ordinal_position 1
+column_default NULL
+character_maximum_length NULL
+character_octet_length NULL
+character_set_name NULL
+collation_name NULL
+column_key
+extra
+privileges select,insert,update,references
+column_comment
+is_generated NEVER
+generation_expression NULL
+table_catalog def
+table_schema test
+table_name t1
+column_name Sys_start
+ordinal_position 2
+column_default NULL
+character_maximum_length NULL
+character_octet_length NULL
+character_set_name NULL
+collation_name NULL
+column_key
+extra INVISIBLE
+privileges select,insert,update,references
+column_comment start
+is_generated ALWAYS
+generation_expression ROW START
+table_catalog def
+table_schema test
+table_name t1
+column_name Sys_end
+ordinal_position 3
+column_default NULL
+character_maximum_length NULL
+character_octet_length NULL
+character_set_name NULL
+collation_name NULL
+column_key
+extra INVISIBLE
+privileges select,insert,update,references
+column_comment end
+is_generated ALWAYS
+generation_expression ROW END
+# Implicit fields test
+create or replace table t1 (
+x2 int unsigned
+) with system versioning;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `x2` int(10) unsigned DEFAULT NULL
+) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+create or replace table t1 (
+x3 int unsigned,
+Sys_start SYS_DATATYPE as row start invisible,
+Sys_end SYS_DATATYPE as row end invisible,
+period for system_time (x, Sys_end)
+) with system versioning;
+ERROR HY000: PERIOD FOR SYSTEM_TIME must use columns `Sys_start` and `Sys_end`
+create or replace table t1 (
+x4 int unsigned,
+Sys_start SYS_DATATYPE as row start invisible,
+Sys_end2 SYS_DATATYPE as row end invisible,
+period for system_time (Sys_start, Sys_end)
+) with system versioning;
+ERROR HY000: PERIOD FOR SYSTEM_TIME must use columns `Sys_start` and `Sys_end2`
+create or replace table t1 (
+x5 int unsigned,
+Sys_start SYS_DATATYPE as row start invisible,
+Sys_end SYS_DATATYPE as row end invisible,
+period for system_time (Sys_start, x)
+) with system versioning;
+ERROR HY000: PERIOD FOR SYSTEM_TIME must use columns `Sys_start` and `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`: missing 'AS ROW START'
+create or replace table t1 (
+x7 int unsigned,
+Sys_start SYS_DATATYPE as row start invisible,
+Sys_end SYS_DATATYPE as row end invisible,
+period for system_time (Sys_start, Sys_end)
+);
+ERROR HY000: Wrong parameters for `t1`: missing 'WITH SYSTEM VERSIONING'
+create or replace table t1 (
+x8 int unsigned,
+Sys_start SYS_DATATYPE as row start invisible,
+Sys_end SYS_DATATYPE as row end invisible,
+period for system_time (sys_insert, sys_remove)
+) with system versioning;
+ERROR HY000: PERIOD FOR SYSTEM_TIME must use columns `Sys_start` and `Sys_end`
+create or replace table t1 (
+x9 int unsigned,
+Sys_start SYS_DATATYPE as row start invisible,
+Sys_end SYS_DATATYPE as row end invisible,
+period for system_time (Sys_start, Sys_end)
+);
+ERROR HY000: Wrong parameters for `t1`: missing 'WITH SYSTEM VERSIONING'
+create or replace table t1 (
+x10 int unsigned,
+Sys_start SYS_DATATYPE as row start invisible,
+Sys_end SYS_DATATYPE as row end invisible,
+period for system_time (Sys_start, Sys_start)
+);
+ERROR HY000: Wrong parameters for `t1`: missing 'WITH SYSTEM VERSIONING'
+create or replace table t1 (
+x11 int unsigned,
+Sys_start bigint unsigned as row start invisible,
+Sys_end timestamp(6) as row end invisible,
+period for system_time (Sys_start, Sys_end)
+) with system versioning;
+Got one of the listed errors
+create or replace table t1 (
+x12 int unsigned,
+Sys_start timestamp(6) as row start invisible,
+Sys_end bigint unsigned as row end invisible,
+period for system_time (Sys_start, Sys_end)
+) with system versioning;
+Got one of the listed errors
+create or replace table t1 (
+x13 int unsigned,
+Sys_start bigint as row start invisible,
+Sys_end bigint unsigned as row end invisible,
+period for system_time (Sys_start, Sys_end)
+) with system versioning engine innodb;
+ERROR HY000: `Sys_start` must be of type TIMESTAMP(6) for system-versioned table `t1`
+create or replace table t1 (
+x14 int unsigned,
+Sys_start bigint unsigned as row start invisible,
+Sys_end bigint as row end invisible,
+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 system-versioned table `t1`
+create or replace table t1 (
+x15 int with system versioning,
+B int
+);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `x15` int(11) DEFAULT NULL,
+ `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING
+) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+create or replace table t1 (
+x16 int with system versioning,
+B int
+) with system versioning;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `x16` int(11) DEFAULT NULL,
+ `B` int(11) DEFAULT NULL
+) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+create or replace table t1 (
+x17 int,
+B int without system versioning
+);
+create or replace table t1 (
+x18 int,
+B int without system versioning
+) with system versioning;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `x18` int(11) DEFAULT NULL,
+ `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING
+) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+create or replace table t1 (
+x19 int with system versioning,
+B int without system versioning
+);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `x19` int(11) DEFAULT NULL,
+ `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING
+) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+create or replace table t1 (
+x20 int with system versioning,
+B int without system versioning
+) with system versioning;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `x20` int(11) DEFAULT NULL,
+ `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING
+) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+create or replace table t1 (
+x21 int without system versioning
+);
+create or replace table t1 (
+x22 int without system versioning
+) with system versioning;
+ERROR HY000: Table `t1` must have at least one versioned column
+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
+) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+drop table tt1;
+create temporary table tt1 like t1;
+Warnings:
+Warning 1105 System versioning is stripped from temporary `test.tt1`
+# Temporary is stripped from versioning
+show create table tt1;
+Table Create Table
+tt1 CREATE TEMPORARY TABLE `tt1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1
+# CREATE TABLE ... SELECT
+create or replace table t1 (x23 int) with system versioning;
+create or replace table t0(
+y int,
+st SYS_DATATYPE as row start,
+en SYS_DATATYPE as row end,
+period for system_time (st, en)
+) with system versioning;
+## For non-versioned table:
+### 1. invisible fields are not included
+create or replace table t2 as select * from t1;
+show create table t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `x23` int(11) DEFAULT NULL
+) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1
+### 2. all visible fields are included
+create or replace table t3 as select * from t0;
+select * from t0;
+y st en
+show create table t3;
+Table Create Table
+t3 CREATE TABLE `t3` (
+ `y` int(11) DEFAULT NULL,
+ `st` SYS_DATATYPE,
+ `en` SYS_DATATYPE
+) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1
+## For versioned table
+insert into t1 values (1);
+select row_start from t1 into @row_start;
+insert into t0 (y) values (2);
+select st from t0 into @st;
+create or replace table t2 with system versioning as select * from t1;
+show create table t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `x23` int(11) DEFAULT NULL
+) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+#### invisible fields are not copied
+select * from t2;
+x23
+1
+select * from t2 where row_start <= @row_start;
+x23
+### 2. source table with visible system fields, target with invisible
+create or replace table t3 with system versioning as select * from t0;
+show create table t3;
+Table Create Table
+t3 CREATE TABLE `t3` (
+ `y` int(11) DEFAULT NULL,
+ `st` SYS_DATATYPE,
+ `en` SYS_DATATYPE
+) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+select * from t3 where y > 2;
+y st en
+select y from t3 where st = @st and row_start > @st;
+y
+2
+### 3. source and target table with visible system fields
+create or replace table t3 (
+st SYS_DATATYPE as row start invisible,
+en SYS_DATATYPE as row end invisible,
+period for system_time (st, en)
+) with system versioning as select * from t0;
+show create table t3;
+Table Create Table
+t3 CREATE TABLE `t3` (
+ `y` int(11) DEFAULT NULL,
+ `st` SYS_DATATYPE GENERATED ALWAYS AS ROW START INVISIBLE,
+ `en` SYS_DATATYPE GENERATED ALWAYS AS ROW END INVISIBLE,
+ PERIOD FOR SYSTEM_TIME (`st`, `en`)
+) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+select y from t3;
+y
+2
+select y from t3 where st = @st;
+y
+### 4. system fields not or wrongly selected
+create or replace table t3 with system versioning select x23 from t1;
+show create table t3;
+Table Create Table
+t3 CREATE TABLE `t3` (
+ `x23` int(11) DEFAULT NULL
+) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+select * from t3;
+x23
+1
+create or replace table t3 with system versioning select x23, row_start from t1;
+ERROR HY000: Wrong parameters for `t3`: missing 'AS ROW END'
+create or replace table t3 with system versioning select x23, row_end from t1;
+ERROR HY000: Wrong parameters for `t3`: missing 'AS ROW START'
+# Prepare checking for historical row
+delete from t1;
+select row_end from t1 for system_time all into @row_end;
+delete from t0;
+select en from t0 for system_time all into @en;
+## Combinations of versioned + non-versioned
+create or replace table t2 (y int);
+insert into t2 values (3);
+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` (
+ `x23` int(11) DEFAULT NULL,
+ `y` int(11) DEFAULT NULL
+) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+select * from t3 for system_time all;
+x23 y
+1 3
+select * from t3 for system_time all where row_start = @row_start and row_end = @row_end;
+x23 y
+create or replace table t2 like t0;
+insert into t2 (y) 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 t3 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 t3 where y = 2 into @st, @en;
+select y from t2 for system_time all where st = @st and en = @en;
+y
+2
+## Default engine detection
+create or replace table t1 (x25 int) with system versioning engine NON_DEFAULT_ENGINE;
+create or replace table t2
+as select x25, row_start, row_end from t1 for system_time all;
+show create table t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `x25` int(11) DEFAULT NULL
+) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1
+create or replace table t2 with system versioning
+as select x25, row_start, row_end from t1;
+show create table t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `x25` int(11) DEFAULT NULL
+) ENGINE=NON_DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+create or replace table t1 (
+x26 int,
+st bigint unsigned as row start,
+en bigint unsigned as row end,
+period for system_time (st, en)
+) with system versioning engine innodb;
+create or replace table t2 with system versioning engine myisam
+as select * from t1;
+ERROR HY000: `st` must be of type TIMESTAMP(6) for system-versioned table `t2`
+create or replace table t1 (x27 int, id int) with system versioning engine NON_DEFAULT_ENGINE;
+create or replace table t2 (b int, id int);
+create or replace table t3 with system versioning
+as select t2.b, t1.x27, t1.row_start, t1.row_end from t2 inner join t1 on t2.id=t1.id;
+show create table t3;
+Table Create Table
+t3 CREATE TABLE `t3` (
+ `b` int(11) DEFAULT NULL,
+ `x27` int(11) DEFAULT NULL
+) ENGINE=NON_DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+## Errors
+create or replace temporary table t (x28 int) with system versioning;
+ERROR HY000: System versioning prohibited for TEMPORARY tables
+create or replace table t1 (
+x29 int unsigned,
+Sys_start0 timestamp(6) as row start invisible,
+Sys_start timestamp(6) as row start invisible,
+Sys_end timestamp(6) as row end invisible,
+period for system_time (Sys_start, Sys_end)
+) with system versioning;
+ERROR HY000: Duplicate ROW START column `Sys_start`
+create or replace table t1 (
+x29 int unsigned,
+Sys_end0 timestamp(6) as row end invisible,
+Sys_start timestamp(6) as row start invisible,
+Sys_end timestamp(6) as row end invisible,
+period for system_time (Sys_start, Sys_end)
+) with system versioning;
+ERROR HY000: Duplicate ROW END column `Sys_end`
+## System fields detection
+create or replace table t1 (x30 int) with system versioning;
+create or replace table t2 (
+y int,
+st SYS_DATATYPE as row start invisible,
+en SYS_DATATYPE as row end invisible,
+period for system_time (st, en)
+) with system versioning;
+create or replace table t3
+as select x30, y, row_start, row_end, st, en from t1, t2;
+show create table t3;
+Table Create Table
+t3 CREATE TABLE `t3` (
+ `x30` int(11) DEFAULT NULL,
+ `y` int(11) DEFAULT NULL,
+ `st` SYS_DATATYPE NOT NULL INVISIBLE DEFAULT '0000-00-00 00:00:00.000000',
+ `en` SYS_DATATYPE NOT NULL INVISIBLE DEFAULT '0000-00-00 00:00:00.000000'
+) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1
+create or replace table t3 (
+y int,
+st SYS_DATATYPE as row start invisible,
+en SYS_DATATYPE as row end invisible,
+period for system_time (st, en)
+) with system versioning
+as select x30, y, row_start, row_end, st, en from t1, t2;
+show create table t3;
+Table Create Table
+t3 CREATE TABLE `t3` (
+ `x30` int(11) DEFAULT NULL,
+ `y` int(11) DEFAULT NULL,
+ `st` SYS_DATATYPE GENERATED ALWAYS AS ROW START INVISIBLE,
+ `en` SYS_DATATYPE GENERATED ALWAYS AS ROW END INVISIBLE,
+ PERIOD FOR SYSTEM_TIME (`st`, `en`)
+) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+# MDEV-14828 Server crashes in JOIN::prepare / setup_fields on 2nd execution of PS [#437]
+create or replace table t1 (x int) with system versioning;
+prepare bad from 'create or replace table t2 with system versioning as select * from t1';
+execute bad;
+execute bad;
+execute bad;
+execute bad;
+execute bad;
+execute bad;
+execute bad;
+execute bad;
+# bad is good.
+drop database test;
+create database 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..fda5e086be2
--- /dev/null
+++ b/mysql-test/suite/versioning/r/cte.result
@@ -0,0 +1,118 @@
+set default_storage_engine=innodb;
+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 max(sys_trx_start) into @ts_1 from emp;
+update emp set mgr=30 where name ="john";
+select 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 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 for system_time as of timestamp @ts_1 as e,
+ancestors as a
+where e.mgr = a.emp_id
+)
+select * from ancestors;
+emp_id name mgr salary
+1 bill NULL 1000
+20 john 1 500
+30 jane 1 750
+/* Expected 3 rows */
+with recursive
+ancestors
+as
+(
+select e.emp_id, e.name, e.mgr, e.salary
+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 for system_time as of timestamp @ts_2 as e,
+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;
+with recursive
+ancestors
+as
+(
+select e.emp_id, e.name, e.mgr
+from emp for system_time as of timestamp @ts as e
+where name = 'bill'
+ union
+select ee.emp_id, ee.name, ee.mgr
+from emp for system_time as of timestamp @ts as ee, ancestors as a
+where ee.mgr = a.emp_id
+)
+select * from ancestors;
+emp_id name mgr
+1 bill 0
+2 bill 1
+3 kate 1
+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 (select * from emp natural join addr) for system_time all as t) 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 (select * from emp natural join addr) for system_time all as t;
+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/ddl.result b/mysql-test/suite/versioning/r/ddl.result
new file mode 100644
index 00000000000..a4323b89ee1
--- /dev/null
+++ b/mysql-test/suite/versioning/r/ddl.result
@@ -0,0 +1,211 @@
+set @@session.time_zone='+00:00';
+select ifnull(max(transaction_id), 0) into @start_trx_id from mysql.transaction_registry;
+set @test_start=now(6);
+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 > @test_start as C,
+commit_timestamp >= begin_timestamp as D
+from mysql.transaction_registry
+where transaction_id > @start_trx_id;
+select ifnull(max(transaction_id), 0)
+into @start_trx_id
+from mysql.transaction_registry;
+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_archive_table_name()
+returns varchar(255)
+begin
+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_archive()
+begin
+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;
+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_archive_table_name(), ' for system_time all');
+a
+2
+1
+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<sys_trx_start from t where a=2;
+@tm<sys_trx_start
+1
+select sys_trx_start from t where a=2 into @tm;
+call concat_exec3('select @tm=sys_trx_end from ', get_archive_table_name(), ' for system_time all where a=2');
+@tm=sys_trx_end
+1
+call drop_last_archive();
+set versioning_alter_history= keep;
+drop table t_vtmd;
+drop table t;
+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;
+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_archive_table_name(), ' for system_time all');
+a
+2
+1
+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<sys_trx_start from t where a=2;
+@tm<sys_trx_start
+1
+select sys_trx_start from t where a=2 into @tm;
+call concat_exec3('select @tm=sys_trx_end from ', get_archive_table_name(), ' for system_time all where a=2');
+@tm=sys_trx_end
+1
+call drop_last_archive();
+set versioning_alter_history= keep;
+drop table t_vtmd;
+drop table t;
+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;
+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_archive_table_name(), ' for system_time all');
+a
+2
+1
+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<sys_trx_start from t where a=2;
+@tm<sys_trx_start
+1
+select sys_trx_start from t where a=2 into @tm;
+call concat_exec3('select @tm=sys_trx_end from ', get_archive_table_name(), ' for system_time all where a=2');
+@tm=sys_trx_end
+1
+call drop_last_archive();
+set versioning_alter_history= keep;
+drop table t_vtmd;
+drop table t;
+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_alter_history = keep;
+drop function get_archive_table_name;
+drop procedure drop_last_archive;
+select * from mysql.vtmd_template;
+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 current lifetime period',
+ `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;
+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
+drop table t;
+drop table t_vtmd;
+drop procedure verify_vtq;
+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
new file mode 100644
index 00000000000..79f619fecdd
--- /dev/null
+++ b/mysql-test/suite/versioning/r/delete.result
@@ -0,0 +1,320 @@
+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, ' as row start invisible,
+ sys_end ', sys_type, ' as row end invisible,
+ 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;
+select "Deleted 0";
+execute stmt;
+delete from t1 where XNo = 1;
+select "Deleted 1";
+execute stmt;
+delete from t1 where XNo > 5;
+select "Deleted >5";
+create view vt1 as select XNo from t1;
+select XNo as XNo_vt1 from vt1;
+delete from vt1 where XNo = 3;
+select "Deleted from VIEW 3";
+select XNo as XNo_vt1 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, ' as row start invisible,
+ sys_end ', sys_type, ' as row end invisible,
+ 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, ' as row start invisible,
+ sys_end ', sys_type, ' as row end invisible,
+ 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
+Deleted 0
+Deleted 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
+Deleted 1
+Deleted 1
+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
+Deleted >5
+Deleted >5
+XNo_vt1
+2
+3
+4
+5
+Deleted from VIEW 3
+Deleted from VIEW 3
+XNo_vt1
+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', 'vtq_commit_ts(sys_end)');
+XNo vtq_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
+Deleted 0
+Deleted 0
+XNo vtq_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
+Deleted 1
+Deleted 1
+XNo vtq_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
+Deleted >5
+Deleted >5
+XNo_vt1
+2
+3
+4
+5
+Deleted from VIEW 3
+Deleted from VIEW 3
+XNo_vt1
+2
+4
+5
+XNo vtq_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
+A B C
+1 1 1
+call test_02('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)');
+x
+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', 'vtq_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
+# Update + delete
+create or replace table t1 (x int) with system versioning;
+insert into t1 values (1);
+update t1 set x= 2;
+delete from t1;
+select x from t1 for system_time all;
+x
+2
+1
+drop database test;
+create database 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..cd6cec7e725
--- /dev/null
+++ b/mysql-test/suite/versioning/r/derived.result
@@ -0,0 +1,295 @@
+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 row_end>'2031-1-1') as tmp;
+emp_id
+4
+set @tmp= "select emp_id from (select emp_id from emp where row_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 for system_time as of timestamp @ts as e
+where name = 'bill'
+ union
+select ee.emp_id, ee.name, ee.mgr
+from emp for system_time as of timestamp @ts as ee,
+ancestors as a
+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 for system_time as of timestamp @ts as e
+ where name = 'bill'
+ union
+ select ee.emp_id, ee.name, ee.mgr
+ from emp for system_time as of timestamp @ts as ee,
+ ancestors as a
+ 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);
+delete from t1;
+insert into t1 values (2);
+insert into t2 values (10);
+select * from (select *, t1.row_end, t1.row_end as endo from t1) as s0;
+x row_end endo
+2 # #
+select * from (select *, t1.row_end, t2.row_start from t1, t2) as s0;
+x y row_end row_start
+2 10 # #
+# SYSTEM_TIME propagation from inner to outer
+select * from (select * from t1 for system_time as of timestamp @t0, t2) as s0;
+x y
+1 10
+with s1 as (select * from t1 for system_time as of timestamp @t0, t2) select * from s1;
+x y
+1 10
+# leading table selection
+select * from (select *, t1.row_end from t2, t1 for system_time as of timestamp @t0) as s2;
+y x row_end
+10 1 #
+with s3 as (select *, t1.row_end from t2, t1 for system_time as of timestamp @t0) select * from s3;
+y x row_end
+10 1 #
+### 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;
+create view vt2 as select * from t1;
+# SYSTEM_TIME propagation from view
+select * from vt1;
+x
+1
+# SYSTEM_TIME propagation from inner to outer
+select * from (select * from vt1, t2) as s0;
+x y
+1 10
+### SYSTEM_TIME clash
+select * from (select * from t1 for system_time all) for system_time all as dt0;
+ERROR HY000: Table `dt0` is not system-versioned
+select * from vt1 for system_time all;
+ERROR HY000: Table `vt1` is not system-versioned
+with dt1 as (select * from t1 for system_time all)
+select * from dt1 for system_time all;
+ERROR HY000: Table `dt1` is not system-versioned
+### UNION
+set @t1= now(6);
+delete from t2;
+insert into t2 values (3);
+# SYSTEM_TIME is not propagated
+select x from t1 union
+select y from t2;
+x
+2
+3
+select x from t1 for system_time as of @t0 union
+select y from t2;
+x
+1
+3
+select x from t1 union
+select y from t2 for system_time as of @t1;
+x
+2
+10
+select x from t1 for system_time as of @t0 union
+select y from t2 for system_time as of @t1;
+x
+1
+10
+# LEFT/RIGHT JOIN
+create or replace table t1 (x int, y int) with system versioning;
+create or replace table t2 (x int, y int) 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);
+## Outer or inner SYSTEM_TIME produces same expression
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where; Using join buffer (flat, BNL join)
+Query A:
+Note 1003 select `test`.`t1`.`x` AS `x`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME ALL join `test`.`t2` FOR SYSTEM_TIME ALL where `test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t1`.`row_end` > <cache>(cast(current_timestamp(6) as datetime(6))) and `test`.`t1`.`row_start` <= <cache>(cast(current_timestamp(6) as datetime(6))) and `test`.`t2`.`row_end` > <cache>(cast(current_timestamp(6) as datetime(6))) and `test`.`t2`.`row_start` <= <cache>(cast(current_timestamp(6) as datetime(6)))
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where; Using join buffer (flat, BNL join)
+Query B:
+Note 1003 select `test`.`t1`.`x` AS `x`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME ALL join `test`.`t2` FOR SYSTEM_TIME ALL where `test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t1`.`row_end` > <cache>(cast(current_timestamp(6) as datetime(6))) and `test`.`t1`.`row_start` <= <cache>(cast(current_timestamp(6) as datetime(6))) and `test`.`t2`.`row_end` > <cache>(cast(current_timestamp(6) as datetime(6))) and `test`.`t2`.`row_start` <= <cache>(cast(current_timestamp(6) as datetime(6)))
+Fine result: queries A and B are equal.
+## LEFT JOIN: t1, t2 versioned
+select * from (
+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)
+as derived;
+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
+alter table t2 drop system versioning;
+## LEFT JOIN: t1 versioned
+select * from (
+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)
+as derived;
+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
+alter table t1 drop system versioning;
+alter table t2 add system versioning;
+## LEFT JOIN: t2 versioned
+select * from (
+select t1.x as LJ3_x1, t1.y as y1, t2.x as x2, t2.y as y2
+from t1 left join t2 on t1.x = t2.x)
+as derived;
+LJ3_x1 y1 x2 y2
+1 1 1 2
+1 2 1 2
+1 3 1 2
+4 4 NULL NULL
+5 5 NULL NULL
+alter table t1 add system versioning;
+## RIGHT JOIN: t1, t2 versioned
+select * from (
+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)
+as derived;
+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
+alter table t2 drop system versioning;
+## RIGHT JOIN: t1 versioned
+select * from (
+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)
+as derived;
+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
+alter table t1 drop system versioning;
+alter table t2 add system versioning;
+## RIGHT JOIN: t2 versioned
+select * from (
+select t1.x as RJ3_x1, t1.y as y1, t2.x as x2, t2.y as y2
+from t1 right join t2 on t1.x = t2.x)
+as derived;
+RJ3_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, t2;
+drop view vt1, vt2;
diff --git a/mysql-test/suite/versioning/r/foreign.result b/mysql-test/suite/versioning/r/foreign.result
new file mode 100644
index 00000000000..ca2459f784a
--- /dev/null
+++ b/mysql-test/suite/versioning/r/foreign.result
@@ -0,0 +1,232 @@
+#################
+# Test RESTRICT #
+#################
+create table parent(
+id int unique key
+) engine innodb;
+create table child(
+parent_id int,
+sys_start SYS_DATATYPE as row start invisible,
+sys_end SYS_DATATYPE as row end invisible,
+period for system_time(sys_start, sys_end),
+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;
+##############################################
+# 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,
+sys_start SYS_DATATYPE as row start invisible,
+sys_end SYS_DATATYPE as row end invisible,
+period for system_time(sys_start, sys_end),
+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;
+################
+# Test CASCADE #
+################
+create table parent(
+id int unique key
+) engine innodb;
+create table child(
+parent_id int,
+sys_start SYS_DATATYPE as row start invisible,
+sys_end SYS_DATATYPE as row end invisible,
+period for system_time(sys_start, sys_end),
+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);
+## FIXME: #415 update of foreign constraints is disabled
+call mtr.add_suppression("foreign key constraints in timestamp-based temporal table");
+delete from parent where id = 1;
+ERROR 42000: Table 'parent' uses an extension that doesn't exist in this MariaDB version
+delete from child where parent_id = 1;
+## FIXME END
+delete from parent where id = 1;
+select * from child;
+parent_id
+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;
+select * from child;
+parent_id
+2
+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,
+sys_start SYS_DATATYPE as row start invisible,
+sys_end SYS_DATATYPE as row end invisible,
+period for system_time(sys_start, sys_end)
+) 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 (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);
+## FIXME: #415 update of foreign constraints is disabled
+delete from child;
+## FIXME END
+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;
+#################
+# Test SET NULL #
+#################
+create table parent(
+id int unique key
+) engine innodb;
+create table child(
+parent_id int,
+sys_start SYS_DATATYPE as row start invisible,
+sys_end SYS_DATATYPE as row end invisible,
+period for system_time(sys_start, sys_end),
+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);
+## FIXME: #415 update of foreign constraints is disabled
+delete from child where parent_id = 1;
+## FIXME END
+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
+1
+delete from child;
+insert into parent values(1);
+insert into child values(1);
+drop table child;
+drop table parent;
+###########################
+# Parent table is foreign #
+###########################
+create or replace table parent(
+id int unique key,
+sys_start SYS_DATATYPE as row start invisible,
+sys_end SYS_DATATYPE as row end invisible,
+period for system_time(sys_start, sys_end)
+) 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;
+###################
+# crash on DELETE #
+###################
+create or replace table a (
+cola int(10) primary key,
+v_cola int(10) as (cola mod 10) virtual,
+sys_start SYS_DATATYPE as row start invisible,
+sys_end SYS_DATATYPE as row end invisible,
+period for system_time(sys_start, sys_end)
+) engine=innodb with system versioning;
+create index v_cola on a (v_cola);
+create or replace table b(
+cola int(10),
+v_cola int(10),
+sys_start SYS_DATATYPE as row start invisible,
+sys_end SYS_DATATYPE as row end invisible,
+period for system_time(sys_start, sys_end)
+) engine=innodb with system versioning;
+alter table b add constraint `v_cola_fk`
+foreign key (v_cola) references a (v_cola);
+insert into a(cola) values (12);
+insert into b(cola, v_cola) values (10,2);
+delete from a;
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`b`, CONSTRAINT `v_cola_fk` FOREIGN KEY (`v_cola`) REFERENCES `a` (`v_cola`))
+drop table b, a;
diff --git a/mysql-test/suite/versioning/r/insert.result b/mysql-test/suite/versioning/r/insert.result
new file mode 100644
index 00000000000..48b1f2778fb
--- /dev/null
+++ b/mysql-test/suite/versioning/r/insert.result
@@ -0,0 +1,361 @@
+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, ' as row start invisible,
+ sys_end ', sys_type, ' as row end invisible,
+ 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 delayed 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, ' as row start invisible,
+ sys_end ', sys_type, ' as row end invisible,
+ 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, ' as row start invisible,
+ sys_end ', sys_type, ' as row end invisible,
+ 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;
+insert into t1(x, y) values(8001, 9001);
+insert into vt1_1(x, y) values(1001, 2001);
+insert into vt1_1 values(1002, 2002);
+set @str= concat('select x, y, ', fields, ' from t1');
+prepare stmt from @str; execute stmt; drop prepare stmt;
+select x, y from vt1_1;
+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 row_start, row_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, row_start > @sys_start as C, row_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, ' as row start invisible,
+ sys_end ', sys_type, ' as row end invisible,
+ 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);
+insert into t1(x, y, sys_start) values
+(7, 7001, DEFAULT);
+insert into t1(x, y, sys_end) values
+(8, 8001, DEFAULT);
+insert into t1(x, y, sys_start, sys_end) values
+(9, 9001, DEFAULT, DEFAULT);
+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.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.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.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.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.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
+1002 2002
+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.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
+1002 2002
+drop table t1;
+drop view vt1_1;
+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', 'vtq_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', 'vtq_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 as row start invisible,
+sys_end bigint unsigned as row end invisible,
+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
+set global system_versioning_transaction_registry= off;
+insert into t2(x) values (1);
+insert into t1(x) values (1);
+ERROR HY000: Temporal operation requires `mysql.transaction_registry` (@@system_versioning_transaction_registry).
+set global system_versioning_transaction_registry= on;
+Warnings:
+Warning 4134 Transaction-based system versioning is EXPERIMENTAL and is subject to change in future.
+create or replace table t1 (
+x int,
+y int as (x) virtual,
+sys_trx_start bigint unsigned as row start invisible,
+sys_trx_end bigint unsigned as row end invisible,
+period for system_time (sys_trx_start, sys_trx_end)
+) engine=innodb with system versioning;
+insert into t1 values (1, null);
+update t1 set x= x + 1;
+select x, y, sys_trx_end = 18446744073709551615 as current from t1 for system_time all;
+x y current
+2 2 1
+1 1 0
+create or replace table t1 (x int) with system versioning engine innodb;
+insert into t1 values (1), (2);
+insert into t1 (row_start) select row_end from t1;
+ERROR HY000: The value specified for generated column 'row_start' in table 't1' ignored
+set sql_mode='';
+insert into t1 (row_start, row_end) values (DEFAULT, 1);
+Warnings:
+Warning 1906 The value specified for generated column 'row_end' in table 't1' ignored
+set sql_mode=default;
+select @@sql_mode into @saved_mode;
+set sql_mode= '';
+insert into t1 (x, row_start, row_end) values (3, 4, 5);
+Warnings:
+Warning 1906 The value specified for generated column 'row_start' in table 't1' ignored
+Warning 1906 The value specified for generated column 'row_end' in table 't1' ignored
+set sql_mode= @saved_mode;
+insert into t1 (row_start, row_end) values (DEFAULT, DEFAULT);
+select * from t1;
+x
+1
+2
+NULL
+3
+NULL
+# MDEV-14792 INSERT without column list into table with explicit versioning columns produces bad data
+create or replace table t1 (
+i int,
+s timestamp(6) as row start,
+e timestamp(6) as row end,
+c varchar(8),
+period for system_time(s, e))
+with system versioning;
+insert into t1 values (1, null, null, 'foo');
+select i, c, current_row(e) from t1;
+i c current_row(e)
+1 foo 1
+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;
+set timestamp=1000000019;
+select now() < sysdate();
+now() < sysdate()
+1
+create table t1 (a int) with system versioning;
+insert t1 values (1);
+select * from t1 for system_time as of now(6);
+a
+select * from t1 for system_time as of sysdate(6);
+a
+1
+drop table t1;
diff --git a/mysql-test/suite/versioning/r/online.result b/mysql-test/suite/versioning/r/online.result
new file mode 100644
index 00000000000..267da5db8fa
--- /dev/null
+++ b/mysql-test/suite/versioning/r/online.result
@@ -0,0 +1,38 @@
+set system_versioning_alter_history=keep;
+create or replace table t (a int, b int) engine=innodb;
+alter table t add system versioning, lock=none;
+ERROR 0A000: LOCK=NONE is not supported. Reason: Not implemented for system-versioned tables. Try LOCK=SHARED
+alter table t add system versioning, lock=shared;
+alter table t drop column b, lock=none;
+ERROR 0A000: LOCK=NONE is not supported. Reason: Not implemented for system-versioned tables. Try LOCK=SHARED
+alter table t drop column b, algorithm=inplace;
+ERROR 0A000: ALGORITHM=INPLACE is not supported. Reason: Not implemented for system-versioned tables. Try ALGORITHM=COPY
+alter table t add index idx(a), lock=none;
+alter table t drop system versioning, lock=none;
+ERROR 0A000: LOCK=NONE is not supported. Reason: Not implemented for system-versioned tables. Try LOCK=SHARED
+alter table t drop system versioning, algorithm=inplace;
+ERROR 0A000: ALGORITHM=INPLACE is not supported. Reason: Not implemented for system-versioned tables. Try ALGORITHM=COPY
+set global system_versioning_transaction_registry=on;
+Warnings:
+Warning 4134 Transaction-based system versioning is EXPERIMENTAL and is subject to change in future.
+create or replace table t (a int, b int) engine=innodb;
+alter table t
+add s bigint unsigned as row start,
+add e bigint unsigned as row end,
+add period for system_time(s, e),
+add system versioning,
+lock=none;
+ERROR 0A000: LOCK=NONE is not supported. Reason: Not implemented for system-versioned tables. Try LOCK=SHARED
+alter table t
+add s bigint unsigned as row start,
+add e bigint unsigned as row end,
+add period for system_time(s, e),
+add system versioning;
+alter table t drop column b, lock=none;
+ERROR 0A000: LOCK=NONE is not supported. Reason: Not implemented for system-versioned tables. Try LOCK=SHARED
+alter table t add index idx(a), lock=none;
+alter table t drop column s, drop column e;
+alter table t drop system versioning, lock=none;
+ERROR 0A000: LOCK=NONE is not supported. Reason: Not implemented for system-versioned tables. Try LOCK=SHARED
+set global system_versioning_transaction_registry=off;
+drop table t;
diff --git a/mysql-test/suite/versioning/r/optimized.result b/mysql-test/suite/versioning/r/optimized.result
new file mode 100644
index 00000000000..443d0401771
--- /dev/null
+++ b/mysql-test/suite/versioning/r/optimized.result
@@ -0,0 +1,97 @@
+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 2 2
+3 4 4
+Warnings:
+Note 4110 Non-versioned field `b` in historical query
+Note 4110 Non-versioned field `b` in historical query
+select * from t for system_time as of timestamp now(6);
+a b
+1 2
+3 4
+Warnings:
+Note 4110 Non-versioned field `b` in historical query
+select count(*) from t for system_time as of timestamp now(6) group by b;
+count(*)
+1
+1
+Warnings:
+Note 4110 Non-versioned field `b` in historical query
+select * from t for system_time as of timestamp now(6) order by b asc;
+a b
+1 2
+3 4
+Warnings:
+Note 4110 Non-versioned field `b` in historical query
+Note 4110 Non-versioned field `b` in historical query
+select * from t for system_time as of timestamp now(6) order by b desc;
+a b
+3 4
+1 2
+Warnings:
+Note 4110 Non-versioned field `b` in historical query
+Note 4110 Non-versioned field `b` in historical query
+select * from t for system_time as of timestamp now(6) group by a having a=2;
+a b
+Warnings:
+Note 4110 Non-versioned field `b` in historical query
+select * from t for system_time as of timestamp now(6) group by b having b=2;
+a b
+1 2
+Warnings:
+Note 4110 Non-versioned field `b` in historical query
+Note 4110 Non-versioned field `b` in historical query
+Note 4110 Non-versioned field `b` in historical query
+select a from t for system_time as of timestamp now(6) where b=2;
+a
+1
+Warnings:
+Note 4110 Non-versioned field `b` in historical query
+select a from t for system_time as of timestamp now(6) where b=NULL;
+a
+Warnings:
+Note 4110 Non-versioned field `b` in historical query
+select a from t for system_time as of timestamp now(6) where b is NULL;
+a
+Warnings:
+Note 4110 Non-versioned 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:
+Note 4110 Non-versioned field `b` in historical query
+Note 4110 Non-versioned field `b` in historical query
+Note 4110 Non-versioned field `b` in historical query
+select a, b from t;
+a b
+1 2
+3 4
+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 2
+3 4
+Warnings:
+Note 4110 Non-versioned field `b` in historical query
+select * from t for system_time as of timestamp now(6) where b is NULL;
+a b
+Warnings:
+Note 4110 Non-versioned field `b` in historical query
+drop table t;
diff --git a/mysql-test/suite/versioning/r/partition.result b/mysql-test/suite/versioning/r/partition.result
new file mode 100644
index 00000000000..1abd35631eb
--- /dev/null
+++ b/mysql-test/suite/versioning/r/partition.result
@@ -0,0 +1,412 @@
+# Check conventional partitioning on temporal tables
+create table t1 (x int)
+with system versioning
+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 partition (p0);
+x
+select * from t1 partition (p1);
+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
+# Engine change native <-> non-native versioning prohibited
+create or replace table t1 (i int) engine=DEFAULT_ENGINE with system versioning partition by hash(i);
+alter table t1 engine=NON_DEFAULT_ENGINE;
+ERROR HY000: Not allowed for system-versioned `test`.`t1`. Change to/from native system versioning engine is prohibited.
+## CREATE TABLE
+create or replace table t1 (x int)
+partition by system_time (
+partition p0 history,
+partition pn current);
+ERROR HY000: Transaction system versioning for `t1` is not supported
+create or replace table t1 (x int);
+alter table t1
+partition by system_time (
+partition p0 history,
+partition pn current);
+Got one of the listed errors
+create or replace table t1 (x int)
+with system versioning
+partition by system_time (
+partition p0 current);
+ERROR HY000: Wrong partitions for `t1`: must have at least one HISTORY and exactly one last CURRENT
+create or replace table t1 (x int)
+with system versioning
+partition by system_time (
+partition p0 current,
+partition p1 current);
+ERROR HY000: Wrong partitions for `t1`: must have at least one HISTORY and exactly one last CURRENT
+create or replace table t1 (x int)
+with system versioning
+partition by system_time (
+partition p0 history,
+partition p1 history);
+ERROR HY000: Wrong partitions for `t1`: must have at least one HISTORY and exactly one last CURRENT
+create or replace table t1 (x int)
+with system versioning
+partition by system_time (
+partition pn current,
+partition p0 history);
+ERROR HY000: Wrong partitions for `t1`: must have at least one HISTORY and exactly one last CURRENT
+create or replace table t1 (x int)
+with system versioning
+partition by system_time (
+partition p0,
+partition pn current);
+ERROR HY000: Wrong partitions for `t1`: must have at least one HISTORY and exactly one last CURRENT
+create or replace table t1 (x int)
+with system versioning
+partition by system_time (
+partition p0 history,
+partition pn current);
+## ALTER TABLE
+alter table t1 add partition (
+partition p1 current);
+ERROR HY000: Wrong partitions for `t1`: must have at least one HISTORY and exactly one last CURRENT
+alter table t1 add partition (
+partition p1 history);
+Warnings:
+Warning 4113 Maybe missing parameters: no rotation condition for multiple HISTORY partitions.
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `x` int(11) DEFAULT NULL
+) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+ PARTITION BY SYSTEM_TIME
+(PARTITION `p0` HISTORY ENGINE = DEFAULT_ENGINE,
+ PARTITION `p1` HISTORY ENGINE = DEFAULT_ENGINE,
+ PARTITION `pn` CURRENT ENGINE = DEFAULT_ENGINE)
+insert into t1 values (1), (2);
+alter table t1 drop partition pn;
+ERROR HY000: Wrong partitions for `t1`: must have at least one HISTORY and exactly one last CURRENT
+alter table t1 drop partition p1;
+alter table t1 drop partition p0;
+ERROR HY000: Wrong partitions for `t1`: must have at least one HISTORY and exactly one last CURRENT
+select x from t1;
+x
+1
+2
+# Bug #260: incorrect IB partitioning warning
+create or replace table t1 (x int)
+with system versioning
+partition by system_time limit 1 (
+partition p0 history,
+partition pn current);
+alter table t1 change x big int;
+create or replace table t1 (i int) engine myisam partition by hash(i) partitions 2;
+alter table t1 add partition (partition px history);
+ERROR HY000: Wrong partitioning type, expected type: `SYSTEM_TIME`
+## INSERT, UPDATE, DELETE
+create or replace table t1 (x int)
+with system versioning
+partition by system_time (
+partition p0 history,
+partition pn current);
+set @now= now(6);
+insert into t1 values (1);
+set @str= concat('select x, row_start < @now as A, row_end > @now as B from t1 partition (p0)');
+prepare select_p0 from @str;
+set @str= concat('select x, row_start > @now as C, row_end = timestamp\'2038-01-19 03:14:07.999999\' as D from t1 partition (pn)');
+prepare select_pn from @str;
+execute select_p0;
+x A B
+execute select_pn;
+x C D
+1 1 1
+## pruning check
+explain partitions select * from tN;
+id select_type table partitions type possible_keys key key_len ref rows Extra
+N SIMPLE tN pn system NULL NULL NULL NULL N
+set @str= concat('select row_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 row_start from t1 partition (p0) into @ts1');
+prepare stmt from @str;
+execute stmt;
+drop prepare stmt;
+select @ts0 = @ts1;
+@ts0 = @ts1
+1
+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 row_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 row_start from t1 partition (p0) where x = 2 into @ts1');
+prepare stmt from @str;
+execute stmt;
+drop prepare stmt;
+set @str= concat('select row_end from t1 partition (p0) where x = 2 into @ts2');
+prepare stmt from @str;
+execute stmt;
+drop prepare stmt;
+set @str= concat('select row_start from t1 partition (pn) into @ts3');
+prepare stmt from @str;
+execute stmt;
+drop prepare stmt;
+select @ts0 = @ts1;
+@ts0 = @ts1
+1
+select @ts2 = @ts3;
+@ts2 = @ts3
+1
+## rotation by LIMIT
+create or replace table t1 (x int)
+with system versioning
+partition by system_time limit 0 (
+partition p0 history,
+partition p1 history,
+partition pn current);
+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 2 (
+partition p0 history,
+partition p1 history,
+partition pn current);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `x` int(11) DEFAULT NULL
+) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+ PARTITION BY SYSTEM_TIME LIMIT 2
+(PARTITION `p0` HISTORY ENGINE = DEFAULT_ENGINE,
+ PARTITION `p1` HISTORY ENGINE = DEFAULT_ENGINE,
+ PARTITION `pn` CURRENT ENGINE = DEFAULT_ENGINE)
+alter table t1 drop partition non_existent;
+ERROR HY000: Error in list of partitions to DROP
+insert into t1 values (1), (2), (3);
+select * from t1 partition (pn);
+x
+1
+2
+3
+### warn about partition switching
+delete from t1;
+Warnings:
+Note 4114 Versioned table `test`.`t1`: switching from partition `p0` to `p1`
+select * from t1 partition (p0);
+x
+1
+2
+select * from t1 partition (p1);
+x
+3
+insert into t1 values (4), (5);
+### warn about full partition
+delete from t1;
+Warnings:
+Warning 4112 Versioned table `test`.`t1`: partition `p1` is full, add more HISTORY partitions
+select * from t1 partition (p1) order by x;
+x
+3
+4
+5
+### Assertion in ALTER on warning from partitioning LIMIT [#446]
+create or replace table t1 (x int) with system versioning;
+insert into t1 values (1), (2);
+delete from t1;
+alter table t1 partition by system_time limit 1 (
+partition p1 history,
+partition pn current);
+Warnings:
+Note 4112 Versioned table `test`.`t1`: partition `p1` is full, add more HISTORY partitions
+## rotation by INTERVAL
+create or replace table t1 (x int)
+with system versioning
+partition by system_time interval 0 second (
+partition p0 history,
+partition p1 history,
+partition pn current);
+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 history,
+partition p1 history,
+partition pn current);
+insert into t1 values (1), (2), (3);
+select * from t1 partition (pn);
+x
+1
+2
+3
+delete from t1;
+select * from t1 partition (p0);
+x
+1
+2
+3
+insert into t1 values (4);
+delete from t1;
+Warnings:
+Note 4114 Versioned table `test`.`t1`: switching from partition `p0` to `p1`
+select * from t1 partition (p1);
+x
+4
+## Subpartitions
+create or replace table t1 (x int)
+with system versioning
+partition by system_time limit 2
+subpartition by key (x)
+subpartitions 2 (
+partition p0 history,
+partition p1 history,
+partition pn current);
+insert into t1 (x) values (1), (2), (3), (4), (5);
+select * from t1 partition (pnsp0);
+x
+1
+3
+5
+select * from t1 partition (pnsp1);
+x
+2
+4
+### warn about partition switching and about full partition
+delete from t1;
+Warnings:
+Note 4114 Versioned table `test`.`t1`: switching from partition `p0` to `p1`
+Warning 4112 Versioned table `test`.`t1`: partition `p1` is full, add more HISTORY partitions
+select * from t1 partition (p0sp0);
+x
+1
+3
+select * from t1 partition (p0sp1);
+x
+select * from t1 partition (p1sp0);
+x
+5
+select * from t1 partition (p1sp1);
+x
+2
+4
+create or replace table t1 (a bigint)
+with system versioning
+partition by range (a)
+(partition p0 values less than (20) engine innodb,
+partition p1 values less than maxvalue engine innodb);
+insert into t1 values (1);
+create or replace table t1 (
+f_int1 integer default 0
+) with system versioning
+partition by range(f_int1)
+subpartition by hash(f_int1)
+( partition part1 values less than (1000)
+(subpartition subpart11 storage engine = 'innodb',
+subpartition subpart12 storage engine = 'innodb'));
+insert into t1 values (1);
+create or replace table t1 (i int) engine=innodb partition by key(i);
+alter table t1 add system versioning;
+insert into t1 values();
+# MDEV-14722 Assertion in ha_commit_trans for sub-statement
+create or replace table t1 (i int) with system versioning
+partition by system_time interval 1 day (
+partition p1 history,
+partition pc current);
+create or replace table t2 (f int);
+create or replace trigger tr before insert on t2
+for each row select table_rows from information_schema.tables
+where table_name = 't1' into @a;
+insert into t2 values (1);
+# MDEV-14740 Locking assertion for system_time partitioning
+create or replace table t1 (i int) with system versioning
+partition by system_time interval 1 week (
+partition p1 history,
+partition pn current);
+create or replace table t2 (f int);
+create or replace trigger tr before insert on t2
+for each row select count(*) from t1 into @a;
+insert into t2 values (1);
+# MDEV-14741 Assertion `(trx)->start_file == 0' failed in row_truncate_table_for_mysql()
+create or replace table t1 (i int) with system versioning
+partition by system_time interval 1 hour (
+partition p1 history,
+partition pn current);
+set autocommit= off;
+truncate table t1;
+set autocommit= on;
+# MDEV-14747 ALTER PARTITION BY SYSTEM_TIME after LOCK TABLES
+create or replace table t1 (x int) with system versioning;
+lock table t1 write;
+alter table t1 partition by system_time interval 1 week (
+partition p1 history,
+partition pn current);
+unlock tables;
+# MDEV-14748 Assertion in ha_myisammrg::attach_children()
+create or replace table t1 (x int) engine=myisam with system versioning
+partition by system_time interval 1 month (partition p1 history, partition pn current);
+create or replace table t2 (x int) engine=myisam;
+create or replace table t3 (x int) engine=merge union=(t2);
+create or replace table t4 (x int) engine=myisam;
+create or replace trigger tr after insert on t4 for each row insert into t2
+( select x from t3 ) union ( select x from t1 );
+insert into t4 values (1);
+# MDEV-14821 Assertion failure
+create or replace table t1 (x int) with system versioning;
+insert into t1 values (0), (1);
+update t1 set x= x + 1;
+alter table t1 partition by system_time limit 1 (
+partition p1 history,
+partition p2 history,
+partition pn current);
+Warnings:
+Note 4114 Versioned table `test`.`t1`: switching from partition `p1` to `p2`
+delete from t1 where x = 1;
+Warnings:
+Warning 4112 Versioned table `test`.`t1`: partition `p2` is full, add more HISTORY partitions
+delete from t1 where x = 2;
+Warnings:
+Warning 4112 Versioned table `test`.`t1`: partition `p2` is full, add more HISTORY partitions
+# Test cleanup
+drop database test;
+create database test;
diff --git a/mysql-test/suite/versioning/r/replace.result b/mysql-test/suite/versioning/r/replace.result
new file mode 100644
index 00000000000..94302c1adf4
--- /dev/null
+++ b/mysql-test/suite/versioning/r/replace.result
@@ -0,0 +1,10 @@
+call create_table('t', 'x int');
+insert t values (1, 2);
+replace t values (1, 3);
+select *, current_row(row_end) as current from t for system_time all
+order by x;
+id x current
+1 2 0
+1 3 1
+drop database test;
+create database test;
diff --git a/mysql-test/suite/versioning/r/rpl.result b/mysql-test/suite/versioning/r/rpl.result
new file mode 100644
index 00000000000..b91c8fd33c8
--- /dev/null
+++ b/mysql-test/suite/versioning/r/rpl.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/select.result b/mysql-test/suite/versioning/r/select.result
new file mode 100644
index 00000000000..4e5d6f65e20
--- /dev/null
+++ b/mysql-test/suite/versioning/r/select.result
@@ -0,0 +1,446 @@
+create or replace table t1 (
+x int unsigned,
+y int unsigned,
+sys_trx_start SYS_DATATYPE as row start invisible,
+sys_trx_end SYS_DATATYPE as row end invisible,
+period for system_time (sys_trx_start, sys_trx_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);
+set @t0= now(6);
+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;
+select x, y from t1;
+x y
+0 100
+1 101
+2 102
+4 104
+5 105
+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
+2 102
+3 103
+4 104
+5 105
+6 106
+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
+2 102
+3 103
+4 104
+5 105
+6 106
+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
+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
+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
+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;
+explain extended select * from (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 as t;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where; Using join buffer (flat, BNL join)
+Warnings:
+Note 1003 select `test`.`t1`.`x` AS `IJ2_x1`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME ALL join `test`.`t2` FOR SYSTEM_TIME ALL where `test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t1`.`row_end` > <cache>(cast(@`t0` as datetime(6))) and `test`.`t1`.`row_start` <= <cache>(cast(@`t0` as datetime(6))) and `test`.`t2`.`row_end` > <cache>(cast(@`t0` as datetime(6))) and `test`.`t2`.`row_start` <= <cache>(cast(@`t0` as datetime(6)))
+explain extended select * from (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 as t;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (flat, BNL join)
+Warnings:
+Note 1003 select `test`.`t1`.`x` AS `LJ2_x1`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME ALL left join `test`.`t2` FOR SYSTEM_TIME ALL on(`test`.`t2`.`x` = `test`.`t1`.`x` and `test`.`t1`.`row_end` > <cache>(cast(@`t0` as datetime(6))) and `test`.`t1`.`row_start` <= <cache>(cast(@`t0` as datetime(6))) and `test`.`t2`.`row_end` > <cache>(cast(@`t0` as datetime(6))) and `test`.`t2`.`row_start` <= <cache>(cast(@`t0` as datetime(6)))) where 1
+explain extended select * from (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 as t;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where; Using join buffer (flat, BNL join)
+Warnings:
+Note 1003 select `test`.`t1`.`x` AS `RJ2_x1`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t2` FOR SYSTEM_TIME ALL left join `test`.`t1` FOR SYSTEM_TIME ALL on(`test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t1`.`row_end` > <cache>(cast(@`t0` as datetime(6))) and `test`.`t1`.`row_start` <= <cache>(cast(@`t0` as datetime(6))) and `test`.`t2`.`row_end` > <cache>(cast(@`t0` as datetime(6))) and `test`.`t2`.`row_start` <= <cache>(cast(@`t0` as datetime(6)))) where 1
+select * from (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 as t;
+IJ2_x1 y1 x2 y2
+1 1 1 2
+1 2 1 2
+1 3 1 2
+select * from (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 as t;
+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 * from (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 as t;
+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;
+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: Table `t1` is not system-versioned
+create or replace table t1 (x int) with system versioning;
+insert into t1 values (1);
+select * from t1 for system_time all for update;
+x
+1
+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.row_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 for system_time all;
+x y
+1 1
+2 1
+select * from (select * from t1 for system_time all, t2 for system_time all)
+for system_time all as t;
+ERROR HY000: Table `t` is not system-versioned
+# TRANSACTION/TIMESTAMP specifier in SYSTEM_TIME [MDEV-14645, Issue #396]
+create or replace table t1 (x int) with system versioning engine myisam;
+select * from t1 for system_time as of transaction 1;
+ERROR HY000: Transaction system versioning for `t1` is not supported
+create or replace table t1 (
+x int,
+sys_trx_start bigint unsigned as row start invisible,
+sys_trx_end bigint unsigned as row end invisible,
+period for system_time (sys_trx_start, sys_trx_end)
+) with system versioning engine innodb;
+insert into t1 values (1);
+set @ts= now(6);
+delete from t1;
+select sys_trx_start from t1 for system_time all into @trx_start;
+## ensure @trx_start is much lower than unix timestamp
+select @trx_start < unix_timestamp(@ts) - 100 as trx_start_good;
+trx_start_good
+1
+## TIMESTAMP specifier
+select x from t1 for system_time as of timestamp @ts;
+x
+1
+select x from t1 for system_time as of timestamp unix_timestamp(@ts);
+x
+1
+select x from t1 for system_time as of timestamp @trx_start;
+x
+set @ts= timestamp'1-1-1 0:0:0';
+## TRANSACTION specifier
+select x from t1 for system_time as of transaction @ts;
+x
+select x from t1 for system_time as of transaction unix_timestamp(@ts);
+x
+select x from t1 for system_time as of transaction @trx_start;
+x
+1
+## no specifier (auto-detection)
+select x from t1 for system_time as of @ts;
+x
+select x from t1 for system_time as of unix_timestamp(@ts);
+x
+select x from t1 for system_time as of @trx_start;
+x
+1
+### Issue #365, bug 4 (related to #226, optimized fields)
+create or replace table t1 (i int, b int) with system versioning;
+insert into t1 values (0, 0), (0, 0);
+select min(i) over (partition by b) as f
+from (select i + 0 as i, b from t1) as tt
+order by i;
+f
+0
+0
+### Issue #365, bug 5 (dangling AND)
+create or replace table t1 (a int);
+create or replace table t2 (b int) with system versioning;
+select * from t1
+where exists (select 1 from t2 where t2.b = t1.a and t2.b = t1.a);
+a
+### Issue #365, bug 9 (not a derived subquery)
+create or replace table t1 (x int) with system versioning;
+select t1.x in (select x from t1) a from t1, (select x from t1) b;
+a
+### Issue #365, bug 10 (WHERE cond freed prematurely for PS)
+create or replace table t1 (x int) with system versioning;
+insert into t1 values (1);
+create or replace view v1 as select x from t1 where x = 1;
+prepare stmt from "
+select x from t1 where x in (select x from v1);";
+execute stmt;
+x
+1
+execute stmt;
+x
+1
+### Issue #365, bug 11 (WHERE cond not top level item)
+create or replace table t1 (a int, b int, key idx(a)) with system versioning;
+insert into t1 values (1, 1), (2, 2);
+select * from t1 where (a, 2) in ((1, 1), (2, 2)) and b = 1;
+a b
+### Issue #398, NOW is now non-magic
+create or replace table t1 (x int) with system versioning;
+select * from t1 for system_time as of current_timestamp;
+x
+select * from t1 for system_time as of now;
+ERROR 42S22: Unknown column 'now' in 'where clause'
+### Issue #405, NATURAL JOIN failure
+create or replace table t1 (a int) with system versioning;
+create or replace table t2 (b int);
+create or replace view v1 as select a, row_start, row_end from t1 where a > round(rand()*1000);
+select * from v1 natural join t2;
+a b
+### Issue #406, MDEV-14633 Assertion on TRT read
+create or replace table t1 (pk int primary key, i int, t time, key (i)) with system versioning;
+insert into t1 values (1, 10, '15:01:53'), (2, 20, '00:00:00');
+delete from t1;
+select * from t1 where t = '00:00:00' and i > 0 and row_end <> '2012-12-12 00:00:00';
+pk i t
+drop view v1;
+drop table t1, t2;
+call verify_vtq_dummy(34);
+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
+28 1 1 1 1
+29 1 1 1 1
+30 1 1 1 1
+31 1 1 1 1
+32 1 1 1 1
+33 1 1 1 1
+34 1 1 1 1
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..6bfe26d0ef7
--- /dev/null
+++ b/mysql-test/suite/versioning/r/select_sp.result
@@ -0,0 +1,369 @@
+create procedure test_01()
+begin
+declare engine varchar(255) default default_engine();
+declare sys_type varchar(255) default sys_datatype(default_engine());
+set @str= concat('
+ create table t1(
+ x int unsigned,
+ y int unsigned,
+ sys_start ', sys_type, ' as row start invisible,
+ sys_end ', sys_type, ' as row end invisible,
+ 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 '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 @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;
+else
+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;
+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(default_engine());
+set @str0= concat('(
+ x int,
+ y int,
+ sys_start ', sys_type, ' as row start invisible,
+ sys_end ', sys_type, ' as row end invisible,
+ 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 IJ2_x1,y1,x2,y2 from (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 as t;
+select LJ2_x1,y1,x2,y2 from (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 as t;
+select RJ2_x1,y1,x2,y2 from (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 as t;
+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
+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
+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
+# MDEV-14686 Server crashes in Item_field::used_tables on 2nd call of SP [#422]
+create or replace table t1 (called int, bad int) with system versioning;
+create or replace procedure bad() select * from t1 where bad in (select called from t1);
+called bad
+called bad
+called bad
+called bad
+called bad
+called bad
+called bad
+called bad
+# bad() is good.
+# MDEV-14751 Server crashes in TABLE::versioned on 2nd execution of SP [#431]
+create or replace table t1 (called_bad int);
+create or replace table t2 (b int);
+create or replace procedure bad() select * from t1 where ( 5, 6 ) in ( select b, b from t2 ) and called_bad in ( select max(b) from t2 );
+called_bad
+called_bad
+called_bad
+called_bad
+called_bad
+called_bad
+called_bad
+called_bad
+# bad() is good.
+# MDEV-14786 Server crashes in Item_cond::transform on 2nd execution of SP querying from a view [#436]
+create or replace table t1 (called_bad int) with system versioning;
+create or replace view v1 as select called_bad from t1 where called_bad < 5;
+create or replace procedure bad() select called_bad from v1;
+called_bad
+called_bad
+called_bad
+called_bad
+called_bad
+called_bad
+called_bad
+called_bad
+# bad() is good.
+# wildcard expansion on hidden fields.
+create or replace 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: Table `t1` is not system-versioned
+create or replace table t1 (x int) with system versioning;
+insert into t1 values (1);
+select * from t1 for system_time as of now() for update;
+x
+1
+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 or replace 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.row_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 for system_time all;
+x y
+1 1
+2 1
+select * from (select * from t1 for system_time all, t2 for system_time all) for system_time all as t;
+ERROR HY000: Table `t` is not system-versioned
+select * from (t1 for system_time all join t2 for system_time all) for system_time all;
+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 '' at line 1
+drop view v1;
+drop table t1, t2;
+drop procedure test_01;
+drop procedure test_02;
diff --git a/mysql-test/suite/versioning/r/simple.result b/mysql-test/suite/versioning/r/simple.result
new file mode 100644
index 00000000000..f6a1ba37f53
--- /dev/null
+++ b/mysql-test/suite/versioning/r/simple.result
@@ -0,0 +1,73 @@
+set default_storage_engine=innodb;
+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 row_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 row_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 row_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 for system_time from timestamp @ts_1 to timestamp @ts_2 e,
+dept for system_time from timestamp @ts_1 to timestamp @ts_2 d
+where d.dept_id = 10
+and d.dept_id = e.dept_id;
+emp_id dept_id name salary dept_id name
+set statement system_versioning_asof=@ts_0 for
+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
+set statement system_versioning_asof=@ts_1 for
+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
+set statement system_versioning_asof=@ts_2 for
+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 1000 10 accounting
+set statement system_versioning_asof=@ts_3 for
+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
+drop table emp, dept;
diff --git a/mysql-test/suite/versioning/r/sysvars.result b/mysql-test/suite/versioning/r/sysvars.result
new file mode 100644
index 00000000000..22f53ca6fbe
--- /dev/null
+++ b/mysql-test/suite/versioning/r/sysvars.result
@@ -0,0 +1,129 @@
+create table t (a int) with system versioning;
+insert into t values (1);
+update t set a= 2;
+show global variables like 'system_versioning_asof';
+Variable_name Value
+system_versioning_asof DEFAULT
+show variables like 'system_versioning_asof';
+Variable_name Value
+system_versioning_asof DEFAULT
+select * from t;
+a
+2
+set system_versioning_asof= '2031-1-1 0:0:0';
+show variables like 'system_versioning_asof';
+Variable_name Value
+system_versioning_asof 2031-01-01 00:00:00.000000
+select * from t;
+a
+2
+set system_versioning_asof= '2011-1-1 0:0:0';
+show variables like 'system_versioning_asof';
+Variable_name Value
+system_versioning_asof 2011-01-01 00:00:00.000000
+select * from t;
+a
+set global system_versioning_asof= 'alley';
+ERROR 42000: Variable 'system_versioning_asof' can't be set to the value of 'alley'
+set global system_versioning_asof= null;
+ERROR 42000: Variable 'system_versioning_asof' can't be set to the value of 'NULL'
+set global system_versioning_asof= 1;
+ERROR 42000: Incorrect argument type to variable 'system_versioning_asof'
+set global system_versioning_asof= 1.1;
+ERROR 42000: Incorrect argument type to variable 'system_versioning_asof'
+set system_versioning_asof= 'alley';
+ERROR 42000: Variable 'system_versioning_asof' can't be set to the value of 'alley'
+set system_versioning_asof= null;
+ERROR 42000: Variable 'system_versioning_asof' can't be set to the value of 'NULL'
+set system_versioning_asof= 1;
+ERROR 42000: Incorrect argument type to variable 'system_versioning_asof'
+set system_versioning_asof= 1.1;
+ERROR 42000: Incorrect argument type to variable 'system_versioning_asof'
+# GLOBAL @@system_versioning_asof
+set global system_versioning_asof= '1911-11-11 11:11:11.1111119';
+Warnings:
+Note 1292 Truncated incorrect datetime value: '1911-11-11 11:11:11.1111119'
+Note 1292 Truncated incorrect datetime value: '1911-11-11 11:11:11.1111119'
+show global variables like 'system_versioning_asof';
+Variable_name Value
+system_versioning_asof 1911-11-11 11:11:11.111111
+set global system_versioning_asof= '1900-01-01 00:00:00';
+show global variables like 'system_versioning_asof';
+Variable_name Value
+system_versioning_asof 1900-01-01 00:00:00.000000
+set global system_versioning_asof= 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 'system_versioning_asof';
+Variable_name Value
+system_versioning_asof 1911-11-11 11:11:11.111111
+set @ts= timestamp'1900-01-01 00:00:00';
+set global system_versioning_asof= @ts;
+show global variables like 'system_versioning_asof';
+Variable_name Value
+system_versioning_asof 1900-01-01 00:00:00.000000
+set global system_versioning_asof= default;
+select @@global.system_versioning_asof;
+@@global.system_versioning_asof
+DEFAULT
+# SESSION @@system_versioning_asof
+set system_versioning_asof= '1911-11-11 11:11:11.1111119';
+Warnings:
+Note 1292 Truncated incorrect datetime value: '1911-11-11 11:11:11.1111119'
+Note 1292 Truncated incorrect datetime value: '1911-11-11 11:11:11.1111119'
+show variables like 'system_versioning_asof';
+Variable_name Value
+system_versioning_asof 1911-11-11 11:11:11.111111
+set system_versioning_asof= '1900-01-01 00:00:00';
+show variables like 'system_versioning_asof';
+Variable_name Value
+system_versioning_asof 1900-01-01 00:00:00.000000
+set system_versioning_asof= 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 'system_versioning_asof';
+Variable_name Value
+system_versioning_asof 1911-11-11 11:11:11.111111
+set @ts= timestamp'1900-01-01 00:00:00';
+set system_versioning_asof= @ts;
+show variables like 'system_versioning_asof';
+Variable_name Value
+system_versioning_asof 1900-01-01 00:00:00.000000
+# DEFAULT: value is copied from GLOBAL to SESSION
+set global system_versioning_asof= timestamp'1911-11-11 11:11:11.111111';
+set system_versioning_asof= '1900-01-01 00:00:00';
+select @@global.system_versioning_asof != @@system_versioning_asof as different;
+different
+1
+set system_versioning_asof= default;
+select @@global.system_versioning_asof = @@system_versioning_asof as equal;
+equal
+1
+set global system_versioning_asof= DEFAULT;
+set system_versioning_asof= DEFAULT;
+select @@global.system_versioning_asof, @@system_versioning_asof;
+@@global.system_versioning_asof @@system_versioning_asof
+DEFAULT DEFAULT
+select * from t for system_time all;
+a
+2
+1
+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
+2
+1
+select * from t for system_time from '0-0-0' to current_timestamp(6);
+a
+2
+1
+select * from t for system_time between '0-0-0' and current_timestamp(6);
+a
+2
+1
+drop table t;
diff --git a/mysql-test/suite/versioning/r/truncate.result b/mysql-test/suite/versioning/r/truncate.result
new file mode 100644
index 00000000000..48b7fbbcf55
--- /dev/null
+++ b/mysql-test/suite/versioning/r/truncate.result
@@ -0,0 +1,71 @@
+create table t (a int);
+delete history from t before system_time now();
+ERROR HY000: Table `t` is not system-versioned
+create or replace table t (a int) with system versioning;
+insert into t values (1);
+update t set a=2;
+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';
+delete history from t;
+select @test from t;
+@test
+correct
+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);
+update t set a=22 where a=2;
+select * from t for system_time all;
+a
+11
+22
+1
+2
+delete history from t before system_time timestamp @ts1;
+select * from t for system_time all;
+a
+11
+22
+2
+prepare stmt from 'delete history from t';
+execute stmt;
+drop prepare stmt;
+select * from t for system_time all;
+a
+11
+22
+delete from t;
+create or replace procedure truncate_sp()
+begin
+delete history from t before system_time timestamp now(6);
+end~~
+call truncate_sp;
+select * from t for system_time all;
+a
+drop procedure truncate_sp;
+### Issue #399, truncate partitioned table is now unimplemented
+create or replace table t (a int)
+with system versioning
+engine myisam
+partition by system_time (
+partition p0 history,
+partition pn current);
+delete history from t;
+ERROR 42000: The used command is not allowed with this MariaDB version
+create or replace table t (i int) with system versioning;
+delete history from t;
+create or replace view v as select * from t;
+delete history from v;
+ERROR HY000: DELETE HISTORY from VIEW is prohibited
+create or replace table t (i int);
+delete history from t;
+ERROR HY000: Table `t` is not system-versioned
+create or replace view v as select * from t;
+delete history from v;
+ERROR HY000: DELETE HISTORY from VIEW is prohibited
+prepare stmt from 'delete history from t';
+ERROR HY000: Table `t` is not system-versioned
+drop table t;
+drop view v;
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..e378407afde
--- /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'
+delete history from mysqltest.t before system_time now();
+ERROR 42000: DELETE VERSIONING ROWS command denied to user 'mysqltest_1'@'localhost' for table 't'
+connection root;
+grant delete history on mysqltest.* to mysqltest_1@localhost;
+grant delete history 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'
+delete history from mysqltest.t before 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/trx_id.result b/mysql-test/suite/versioning/r/trx_id.result
new file mode 100644
index 00000000000..800d61beba7
--- /dev/null
+++ b/mysql-test/suite/versioning/r/trx_id.result
@@ -0,0 +1,96 @@
+select @@system_versioning_transaction_registry;
+@@system_versioning_transaction_registry
+0
+create or replace table t1 (
+x int,
+sys_trx_start bigint(20) unsigned as row start invisible,
+sys_trx_end bigint(20) unsigned as row end invisible,
+period for system_time (sys_trx_start, sys_trx_end)
+) with system versioning engine innodb;
+ERROR HY000: Temporal operation requires `mysql.transaction_registry` (@@system_versioning_transaction_registry).
+set global system_versioning_transaction_registry= 1;
+Warnings:
+Warning 4134 Transaction-based system versioning is EXPERIMENTAL and is subject to change in future.
+create or replace table t1 (
+x int,
+sys_trx_start bigint(20) unsigned as row start invisible,
+sys_trx_end bigint(20) unsigned as row end invisible,
+period for system_time (sys_trx_start, sys_trx_end)
+) with system versioning engine innodb;
+insert into t1 (x) values (1);
+set global system_versioning_transaction_registry= 0;
+insert into t1 (x) values (2);
+ERROR HY000: Temporal operation requires `mysql.transaction_registry` (@@system_versioning_transaction_registry).
+delete from t1;
+ERROR HY000: Temporal operation requires `mysql.transaction_registry` (@@system_versioning_transaction_registry).
+update t1 set x= 3;
+ERROR HY000: Temporal operation requires `mysql.transaction_registry` (@@system_versioning_transaction_registry).
+# ALTER ADD SYSTEM VERSIONING should write to mysql.transaction_registry
+create function check_result (cond boolean)
+returns char(50) deterministic
+return if(cond = 1, '[CORRECT]', '[INCORRECT]');
+set @@system_versioning_alter_history=keep;
+set global system_versioning_transaction_registry=on;
+Warnings:
+Warning 4134 Transaction-based system versioning is EXPERIMENTAL and is subject to change in future.
+create or replace table t1 (x int) engine innodb;
+insert into t1 values (1);
+alter table t1
+add column s bigint unsigned as row start,
+add column e bigint unsigned as row end,
+add period for system_time(s, e),
+add system versioning,
+algorithm=inplace;
+select s from t1 into @trx_start;
+select check_result(count(*) = 1) from mysql.transaction_registry where transaction_id = @trx_start;
+check_result(count(*) = 1)
+[CORRECT]
+create or replace table t1 (x int) engine innodb;
+select count(*) from mysql.transaction_registry into @tmp;
+alter table t1
+add column s bigint unsigned as row start,
+add column e bigint unsigned as row end,
+add period for system_time(s, e),
+add system versioning,
+algorithm=inplace;
+select check_result(count(*) = @tmp) from mysql.transaction_registry;
+check_result(count(*) = @tmp)
+[CORRECT]
+create or replace table t1 (x int) engine innodb;
+insert into t1 values (1);
+alter table t1
+add column s bigint unsigned as row start,
+add column e bigint unsigned as row end,
+add period for system_time(s, e),
+add system versioning,
+algorithm=copy;
+select s from t1 into @trx_start;
+select check_result(count(*) = 1) from mysql.transaction_registry where transaction_id = @trx_start;
+check_result(count(*) = 1)
+[CORRECT]
+create or replace table t1 (x int) engine innodb;
+select count(*) from mysql.transaction_registry into @tmp;
+alter table t1
+add column s bigint unsigned as row start,
+add column e bigint unsigned as row end,
+add period for system_time(s, e),
+add system versioning,
+algorithm=copy;
+select check_result(count(*) = @tmp) from mysql.transaction_registry;
+check_result(count(*) = @tmp)
+[CORRECT]
+# TRX_ID to TIMESTAMP versioning switch
+create or replace table t1 (
+x int,
+sys_start bigint unsigned as row start invisible,
+sys_end bigint unsigned as row end invisible,
+period for system_time (sys_start, sys_end)
+) engine innodb with system versioning;
+insert into t1 values (1);
+alter table t1 drop column sys_start, drop column sys_end;
+select sys_end = 18446744073709551615 as transaction_based from t1 for system_time all;
+transaction_based
+1
+drop table t1;
+set global system_versioning_transaction_registry=off;
+drop function check_result;
diff --git a/mysql-test/suite/versioning/r/update.result b/mysql-test/suite/versioning/r/update.result
new file mode 100644
index 00000000000..08be6825b7f
--- /dev/null
+++ b/mysql-test/suite/versioning/r/update.result
@@ -0,0 +1,627 @@
+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_trx_start ', sys_type, ' as row start invisible,
+ sys_trx_end ', sys_type, ' as row end invisible,
+ period for system_time (sys_trx_start, sys_trx_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,
+ x int,
+ y int without system versioning,
+ sys_trx_start ', sys_type, ' as row start invisible,
+ sys_trx_end ', sys_type, ' as row end invisible,
+ period for system_time (sys_trx_start, sys_trx_end))
+ 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 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 y= 1 where id = 1;
+select @tmp1 = sys_trx_start as A2, x 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,
+ sys_trx_start bigint unsigned as row start invisible,
+ sys_trx_end bigint unsigned as row end invisible,
+ period for system_time (sys_trx_start, sys_trx_end)
+ ) 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), (4, 1), (5, 1);
+start transaction;
+update t1 set y= y + 1 where x = 3;
+update t1 set y= y + 1 where x = 2;
+update t1 set y= y + 1 where x = 3;
+update t1 set y= y + 1 where x > 3;
+update t1 set y= y + 1 where x > 4;
+commit;
+select x, y, sys_trx_end = 18446744073709551615 as current from t1 for system_time all;
+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,
+ sys_trx_start ', sys_type, ' as row start invisible,
+ sys_trx_end ', sys_type, ' as row end invisible,
+ period for system_time (sys_trx_start, sys_trx_end))
+ 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,
+ sys_trx_end ', sys_type, ' as row end invisible,
+ sys_trx_start ', sys_type, ' as row start invisible,
+ y int unsigned,
+ period for system_time (sys_trx_start, sys_trx_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),
+(3, 3000),
+(4, 4000),
+(5, 5000);
+insert into t1(x, y) values(3, 3000) 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 all;
+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_trx_start ', sys_type, ' as row start invisible,
+ sys_trx_end ', sys_type, ' as row end invisible,
+ period for system_time (sys_trx_start, sys_trx_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 without system versioning,
+ name varchar(128),
+ salary bigint without system versioning,
+ sys_trx_start ', sys_type, ' as row start invisible,
+ sys_trx_end ', sys_type, ' as row end invisible,
+ period for system_time (sys_trx_start, sys_trx_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 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_trx_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('timestamp(6)', 'innodb', 'vtq_commit_ts(sys_trx_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', 'vtq_commit_ts(sys_trx_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 verify_vtq;
+No A B C D
+1 1 1 1 1
+2 1 1 1 1
+call test_02('timestamp(6)', 'myisam', 'sys_trx_end');
+A1 x y
+1 11 11
+A2 x
+1 11
+call test_02('timestamp(6)', 'innodb', 'vtq_commit_ts(sys_trx_end)');
+A1 x y
+1 11 11
+A2 x
+1 11
+call test_02('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_trx_end)');
+A1 x y
+1 11 11
+A2 x
+1 11
+call verify_vtq;
+No A B C D
+1 1 1 1 1
+2 1 1 1 1
+# Multiple UPDATE of same rows in single transaction create historical
+# rows only once (applicable to transaction-based only).
+call test_03('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_trx_end)');
+x y current
+1 1 1
+2 2 1
+3 3 1
+4 2 1
+5 3 1
+3 1 0
+2 1 0
+4 1 0
+5 1 0
+call verify_vtq;
+No A B C D
+1 1 1 1 1
+2 1 1 1 1
+call test_04('timestamp(6)', 'myisam', 'sys_trx_end');
+x
+x
+1
+x
+2
+x
+3
+call test_04('timestamp(6)', 'innodb', 'vtq_commit_ts(sys_trx_end)');
+x
+x
+1
+x
+2
+x
+3
+call test_04('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_trx_end)');
+x
+x
+1
+x
+2
+x
+3
+call verify_vtq;
+No A B C D
+1 1 1 1 1
+2 1 1 1 1
+3 1 1 1 1
+call test_05('timestamp(6)', 'myisam', 'sys_trx_end');
+x y
+1 1000
+3 3000
+3 3001
+4 4000
+4 4444
+5 5000
+x y
+1 1000
+3 3001
+4 4000
+4 4444
+5 5000
+call test_05('timestamp(6)', 'innodb', 'vtq_commit_ts(sys_trx_end)');
+x y
+1 1000
+3 3000
+3 3001
+4 4000
+4 4444
+5 5000
+x y
+1 1000
+3 3001
+4 4000
+4 4444
+5 5000
+call test_05('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_trx_end)');
+x y
+1 1000
+3 3000
+3 3001
+4 4000
+4 4444
+5 5000
+x y
+1 1000
+3 3001
+4 4000
+4 4444
+5 5000
+call verify_vtq;
+No A B C D
+1 1 1 1 1
+2 1 1 1 1
+3 1 1 1 1
+call test_06('timestamp(6)', 'myisam', 'sys_trx_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('timestamp(6)', 'innodb', 'vtq_commit_ts(sys_trx_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', 'vtq_commit_ts(sys_trx_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 verify_vtq;
+No A B C D
+1 1 1 1 1
+2 1 1 1 1
+3 1 1 1 1
+# Optimized fields
+call test_07('timestamp(6)', 'myisam', 'sys_trx_end');
+A1 name
+1 Jerry
+A2 name
+1 Jerry
+B1 salary
+1 2500
+B2 salary
+1 2500
+call test_07('timestamp(6)', 'innodb', 'vtq_commit_ts(sys_trx_end)');
+A1 name
+1 Jerry
+A2 name
+1 Jerry
+B1 salary
+1 2500
+B2 salary
+1 2500
+call test_07('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_trx_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
+### Issue #365, bug 7 (duplicate of historical row)
+set timestamp= 1000000019;
+create or replace table t1 (a int primary key, b int)
+with system versioning engine myisam;
+insert into t1 (a) values (1);
+update t1 set b= 2;
+insert into t1 (a) values (1) on duplicate key update a= 2;
+ERROR 23000: Duplicate entry '1-2001-09-09 01:46:59.000000' for key 'PRIMARY'
+drop database test;
+create database 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..0dc28c230c2
--- /dev/null
+++ b/mysql-test/suite/versioning/r/view.result
@@ -0,0 +1,120 @@
+create or replace table t1 (x int) with system versioning;
+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 or replace 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 or replace view vt2 as select *, row_end from t1 for system_time as of timestamp '", @t2, "'");
+prepare stmt from @vt2;
+execute stmt;
+drop prepare stmt;
+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` FOR SYSTEM_TIME ALL where `t1`.`row_end` = MAX_RESULT latin1 latin1_swedish_ci
+drop view vt1;
+drop view vt2;
+create or replace view vt1 as select * from t1 for system_time all;
+select * from vt1;
+x
+2
+1
+prepare stmt from 'select * from vt1';
+execute stmt;
+x
+2
+1
+drop prepare stmt;
+set @str= concat('create or replace view vt1 as
+select * from t1 for system_time as of timestamp "', @t1, '"');
+prepare stmt from @str;
+execute stmt;
+drop prepare stmt;
+select * from t1 for system_time as of timestamp @t1;
+x
+1
+select * from vt1;
+x
+1
+insert into vt1 values (3);
+select * from t1;
+x
+3
+select * from vt1;
+x
+1
+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;
+select * from vt1;
+x
+1
+2
+# VIEW with parameters [#151]
+create or replace table t1 (x int) with system versioning;
+create or replace view vt1(c) as select x 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 `c` from `t1` FOR SYSTEM_TIME ALL where `t1`.`row_end` = MAX_RESULT latin1 latin1_swedish_ci
+# VIEW over JOIN of versioned tables [#153]
+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
+# VIEW improvements [#183]
+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` from ((`t1` FOR SYSTEM_TIME ALL join `t2` FOR SYSTEM_TIME ALL) join `t3`) where `t1`.`row_end` = MAX_RESULT and `t2`.`row_end` = MAX_RESULT 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` from ((`t3` join `t2` FOR SYSTEM_TIME ALL) join `t1` FOR SYSTEM_TIME ALL) where `t2`.`row_end` = MAX_RESULT and `t1`.`row_end` = MAX_RESULT latin1 latin1_swedish_ci
+create or replace view vt1 as select a, t2.row_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`.`row_end` AS `endo` from ((`t3` join `t1` FOR SYSTEM_TIME ALL) join `t2` FOR SYSTEM_TIME ALL) where `t1`.`row_end` = MAX_RESULT and `t2`.`row_end` = MAX_RESULT latin1 latin1_swedish_ci
+# VIEW over UNION [#269]
+create or replace view vt1 as select * from t1 union select * from t1;
+select * from vt1;
+a
+1
+# VIEW over UNION with non-versioned [#393]
+create or replace table t2 (a int);
+create or replace view vt1 as select * from t1 union select * from t2;
+select * from vt1;
+a
+1
+# MDEV-14689 crash on second PS execute
+create or replace table t1 (a int);
+create or replace view v1 as select * from t1;
+create or replace table t2 (b int) with system versioning;
+prepare stmt from 'select a from v1 inner join t2 group by a order by a';
+execute stmt;
+a
+execute stmt;
+a
+drop database test;
+create database test;
diff --git a/mysql-test/suite/versioning/r/vtmd.result b/mysql-test/suite/versioning/r/vtmd.result
new file mode 100644
index 00000000000..ece5f5af61a
--- /dev/null
+++ b/mysql-test/suite/versioning/r/vtmd.result
@@ -0,0 +1,365 @@
+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, '
+ 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;
+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 with system versioning as
+ 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;
+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~~
+create or replace procedure show_tables()
+begin
+show tables;
+select table_name, table_schema from information_schema.tables
+where table_schema not in ('mysql', 'performance_schema', 'information_schema', 'mtr')
+order by table_name;
+end~~
+set versioning_alter_history= keep;
+create table t0 (z int) with system versioning;
+show tables;
+Tables_in_test
+t0
+set versioning_alter_history= survive;
+create or replace table t0 (y 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 current lifetime period',
+ `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_alter_history= keep;
+drop table t0;
+set versioning_alter_history= survive;
+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;
+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
+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;
+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_alter_history= keep;
+drop tables t0, t0_vtmd;
+set versioning_alter_history= survive;
+set versioning_alter_history= keep;
+create or replace table x0 (x int) with system versioning;
+set versioning_alter_history= survive;
+rename table x0 to d0;
+show tables;
+Tables_in_test
+d0
+set versioning_alter_history= keep;
+drop table d0;
+set versioning_alter_history= survive;
+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_alter_history= keep;
+drop table d0;
+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!
+show tables;
+Tables_in_test
+d0_vtmd
+x0
+x0_vtmd
+drop table x0_vtmd;
+rename table x0 to d0;
+Warnings:
+Warning 4122 `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_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
+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
+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
+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
+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
+t0_TIMESTAMP_SUFFIX test
+t0_TIMESTAMP_SUFFIX test
+t0_TIMESTAMP_SUFFIX test
+t0_TIMESTAMP_SUFFIX test
+t1_TIMESTAMP_SUFFIX db1
+t2 test
+t2_vtmd test
+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 4122 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;
+create database test;
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..4c77182c5de
--- /dev/null
+++ b/mysql-test/suite/versioning/r/vtmd_show.result
@@ -0,0 +1,229 @@
+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, '
+ 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;
+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 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;
+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: Table 'test.t' doesn't exist
+show create table t for system_time as of timestamp '01-01-2020';
+ERROR HY000: VTMD error: Table 'test.t' doesn't exist
+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/alter.test b/mysql-test/suite/versioning/t/alter.test
new file mode 100644
index 00000000000..8fb21dcb1eb
--- /dev/null
+++ b/mysql-test/suite/versioning/t/alter.test
@@ -0,0 +1,408 @@
+select @@system_versioning_alter_history;
+
+create table t(
+ a int
+);
+show create table t;
+--error ER_VERS_NOT_VERSIONED
+alter table t drop system versioning;
+
+alter table t add system versioning;
+show create table t;
+
+--error ER_VERS_ALTER_NOT_ALLOWED
+alter table t add column y int;
+--error ER_VERS_ALTER_ENGINE_PROHIBITED
+alter table t engine innodb;
+
+alter table t drop system versioning;
+show create table t;
+
+set system_versioning_alter_history= keep;
+
+--error ER_VERS_FIELD_WRONG_TYPE
+alter table t
+ add column trx_start bigint(20) unsigned as row start invisible,
+ add column trx_end bigint(20) unsigned as row end invisible,
+ add period for system_time(trx_start, trx_end),
+ add system versioning;
+
+--error ER_VERS_FIELD_WRONG_TYPE
+alter table t
+ add column trx_start timestamp as row start invisible,
+ add column trx_end timestamp as row end invisible,
+ add period for system_time(trx_start, trx_end),
+ add system versioning;
+
+--error ER_PARSE_ERROR
+alter table t
+ add column trx_start timestamp(6) not null as row start invisible,
+ add column trx_end timestamp(6) not null as row end invisible,
+ add period for system_time(trx_start, trx_end),
+ add system versioning;
+
+alter table t
+ add column trx_start timestamp(6) as row start invisible,
+ add column trx_end timestamp(6) as row end invisible,
+ add period for system_time(trx_start, trx_end),
+ add system versioning;
+show create table t;
+
+alter table t drop column trx_start, drop column trx_end;
+alter table t drop system versioning;
+show create table t;
+
+alter table t add 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;
+
+alter table t drop column a;
+show create table t;
+
+create or replace table t (
+ a int,
+ row_start timestamp(6) as row start invisible,
+ row_end timestamp(6) as row end invisible,
+ period for system_time(row_start, row_end))
+with system versioning;
+
+select * from t for system_time all;
+alter table t drop column row_start;
+alter table t drop column row_end;
+select * from t for system_time all;
+
+--error ER_CANT_DROP_FIELD_OR_KEY
+alter table t drop column row_start;
+--error ER_CANT_DROP_FIELD_OR_KEY
+alter table t drop column row_end;
+
+create or replace table t (
+ a int,
+ row_start timestamp(6) as row start invisible,
+ row_end timestamp(6) as row end invisible,
+ period for system_time(row_start, row_end))
+with system versioning;
+
+select * from t for system_time all;
+alter table t drop column row_start, drop column row_end;
+select * from t for system_time all;
+
+create or replace table t(
+ a int
+);
+insert into t values(1);
+alter table t add 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 row_start from t where a=3 into @tm;
+alter table t add column b int;
+select @tm=row_start from t where a=3;
+show create table t;
+select * from t;
+select * from t for system_time all;
+
+alter table t drop system versioning;
+select * from t;
+show create table t;
+
+--error ER_VERS_NOT_VERSIONED
+alter table t modify a int with system versioning;
+--error ER_VERS_NOT_VERSIONED
+alter table t modify a int without system versioning;
+
+alter table t add 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;
+
+# TODO: move TRX_ID cases to separate test
+-- source suite/versioning/common.inc
+create or replace table t(
+ a int
+) engine=innodb;
+
+alter table t
+ add column trx_start timestamp(6) as row start invisible,
+ add column trx_end timestamp(6) as row end invisible,
+ add period for system_time(trx_start, trx_end),
+ add system versioning;
+
+show create table t;
+--echo # Issue #211: drop of system columns required before drop system versioning
+alter table t drop column trx_start, drop column trx_end;
+show create table t;
+
+alter table t drop system versioning;
+
+insert into t values(1);
+
+call verify_vtq;
+alter table t
+ add column trx_start bigint(20) unsigned as row start invisible,
+ add column trx_end bigint(20) unsigned as row end invisible,
+ add period for system_time(trx_start, trx_end),
+ add system versioning;
+call verify_vtq;
+
+show create table t;
+alter table t drop column trx_start, drop column trx_end;
+
+call verify_vtq;
+alter table t drop system versioning, algorithm=copy;
+call verify_vtq;
+
+alter table t add system versioning, algorithm=copy;
+call verify_vtq;
+
+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;
+call verify_vtq;
+
+alter table t drop column b, algorithm=copy;
+show create table t;
+select * from t for system_time all;
+call verify_vtq;
+
+## FIXME: #414 IB: inplace for VERS_TIMESTAMP versioning
+if (0)
+{
+alter table t drop system versioning, algorithm=inplace;
+call verify_vtq;
+
+alter table t add system versioning, algorithm=inplace;
+call verify_vtq;
+show create table t;
+
+update t set a= 1;
+select * from t for system_time all;
+call verify_vtq;
+
+alter table t add column b int, algorithm=inplace;
+show create table t;
+select * from t;
+call verify_vtq;
+
+alter table t drop column b, algorithm=inplace;
+show create table t;
+select * from t for system_time all;
+}
+## FIXME END
+
+alter table t drop system versioning, algorithm=copy;
+show create table t;
+call verify_vtq;
+
+# nullable autoinc test w/o versioning
+create or replace table t (a int);
+insert t values (1),(2),(3),(4);
+alter table t add b int auto_increment null unique;
+select * from t;
+drop 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;
+--error ER_DUP_ENTRY, ER_DUP_ENTRY
+alter table t add b int not null unique;
+--error ER_UNSUPPORTED_EXTENSION, ER_UNSUPPORTED_EXTENSION
+alter table t add b int auto_increment unique;
+alter table t add b int auto_increment null unique;
+select * from t;
+select * from t for system_time all;
+insert into t values (4, 0);
+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;
+--error ER_DUP_ENTRY, ER_DUP_ENTRY
+alter table t add b int not null unique;
+--error ER_UNSUPPORTED_EXTENSION, ER_UNSUPPORTED_EXTENSION
+alter table t add b int auto_increment unique;
+alter table t add b int auto_increment null unique;
+select * from t;
+select * from t for system_time all;
+insert into t values (4, 0);
+select * from t for system_time all;
+
+create or replace table t (
+ a int,
+ row_start timestamp(6) as row start invisible,
+ row_end timestamp(6) as row end invisible,
+ period for system_time(row_start, row_end)
+) with system versioning;
+--error ER_VERS_ALTER_SYSTEM_FIELD
+alter table t change column row_start asdf timestamp(6);
+insert into t values (1);
+--error ER_VERS_ALTER_SYSTEM_FIELD
+alter table t modify column row_start bigint unsigned;
+
+create or replace table t (
+ a int,
+ row_start timestamp(6) as row start invisible,
+ row_end timestamp(6) as row end invisible,
+ period for system_time(row_start, row_end)
+) with system versioning;
+select * from t;
+
+--error ER_VERS_SYS_FIELD_EXISTS
+alter table t drop system versioning;
+alter table t drop column row_start;
+select * from t;
+
+--error ER_VERS_SYS_FIELD_EXISTS
+alter table t drop system versioning;
+alter table t drop column row_end;
+select * from t;
+
+alter table t drop system versioning;
+show create table t;
+
+
+## These experimental options are now disabled
+
+--error ER_WRONG_VALUE_FOR_VAR
+set system_versioning_alter_history= SURVIVE;
+
+--error ER_WRONG_VALUE_FOR_VAR
+set system_versioning_alter_history= DROP;
+
+if (0)
+{
+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;
+
+create or replace table non_empty (
+ a int,
+ row_start bigint(20) unsigned,
+ row_end bigint(20) unsigned
+) engine innodb;
+insert into non_empty values (1, 100, 200);
+
+--error ER_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN
+alter table non_empty
+ change column row_start row_start bigint(20) unsigned as row start invisible;
+--error ER_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN
+alter table non_empty
+ change column row_end row_end bigint(20) unsigned as row end invisible;
+drop table non_empty;
+
+create or replace table t (a int primary key) with system versioning;
+insert into t values (1);
+update t set a=2;
+alter table t drop primary key, add primary key (a), drop system versioning;
+select * from t;
+--replace_result InnoDB INNODB_OR_MYISAM MyISAM INNODB_OR_MYISAM
+show create table t;
+
+create or replace table t (a int primary key) with system versioning;
+insert into t values (1);
+update t set a=2;
+alter table t drop system versioning;
+select * from t;
+--replace_result InnoDB INNODB_OR_MYISAM MyISAM INNODB_OR_MYISAM
+show create table t;
+
+
+call verify_vtq;
+}
+
+create or replace table t (a int) with system versioning;
+--error ER_VERS_ALREADY_VERSIONED
+alter table t add system versioning;
+--error ER_VERS_ALREADY_VERSIONED
+alter table t add system versioning, drop system versioning;
+
+set @@system_versioning_alter_history=keep;
+create or replace table t(x int, y int) with system versioning engine=innodb;
+alter table t modify y int without system versioning;
+insert into t values(1, 1);
+update t set y=2;
+
+--echo # MDEV-14681 Bogus ER_UNSUPPORTED_EXTENSION
+create or replace table t1 (pk int auto_increment unique) with system versioning;
+insert into t1 values (1);
+delete from t1;
+alter table t1 engine=myisam;
+
+--echo # MDEV-14692 crash in MDL_context::upgrade_shared_lock()
+create or replace temporary table t (a int);
+--error ER_VERS_TEMPORARY
+alter table t change column if exists b c bigint unsigned generated always as row start;
+--error ER_VERS_TEMPORARY
+alter table t change column if exists b c bigint unsigned generated always as row end;
+--error ER_VERS_TEMPORARY
+alter table t add system versioning;
+drop table t;
+
+--echo # MDEV-14744 trx_id-based and transaction-based mixup in assertion
+create or replace table t (c text) engine=innodb with system versioning;
+show create table t;
+alter table t add fulltext key (c);
+
+create or replace table t (a int) with system versioning;
+--error ER_VERS_TABLE_MUST_HAVE_COLUMNS
+alter table t drop column a;
+--error ER_CANT_DROP_FIELD_OR_KEY
+alter table t drop column a, drop column a;
+
+create or replace table t1 (row_start int);
+--error ER_DUP_FIELDNAME
+alter table t1 with system versioning;
+
+create or replace table t1 (row_end int);
+--error ER_DUP_FIELDNAME
+alter table t1 with system versioning;
+
+--error ER_DUP_FIELDNAME
+create or replace table t1 (a int, row_start int) with system versioning;
+
+create or replace table t1 (a int) with system versioning;
+
+--error ER_DUP_FIELDNAME
+set statement system_versioning_alter_history=keep for
+alter table t1 add column row_start int;
+
+--error ER_DUP_FIELDNAME
+set statement system_versioning_alter_history=keep for
+alter table t1 add column row_start timestamp(6);
+
+drop database test;
+create database test;
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..6108f6d9818
--- /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, ' as row start invisible,
+ sys_end ', sys_type, ' as row end invisible,
+ 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');
+call test_01('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)');
+call verify_vtq;
+
+drop procedure test_01;
+
+-- 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
new file mode 100644
index 00000000000..66a9db64e10
--- /dev/null
+++ b/mysql-test/suite/versioning/t/commit_id.test
@@ -0,0 +1,94 @@
+-- source suite/versioning/common.inc
+
+create table t1(
+ id int auto_increment primary key,
+ sys_trx_start bigint unsigned as row start invisible,
+ sys_trx_end bigint unsigned as row end invisible,
+ period for system_time (sys_trx_start, sys_trx_end)
+)
+with system versioning
+engine innodb;
+
+
+# VTQ_TRX_ID, VTQ_COMMIT_ID, VTQ_TRX_SEES #
+
+insert into t1 values ();
+
+--real_sleep 0.01
+set @ts0= now(6);
+insert into t1 values ();
+select sys_trx_start from t1 where id = last_insert_id() into @tx0;
+select transaction_id = @tx0 from mysql.transaction_registry
+order by transaction_id desc limit 1;
+
+set @ts1= now(6);
+insert into t1 values ();
+select sys_trx_start from t1 where id = last_insert_id() into @tx1;
+select transaction_id = @tx1 from mysql.transaction_registry
+order by transaction_id desc limit 1;
+
+set @ts2= now(6);
+insert into t1 values ();
+select sys_trx_start from t1 where id = last_insert_id() into @tx2;
+select transaction_id = @tx2 from mysql.transaction_registry
+order by transaction_id desc 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;
+
+
+# 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 isolation_level = 'READ-UNCOMMITTED' from mysql.transaction_registry 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 isolation_level = 'READ-COMMITTED' from mysql.transaction_registry 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 isolation_level = 'SERIALIZABLE' from mysql.transaction_registry 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 isolation_level = 'REPEATABLE-READ' from mysql.transaction_registry where transaction_id = @tx6;
+
+
+drop table t1;
+call verify_vtq;
+
+-- source suite/versioning/common_finish.inc
diff --git a/mysql-test/suite/versioning/t/create.test b/mysql-test/suite/versioning/t/create.test
new file mode 100644
index 00000000000..f1ffd7fcf68
--- /dev/null
+++ b/mysql-test/suite/versioning/t/create.test
@@ -0,0 +1,367 @@
+--source suite/versioning/engines.inc
+--source suite/versioning/common.inc
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype_expl SYS_DATATYPE NULL ''
+eval create table t1 (
+ x1 int unsigned,
+ Sys_start $sys_datatype_expl as row start invisible comment 'start',
+ Sys_end $sys_datatype_expl as row end invisible comment 'end',
+ period for system_time (Sys_start, Sys_end)
+) with system versioning;
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype_expl SYS_DATATYPE
+show create table t1;
+
+--query_vertical select table_catalog,table_schema,table_name,table_type,version,table_rows,avg_row_length,data_free,auto_increment,check_time,table_collation,checksum,create_options,table_comment from information_schema.tables where table_name='t1'
+--query_vertical select table_catalog,table_schema,table_name,column_name,ordinal_position,column_default,character_maximum_length,character_octet_length,character_set_name,collation_name,column_key,extra,privileges,column_comment,is_generated,generation_expression from information_schema.columns where table_name='t1'
+
+--echo # Implicit fields test
+create or replace table t1 (
+ x2 int unsigned
+) with system versioning;
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE
+show create table t1;
+
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE
+--error ER_VERS_PERIOD_COLUMNS
+eval create or replace table t1 (
+ x3 int unsigned,
+ Sys_start $sys_datatype as row start invisible,
+ Sys_end $sys_datatype as row end invisible,
+ period for system_time (x, Sys_end)
+) with system versioning;
+
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE
+--error ER_VERS_PERIOD_COLUMNS
+eval create or replace table t1 (
+ x4 int unsigned,
+ Sys_start $sys_datatype as row start invisible,
+ Sys_end2 $sys_datatype as row end invisible,
+ period for system_time (Sys_start, Sys_end)
+) with system versioning;
+
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE
+--error ER_VERS_PERIOD_COLUMNS
+eval create or replace table t1 (
+ x5 int unsigned,
+ Sys_start $sys_datatype as row start invisible,
+ Sys_end $sys_datatype as row end invisible,
+ period for system_time (Sys_start, x)
+) with system versioning;
+
+--error ER_MISSING
+create or replace table t1 (
+ x6 int unsigned,
+ period for system_time (Sys_start, Sys_end)
+) with system versioning;
+
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE
+--error ER_MISSING
+eval create or replace table t1 (
+ x7 int unsigned,
+ Sys_start $sys_datatype as row start invisible,
+ Sys_end $sys_datatype as row end invisible,
+ period for system_time (Sys_start, Sys_end)
+);
+
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE
+--error ER_VERS_PERIOD_COLUMNS
+eval create or replace table t1 (
+ x8 int unsigned,
+ Sys_start $sys_datatype as row start invisible,
+ Sys_end $sys_datatype as row end invisible,
+ period for system_time (sys_insert, sys_remove)
+) with system versioning;
+
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE
+--error ER_MISSING
+eval create or replace table t1 (
+ x9 int unsigned,
+ Sys_start $sys_datatype as row start invisible,
+ Sys_end $sys_datatype as row end invisible,
+ period for system_time (Sys_start, Sys_end)
+);
+
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE
+--error ER_MISSING
+eval create or replace table t1 (
+ x10 int unsigned,
+ Sys_start $sys_datatype as row start invisible,
+ Sys_end $sys_datatype as row end invisible,
+ period for system_time (Sys_start, Sys_start)
+);
+
+--error ER_VERS_FIELD_WRONG_TYPE, ER_VERS_FIELD_WRONG_TYPE
+create or replace table t1 (
+ x11 int unsigned,
+ Sys_start bigint unsigned as row start invisible,
+ Sys_end timestamp(6) as row end invisible,
+ period for system_time (Sys_start, Sys_end)
+) with system versioning;
+
+--error ER_VERS_FIELD_WRONG_TYPE, ER_VERS_FIELD_WRONG_TYPE
+create or replace table t1 (
+ x12 int unsigned,
+ Sys_start timestamp(6) as row start invisible,
+ Sys_end bigint unsigned as row end invisible,
+ period for system_time (Sys_start, Sys_end)
+) with system versioning;
+
+--error ER_VERS_FIELD_WRONG_TYPE
+create or replace table t1 (
+ x13 int unsigned,
+ Sys_start bigint as row start invisible,
+ Sys_end bigint unsigned as row end invisible,
+ period for system_time (Sys_start, Sys_end)
+) with system versioning engine innodb;
+
+--error ER_VERS_FIELD_WRONG_TYPE
+create or replace table t1 (
+ x14 int unsigned,
+ Sys_start bigint unsigned as row start invisible,
+ Sys_end bigint as row end invisible,
+ period for system_time (Sys_start, Sys_end)
+) with system versioning engine innodb;
+
+# columns with/without system versioning
+
+create or replace table t1 (
+ x15 int with system versioning,
+ B int
+);
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE
+show create table t1;
+
+create or replace table t1 (
+ x16 int with system versioning,
+ B int
+) with system versioning;
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE
+show create table t1;
+
+create or replace table t1 (
+ x17 int,
+ B int without system versioning
+);
+
+create or replace table t1 (
+ x18 int,
+ B int without system versioning
+) with system versioning;
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE
+show create table t1;
+
+create or replace table t1 (
+ x19 int with system versioning,
+ B int without system versioning
+);
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE
+show create table t1;
+
+create or replace table t1 (
+ x20 int with system versioning,
+ B int without system versioning
+) with system versioning;
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE
+show create table t1;
+
+create or replace table t1 (
+ x21 int without system versioning
+);
+
+--error ER_VERS_TABLE_MUST_HAVE_COLUMNS
+create or replace table t1 (
+ x22 int without system versioning
+) with system versioning;
+
+# CREATE TABLE ... LIKE
+create or replace table t1 (a int) with system versioning;
+create table tt1 like t1;
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE
+show create table tt1;
+drop table tt1;
+create temporary table tt1 like t1;
+--echo # Temporary is stripped from versioning
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE
+show create table tt1;
+
+--echo # CREATE TABLE ... SELECT
+create or replace table t1 (x23 int) with system versioning;
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE
+eval create or replace table t0(
+ y int,
+ st $sys_datatype as row start,
+ en $sys_datatype as row end,
+ period for system_time (st, en)
+) with system versioning;
+
+--echo ## For non-versioned table:
+--echo ### 1. invisible fields are not included
+create or replace table t2 as select * from t1;
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE
+show create table t2;
+
+--echo ### 2. all visible fields are included
+create or replace table t3 as select * from t0;
+select * from t0;
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE $sys_datatype_null SYS_DATATYPE $sys_datatype_not_null SYS_DATATYPE $sys_datatype_default_null SYS_DATATYPE
+show create table t3;
+
+--echo ## For versioned table
+insert into t1 values (1);
+select row_start from t1 into @row_start;
+insert into t0 (y) values (2);
+select st from t0 into @st;
+
+create or replace table t2 with system versioning as select * from t1;
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE
+show create table t2;
+--echo #### invisible fields are not copied
+select * from t2;
+select * from t2 where row_start <= @row_start;
+
+--echo ### 2. source table with visible system fields, target with invisible
+create or replace table t3 with system versioning as select * from t0;
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE $sys_datatype_null SYS_DATATYPE $sys_datatype_not_null SYS_DATATYPE $sys_datatype_default_null SYS_DATATYPE
+show create table t3;
+select * from t3 where y > 2;
+select y from t3 where st = @st and row_start > @st;
+
+--echo ### 3. source and target table with visible system fields
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE
+eval create or replace table t3 (
+ st $sys_datatype as row start invisible,
+ en $sys_datatype as row end invisible,
+ period for system_time (st, en)
+) with system versioning as select * from t0;
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE $sys_datatype_null SYS_DATATYPE $sys_datatype_not_null SYS_DATATYPE $sys_datatype_default_null SYS_DATATYPE
+show create table t3;
+select y from t3;
+select y from t3 where st = @st;
+
+--echo ### 4. system fields not or wrongly selected
+create or replace table t3 with system versioning select x23 from t1;
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE $sys_datatype_null SYS_DATATYPE $sys_datatype_not_null SYS_DATATYPE $sys_datatype_default_null SYS_DATATYPE
+show create table t3;
+select * from t3;
+--error ER_MISSING
+create or replace table t3 with system versioning select x23, row_start from t1;
+--error ER_MISSING
+create or replace table t3 with system versioning select x23, row_end from t1;
+
+--echo # Prepare checking for historical row
+delete from t1;
+select row_end from t1 for system_time all into @row_end;
+delete from t0;
+select en from t0 for system_time all into @en;
+
+--echo ## Combinations of versioned + non-versioned
+create or replace table t2 (y int);
+insert into t2 values (3);
+create or replace table t3 with system versioning select * from t1 for system_time all, t2;
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE
+show create table t3;
+select * from t3 for system_time all;
+select * from t3 for system_time all where row_start = @row_start and row_end = @row_end;
+
+create or replace table t2 like t0;
+insert into t2 (y) 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 t3 where y = 1 into @st, @en;
+select y from t2 for system_time all where st = @st and en = @en;
+select st, en from t3 where y = 2 into @st, @en;
+select y from t2 for system_time all where st = @st and en = @en;
+
+--echo ## Default engine detection
+--replace_result $non_default_engine NON_DEFAULT_ENGINE $sys_datatype SYS_DATATYPE
+eval create or replace table t1 (x25 int) with system versioning engine $non_default_engine;
+create or replace table t2
+as select x25, row_start, row_end from t1 for system_time all;
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE $sys_datatype_null SYS_DATATYPE
+show create table t2;
+
+create or replace table t2 with system versioning
+as select x25, row_start, row_end from t1;
+--replace_result $non_default_engine NON_DEFAULT_ENGINE $sys_datatype SYS_DATATYPE
+show create table t2;
+
+create or replace table t1 (
+ x26 int,
+ st bigint unsigned as row start,
+ en bigint unsigned as row end,
+ period for system_time (st, en)
+) with system versioning engine innodb;
+--error ER_VERS_FIELD_WRONG_TYPE
+create or replace table t2 with system versioning engine myisam
+as select * from t1;
+
+--replace_result $non_default_engine NON_DEFAULT_ENGINE
+eval create or replace table t1 (x27 int, id int) with system versioning engine $non_default_engine;
+create or replace table t2 (b int, id int);
+create or replace table t3 with system versioning
+as select t2.b, t1.x27, t1.row_start, t1.row_end from t2 inner join t1 on t2.id=t1.id;
+--replace_result $non_default_engine NON_DEFAULT_ENGINE $sys_datatype SYS_DATATYPE $sys_datatype_null SYS_DATATYPE
+show create table t3;
+
+--echo ## Errors
+
+--error ER_VERS_TEMPORARY
+create or replace temporary table t (x28 int) with system versioning;
+
+--error ER_VERS_DUPLICATE_ROW_START_END
+create or replace table t1 (
+ x29 int unsigned,
+ Sys_start0 timestamp(6) as row start invisible,
+ Sys_start timestamp(6) as row start invisible,
+ Sys_end timestamp(6) as row end invisible,
+ period for system_time (Sys_start, Sys_end)
+) with system versioning;
+
+--error ER_VERS_DUPLICATE_ROW_START_END
+create or replace table t1 (
+ x29 int unsigned,
+ Sys_end0 timestamp(6) as row end invisible,
+ Sys_start timestamp(6) as row start invisible,
+ Sys_end timestamp(6) as row end invisible,
+ period for system_time (Sys_start, Sys_end)
+) with system versioning;
+
+--echo ## System fields detection
+create or replace table t1 (x30 int) with system versioning;
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE
+eval create or replace table t2 (
+ y int,
+ st $sys_datatype as row start invisible,
+ en $sys_datatype as row end invisible,
+ period for system_time (st, en)
+) with system versioning;
+
+create or replace table t3
+as select x30, y, row_start, row_end, st, en from t1, t2;
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE $sys_datatype_null SYS_DATATYPE $sys_datatype_not_null SYS_DATATYPE $sys_datatype_default_null SYS_DATATYPE
+show create table t3;
+
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE
+eval create or replace table t3 (
+ y int,
+ st $sys_datatype as row start invisible,
+ en $sys_datatype as row end invisible,
+ period for system_time (st, en)
+) with system versioning
+as select x30, y, row_start, row_end, st, en from t1, t2;
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE $sys_datatype_null SYS_DATATYPE $sys_datatype_not_null SYS_DATATYPE $sys_datatype_default_null SYS_DATATYPE
+show create table t3;
+
+--echo # MDEV-14828 Server crashes in JOIN::prepare / setup_fields on 2nd execution of PS [#437]
+create or replace table t1 (x int) with system versioning;
+prepare bad from 'create or replace table t2 with system versioning as select * from t1';
+execute bad; execute bad; execute bad; execute bad; execute bad; execute bad; execute bad; execute bad;
+--echo # bad is good.
+
+drop database test;
+create database test;
diff --git a/mysql-test/suite/versioning/t/cte.test b/mysql-test/suite/versioning/t/cte.test
new file mode 100644
index 00000000000..9df0bb3dfba
--- /dev/null
+++ b/mysql-test/suite/versioning/t/cte.test
@@ -0,0 +1,101 @@
+-- source include/have_innodb.inc
+set default_storage_engine=innodb;
+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 max(sys_trx_start) into @ts_1 from emp;
+
+update emp set mgr=30 where name ="john";
+select 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 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 for system_time as of timestamp @ts_1 as e,
+ 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 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 for system_time as of timestamp @ts_2 as e,
+ 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;
+
+with recursive
+ancestors
+as
+(
+ select e.emp_id, e.name, e.mgr
+ from emp for system_time as of timestamp @ts as e
+ where name = 'bill'
+ union
+ select ee.emp_id, ee.name, ee.mgr
+ from emp for system_time as of timestamp @ts as ee, ancestors as a
+ where ee.mgr = a.emp_id
+)
+select * from ancestors;
+
+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 (select * from emp natural join addr) for system_time all as t) select * from ancestors;
+select * from (select * from emp natural join addr) for system_time all as t;
+
+drop table emp;
+drop table dept;
+drop table addr;
diff --git a/mysql-test/suite/versioning/t/ddl.test b/mysql-test/suite/versioning/t/ddl.test
new file mode 100644
index 00000000000..5be62281a6d
--- /dev/null
+++ b/mysql-test/suite/versioning/t/ddl.test
@@ -0,0 +1,105 @@
+-- source suite/versioning/common.inc
+
+delimiter ~~;
+create function get_archive_table_name()
+returns varchar(255)
+begin
+ 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_archive()
+begin
+ call concat_exec2('drop table ', get_archive_table_name());
+end~~
+delimiter ;~~
+
+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;
+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_archive_table_name(), ' for system_time all');
+
+call concat_exec3('select @tm=sys_trx_start from ', get_archive_table_name(), ' for system_time all where a=2');
+select @tm<sys_trx_start from t where a=2;
+select sys_trx_start from t where a=2 into @tm;
+call concat_exec3('select @tm=sys_trx_end from ', get_archive_table_name(), ' for system_time all where a=2');
+
+call drop_last_archive();
+
+
+set versioning_alter_history= keep;
+drop table t_vtmd;
+drop table t;
+set versioning_alter_history= survive;
+
+# same for INNODB ALGORITHM=COPY
+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;
+call concat_exec3('select * from ', get_archive_table_name(), ' for system_time all');
+
+call concat_exec3('select @tm=sys_trx_start from ', get_archive_table_name(), ' for system_time all where a=2');
+select @tm<sys_trx_start from t where a=2;
+select sys_trx_start from t where a=2 into @tm;
+call concat_exec3('select @tm=sys_trx_end from ', get_archive_table_name(), ' for system_time all where a=2');
+
+call drop_last_archive();
+
+
+set versioning_alter_history= keep;
+drop table t_vtmd;
+drop table t;
+set versioning_alter_history= survive;
+
+# same for INNODB default ALGORITHM
+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;
+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_archive_table_name(), ' for system_time all');
+
+call concat_exec3('select @tm=sys_trx_start from ', get_archive_table_name(), ' for system_time all where a=2');
+select @tm<sys_trx_start from t where a=2;
+select sys_trx_start from t where a=2 into @tm;
+call concat_exec3('select @tm=sys_trx_end from ', get_archive_table_name(), ' for system_time all where a=2');
+
+call drop_last_archive();
+
+
+set versioning_alter_history= keep;
+drop table t_vtmd;
+drop table t;
+set versioning_alter_history= survive;
+
+# no DDL for INNODB explicit ALGORITHM=INPLACE
+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_alter_history = keep;
+
+drop function get_archive_table_name;
+drop procedure drop_last_archive;
+
+select * from mysql.vtmd_template;
+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/delete.test b/mysql-test/suite/versioning/t/delete.test
new file mode 100644
index 00000000000..55420a21185
--- /dev/null
+++ b/mysql-test/suite/versioning/t/delete.test
@@ -0,0 +1,129 @@
+-- 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, ' as row start invisible,
+ sys_end ', sys_type, ' as row end invisible,
+ 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;
+ select "Deleted 0";
+ execute stmt;
+ delete from t1 where XNo = 1;
+ select "Deleted 1";
+ execute stmt;
+ delete from t1 where XNo > 5;
+ select "Deleted >5";
+ create view vt1 as select XNo from t1;
+ select XNo as XNo_vt1 from vt1;
+ delete from vt1 where XNo = 3;
+ select "Deleted from VIEW 3";
+ select XNo as XNo_vt1 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, ' as row start invisible,
+ sys_end ', sys_type, ' as row end invisible,
+ 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, ' as row start invisible,
+ sys_end ', sys_type, ' as row end invisible,
+ 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', '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', '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', 'vtq_commit_ts(sys_end)');
+call verify_vtq;
+
+--echo # Update + delete
+create or replace table t1 (x int) with system versioning;
+insert into t1 values (1);
+update t1 set x= 2;
+delete from t1;
+select x from t1 for system_time all;
+
+drop database test;
+create database test;
diff --git a/mysql-test/suite/versioning/t/derived.test b/mysql-test/suite/versioning/t/derived.test
new file mode 100644
index 00000000000..9784a4a0d2f
--- /dev/null
+++ b/mysql-test/suite/versioning/t/derived.test
@@ -0,0 +1,236 @@
+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 row_end>'2031-1-1') as tmp;
+set @tmp= "select emp_id from (select emp_id from emp where row_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;
+
+#385
+with recursive
+ancestors
+as
+(
+ select e.emp_id, e.name, e.mgr
+ from emp for system_time as of timestamp @ts as e
+ where name = 'bill'
+ union
+ select ee.emp_id, ee.name, ee.mgr
+ from emp for system_time as of timestamp @ts 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 for system_time as of timestamp @ts as e
+ where name = 'bill'
+ union
+ select ee.emp_id, ee.name, ee.mgr
+ from emp for system_time as of timestamp @ts as ee,
+ ancestors as a
+ 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);
+delete from t1;
+insert into t1 values (2);
+insert into t2 values (10);
+
+--replace_column 2 # 3 #
+select * from (select *, t1.row_end, t1.row_end as endo from t1) as s0;
+--replace_column 3 # 4 #
+select * from (select *, t1.row_end, t2.row_start from t1, t2) as s0;
+
+--echo # 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;
+--echo # leading table selection
+--replace_column 3 #
+select * from (select *, t1.row_end from t2, t1 for system_time as of timestamp @t0) as s2;
+--replace_column 3 #
+with s3 as (select *, t1.row_end from t2, t1 for system_time as of timestamp @t0) select * from s3;
+
+--echo ### 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;
+create view vt2 as select * from t1;
+
+--echo # SYSTEM_TIME propagation from view
+select * from vt1;
+--echo # SYSTEM_TIME propagation from inner to outer
+select * from (select * from vt1, t2) as s0;
+
+--echo ### SYSTEM_TIME clash
+--error ER_VERS_NOT_VERSIONED
+select * from (select * from t1 for system_time all) for system_time all as dt0;
+--error ER_VERS_NOT_VERSIONED
+select * from vt1 for system_time all;
+--error ER_VERS_NOT_VERSIONED
+with dt1 as (select * from t1 for system_time all)
+select * from dt1 for system_time all;
+
+--echo ### UNION
+set @t1= now(6);
+delete from t2;
+insert into t2 values (3);
+--echo # SYSTEM_TIME is not propagated
+select x from t1 union
+select y from t2;
+select x from t1 for system_time as of @t0 union
+select y from t2;
+select x from t1 union
+select y from t2 for system_time as of @t1;
+select x from t1 for system_time as of @t0 union
+select y from t2 for system_time as of @t1;
+
+--echo # LEFT/RIGHT JOIN
+create or replace table t1 (x int, y int) with system versioning;
+create or replace table t2 (x int, y int) 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);
+
+--echo ## Outer or inner SYSTEM_TIME produces same expression
+
+--disable_warnings
+--disable_query_log
+explain extended
+select * from (
+ select t1.x, t1.y as y1, t2.x as x2, t2.y as y2
+ from t1 join t2 on t1.x = t2.x) for system_time as of now() as t;
+
+let $a=`show warnings`;
+--echo Query A:
+echo $a;
+
+explain extended
+select * from (
+ select t1.x, t1.y as y1, t2.x as x2, t2.y as y2
+ from t1 for system_time as of now()
+ join t2 for system_time as of now() on t1.x = t2.x) as t;
+
+let $b=`show warnings`;
+--echo Query B:
+echo $b;
+
+if ($a == $b)
+{
+ --echo Fine result: queries A and B are equal.
+}
+--enable_query_log
+--enable_warnings
+
+--echo ## LEFT JOIN: t1, t2 versioned
+select * from (
+ 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)
+as derived;
+
+alter table t2 drop system versioning;
+
+--echo ## LEFT JOIN: t1 versioned
+select * from (
+ 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)
+as derived;
+
+alter table t1 drop system versioning;
+alter table t2 add system versioning;
+
+--echo ## LEFT JOIN: t2 versioned
+select * from (
+ select t1.x as LJ3_x1, t1.y as y1, t2.x as x2, t2.y as y2
+ from t1 left join t2 on t1.x = t2.x)
+as derived;
+
+alter table t1 add system versioning;
+
+--echo ## RIGHT JOIN: t1, t2 versioned
+select * from (
+ 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)
+as derived;
+
+alter table t2 drop system versioning;
+
+--echo ## RIGHT JOIN: t1 versioned
+select * from (
+ 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)
+as derived;
+
+alter table t1 drop system versioning;
+alter table t2 add system versioning;
+
+--echo ## RIGHT JOIN: t2 versioned
+select * from (
+ select t1.x as RJ3_x1, t1.y as y1, t2.x as x2, t2.y as y2
+ from t1 right join t2 on t1.x = t2.x)
+as derived;
+
+drop table t1, t2;
+drop view vt1, vt2;
+
diff --git a/mysql-test/suite/versioning/t/engines.combinations b/mysql-test/suite/versioning/t/engines.combinations
new file mode 100644
index 00000000000..561c5656929
--- /dev/null
+++ b/mysql-test/suite/versioning/t/engines.combinations
@@ -0,0 +1,8 @@
+[timestamp]
+default-storage-engine=innodb
+
+[trx_id]
+default-storage-engine=innodb
+
+[myisam]
+default-storage-engine=myisam
diff --git a/mysql-test/suite/versioning/t/foreign.combinations b/mysql-test/suite/versioning/t/foreign.combinations
new file mode 100644
index 00000000000..1a0812cfafe
--- /dev/null
+++ b/mysql-test/suite/versioning/t/foreign.combinations
@@ -0,0 +1,5 @@
+[timestamp]
+default-storage-engine=innodb
+
+[trx_id]
+default-storage-engine=innodb
diff --git a/mysql-test/suite/versioning/t/foreign.test b/mysql-test/suite/versioning/t/foreign.test
new file mode 100644
index 00000000000..81d1caa2594
--- /dev/null
+++ b/mysql-test/suite/versioning/t/foreign.test
@@ -0,0 +1,282 @@
+--source suite/versioning/common.inc
+
+--echo #################
+--echo # Test RESTRICT #
+--echo #################
+
+create table parent(
+ id int unique key
+) engine innodb;
+
+--replace_result $sys_datatype_expl SYS_DATATYPE
+eval create table child(
+ parent_id int,
+ sys_start $sys_datatype_expl as row start invisible,
+ sys_end $sys_datatype_expl as row end invisible,
+ period for system_time(sys_start, sys_end),
+ 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;
+
+--echo ##############################################
+--echo # Test when clustered index is a foreign key #
+--echo ##############################################
+
+create table parent(
+ id int(10) unsigned unique key
+) engine innodb;
+
+--replace_result $sys_datatype_expl SYS_DATATYPE
+eval create table child(
+ parent_id int(10) unsigned primary key,
+ sys_start $sys_datatype_expl as row start invisible,
+ sys_end $sys_datatype_expl as row end invisible,
+ period for system_time(sys_start, sys_end),
+ 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;
+
+--echo ################
+--echo # Test CASCADE #
+--echo ################
+
+create table parent(
+ id int unique key
+) engine innodb;
+
+--replace_result $sys_datatype_expl SYS_DATATYPE
+eval create table child(
+ parent_id int,
+ sys_start $sys_datatype_expl as row start invisible,
+ sys_end $sys_datatype_expl as row end invisible,
+ period for system_time(sys_start, sys_end),
+ 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);
+
+--echo ## FIXME: #415 update of foreign constraints is disabled
+call mtr.add_suppression("foreign key constraints in timestamp-based temporal table");
+--error ER_UNSUPPORTED_EXTENSION
+delete from parent where id = 1;
+delete from child where parent_id = 1;
+--echo ## FIXME END
+delete from parent where id = 1;
+select * from child;
+select * from child for system_time all;
+
+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 all;
+
+drop table child;
+drop table parent;
+
+--replace_result $sys_datatype_expl SYS_DATATYPE
+eval create or replace table parent (
+ id int primary key,
+ sys_start $sys_datatype_expl as row start invisible,
+ sys_end $sys_datatype_expl as row end invisible,
+ period for system_time(sys_start, sys_end)
+) 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 (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);
+--echo ## FIXME: #415 update of foreign constraints is disabled
+delete from child;
+--echo ## FIXME END
+delete from parent;
+select * from child;
+select * from child for system_time all;
+
+drop table child;
+drop table parent;
+
+--echo #################
+--echo # Test SET NULL #
+--echo #################
+
+create table parent(
+ id int unique key
+) engine innodb;
+
+--replace_result $sys_datatype_expl SYS_DATATYPE
+eval create table child(
+ parent_id int,
+ sys_start $sys_datatype_expl as row start invisible,
+ sys_end $sys_datatype_expl as row end invisible,
+ period for system_time(sys_start, sys_end),
+ 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);
+
+--echo ## FIXME: #415 update of foreign constraints is disabled
+delete from child where parent_id = 1;
+--echo ## FIXME END
+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);
+## FIXME: #415 update of foreign constraints is disabled
+if (0)
+{
+update parent set id=id+1;
+select * from child;
+select * from child for system_time from timestamp '1-1-1' to timestamp now(6);
+}
+## FIXME END
+
+drop table child;
+drop table parent;
+
+--echo ###########################
+--echo # Parent table is foreign #
+--echo ###########################
+
+--replace_result $sys_datatype_expl SYS_DATATYPE
+eval create or replace table parent(
+ id int unique key,
+ sys_start $sys_datatype_expl as row start invisible,
+ sys_end $sys_datatype_expl as row end invisible,
+ period for system_time(sys_start, sys_end)
+) 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;
+
+--echo ###################
+--echo # crash on DELETE #
+--echo ###################
+
+--replace_result $sys_datatype_expl SYS_DATATYPE
+eval create or replace table a (
+ cola int(10) primary key,
+ v_cola int(10) as (cola mod 10) virtual,
+ sys_start $sys_datatype_expl as row start invisible,
+ sys_end $sys_datatype_expl as row end invisible,
+ period for system_time(sys_start, sys_end)
+) engine=innodb with system versioning;
+
+create index v_cola on a (v_cola);
+
+--replace_result $sys_datatype_expl SYS_DATATYPE
+eval create or replace table b(
+ cola int(10),
+ v_cola int(10),
+ sys_start $sys_datatype_expl as row start invisible,
+ sys_end $sys_datatype_expl as row end invisible,
+ period for system_time(sys_start, sys_end)
+) engine=innodb with system versioning;
+
+alter table b add constraint `v_cola_fk`
+foreign key (v_cola) references a (v_cola);
+
+insert into a(cola) values (12);
+insert into b(cola, v_cola) values (10,2);
+--error ER_ROW_IS_REFERENCED_2
+delete from a;
+
+drop table b, a;
+
+--source suite/versioning/common_finish.inc
diff --git a/mysql-test/suite/versioning/t/insert.test b/mysql-test/suite/versioning/t/insert.test
new file mode 100644
index 00000000000..f459f196759
--- /dev/null
+++ b/mysql-test/suite/versioning/t/insert.test
@@ -0,0 +1,254 @@
+-- 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, ' as row start invisible,
+ sys_end ', sys_type, ' as row end invisible,
+ 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 delayed 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, ' as row start invisible,
+ sys_end ', sys_type, ' as row end invisible,
+ 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, ' as row start invisible,
+ sys_end ', sys_type, ' as row end invisible,
+ 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;
+ insert into t1(x, y) values(8001, 9001);
+ insert into vt1_1(x, y) values(1001, 2001);
+ insert into vt1_1 values(1002, 2002);
+ set @str= concat('select x, y, ', fields, ' from t1');
+ prepare stmt from @str; execute stmt; drop prepare stmt;
+ select x, y from vt1_1;
+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 row_start, row_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, row_start > @sys_start as C, row_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, ' as row start invisible,
+ sys_end ', sys_type, ' as row end invisible,
+ 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);
+ insert into t1(x, y, sys_start) values
+ (7, 7001, DEFAULT);
+ insert into t1(x, y, sys_end) values
+ (8, 8001, DEFAULT);
+ insert into t1(x, y, sys_start, sys_end) values
+ (9, 9001, DEFAULT, DEFAULT);
+ 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', 'vtq_commit_ts(sys_end)');
+
+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');
+drop table t1;
+drop view vt1_1;
+
+call test_03('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)');
+drop table t1;
+drop view vt1_1;
+
+call test_04('timestamp(6)', 'myisam', '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', 'vtq_commit_ts(sys_end)');
+
+# VTQ test
+
+call verify_vtq;
+
+create table t1(
+ x int unsigned,
+ sys_start bigint unsigned as row start invisible,
+ sys_end bigint unsigned as row end invisible,
+ 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;
+
+set global system_versioning_transaction_registry= off;
+insert into t2(x) values (1);
+--error ER_VERS_TRT_IS_DISABLED
+insert into t1(x) values (1);
+set global system_versioning_transaction_registry= on;
+
+# virtual columns
+create or replace table t1 (
+ x int,
+ y int as (x) virtual,
+ sys_trx_start bigint unsigned as row start invisible,
+ sys_trx_end bigint unsigned as row end invisible,
+ period for system_time (sys_trx_start, sys_trx_end)
+) engine=innodb with system versioning;
+insert into t1 values (1, null);
+update t1 set x= x + 1;
+select x, y, sys_trx_end = 18446744073709551615 as current from t1 for system_time all;
+
+create or replace table t1 (x int) with system versioning engine innodb;
+insert into t1 values (1), (2);
+--error ER_WARNING_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN
+insert into t1 (row_start) select row_end from t1;
+set sql_mode='';
+insert into t1 (row_start, row_end) values (DEFAULT, 1);
+set sql_mode=default;
+select @@sql_mode into @saved_mode;
+set sql_mode= '';
+insert into t1 (x, row_start, row_end) values (3, 4, 5);
+set sql_mode= @saved_mode;
+insert into t1 (row_start, row_end) values (DEFAULT, DEFAULT);
+select * from t1;
+
+--echo # MDEV-14792 INSERT without column list into table with explicit versioning columns produces bad data
+create or replace table t1 (
+ i int,
+ s timestamp(6) as row start,
+ e timestamp(6) as row end,
+ c varchar(8),
+ period for system_time(s, e))
+with system versioning;
+insert into t1 values (1, null, null, 'foo');
+select i, c, current_row(e) from t1;
+
+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;
+
+-- source suite/versioning/common_finish.inc
+
+#
+# MDEV-14788 System versioning cannot be based on local timestamps, as it is now
+#
+set timestamp=1000000019;
+select now() < sysdate();
+create table t1 (a int) with system versioning;
+insert t1 values (1);
+select * from t1 for system_time as of now(6);
+select * from t1 for system_time as of sysdate(6);
+drop table t1;
diff --git a/mysql-test/suite/versioning/t/online.test b/mysql-test/suite/versioning/t/online.test
new file mode 100644
index 00000000000..3b1c20792d2
--- /dev/null
+++ b/mysql-test/suite/versioning/t/online.test
@@ -0,0 +1,45 @@
+--source include/have_innodb.inc
+
+set system_versioning_alter_history=keep;
+
+create or replace table t (a int, b int) engine=innodb;
+
+--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
+alter table t add system versioning, lock=none;
+alter table t add system versioning, lock=shared;
+--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
+alter table t drop column b, lock=none;
+--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
+alter table t drop column b, algorithm=inplace;
+alter table t add index idx(a), lock=none;
+--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
+alter table t drop system versioning, lock=none;
+--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
+alter table t drop system versioning, algorithm=inplace;
+
+
+set global system_versioning_transaction_registry=on;
+create or replace table t (a int, b int) engine=innodb;
+
+--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
+alter table t
+ add s bigint unsigned as row start,
+ add e bigint unsigned as row end,
+ add period for system_time(s, e),
+ add system versioning,
+ lock=none;
+alter table t
+ add s bigint unsigned as row start,
+ add e bigint unsigned as row end,
+ add period for system_time(s, e),
+ add system versioning;
+--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
+alter table t drop column b, lock=none;
+alter table t add index idx(a), lock=none;
+alter table t drop column s, drop column e;
+--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
+alter table t drop system versioning, lock=none;
+
+set global system_versioning_transaction_registry=off;
+
+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..93dd6ed6fc6
--- /dev/null
+++ b/mysql-test/suite/versioning/t/optimized.test
@@ -0,0 +1,33 @@
+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 for system_time as of timestamp now(6) group by b;
+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 for system_time as of timestamp now(6) group by a having a=2;
+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;
+select a, b from t;
+
+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/partition.combinations b/mysql-test/suite/versioning/t/partition.combinations
new file mode 100644
index 00000000000..4d73ef5a5ea
--- /dev/null
+++ b/mysql-test/suite/versioning/t/partition.combinations
@@ -0,0 +1,5 @@
+[timestamp]
+default-storage-engine=innodb
+
+[myisam]
+default-storage-engine=myisam
diff --git a/mysql-test/suite/versioning/t/partition.opt b/mysql-test/suite/versioning/t/partition.opt
new file mode 100644
index 00000000000..71be6744916
--- /dev/null
+++ b/mysql-test/suite/versioning/t/partition.opt
@@ -0,0 +1 @@
+--system-versioning-alter-history=keep
diff --git a/mysql-test/suite/versioning/t/partition.test b/mysql-test/suite/versioning/t/partition.test
new file mode 100644
index 00000000000..9422d5d336d
--- /dev/null
+++ b/mysql-test/suite/versioning/t/partition.test
@@ -0,0 +1,356 @@
+-- source include/have_partition.inc
+-- source suite/versioning/common.inc
+
+--echo # Check conventional partitioning on temporal tables
+
+create table t1 (x int)
+with system versioning
+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 partition (p0);
+select * from t1 partition (p1);
+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;
+
+--echo # Engine change native <-> non-native versioning prohibited
+--replace_result $default_engine DEFAULT_ENGINE
+eval create or replace table t1 (i int) engine=$default_engine with system versioning partition by hash(i);
+--replace_result $non_default_engine NON_DEFAULT_ENGINE
+--error ER_VERS_ALTER_ENGINE_PROHIBITED
+eval alter table t1 engine=$non_default_engine;
+
+
+--echo ## CREATE TABLE
+
+--error ER_VERS_ENGINE_UNSUPPORTED
+create or replace table t1 (x int)
+partition by system_time (
+ partition p0 history,
+ partition pn current);
+
+create or replace table t1 (x int);
+--error ER_VERS_ENGINE_UNSUPPORTED,ER_VERS_ENGINE_UNSUPPORTED
+alter table t1
+partition by system_time (
+ partition p0 history,
+ partition pn current);
+
+--error ER_VERS_WRONG_PARTS
+create or replace table t1 (x int)
+with system versioning
+partition by system_time (
+ partition p0 current);
+
+--error ER_VERS_WRONG_PARTS
+create or replace table t1 (x int)
+with system versioning
+partition by system_time (
+ partition p0 current,
+ partition p1 current);
+
+--error ER_VERS_WRONG_PARTS
+create or replace table t1 (x int)
+with system versioning
+partition by system_time (
+ partition p0 history,
+ partition p1 history);
+
+--error ER_VERS_WRONG_PARTS
+create or replace table t1 (x int)
+with system versioning
+partition by system_time (
+ partition pn current,
+ partition p0 history);
+
+--error ER_VERS_WRONG_PARTS
+create or replace table t1 (x int)
+with system versioning
+partition by system_time (
+ partition p0,
+ partition pn current);
+
+create or replace table t1 (x int)
+with system versioning
+partition by system_time (
+ partition p0 history,
+ partition pn current);
+
+
+--echo ## ALTER TABLE
+
+--error ER_VERS_WRONG_PARTS
+alter table t1 add partition (
+ partition p1 current);
+
+alter table t1 add partition (
+ partition p1 history);
+
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE
+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;
+
+--echo # Bug #260: incorrect IB partitioning warning
+create or replace table t1 (x int)
+with system versioning
+partition by system_time limit 1 (
+ partition p0 history,
+ partition pn current);
+alter table t1 change x big int;
+
+create or replace table t1 (i int) engine myisam partition by hash(i) partitions 2;
+--error ER_PARTITION_WRONG_TYPE
+alter table t1 add partition (partition px history);
+
+
+--echo ## INSERT, UPDATE, DELETE
+
+create or replace table t1 (x int)
+with system versioning
+partition by system_time (
+ partition p0 history,
+ partition pn current);
+
+set @now= now(6);
+insert into t1 values (1);
+set @str= concat('select x, row_start < @now as A, row_end > @now as B from t1 partition (p0)');
+prepare select_p0 from @str;
+set @str= concat('select x, row_start > @now as C, row_end = timestamp\'2038-01-19 03:14:07.999999\' as D from t1 partition (pn)');
+prepare select_pn from @str;
+
+execute select_p0;
+execute select_pn;
+
+--echo ## pruning check
+--replace_regex /\d/N/ /ALL/system/ /Using where//
+explain partitions select * from t1;
+
+set @str= concat('select row_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;
+execute select_pn;
+
+set @str= concat('select row_start from t1 partition (p0) 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 row_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 row_start from t1 partition (p0) where x = 2 into @ts1');
+prepare stmt from @str; execute stmt; drop prepare stmt;
+set @str= concat('select row_end from t1 partition (p0) where x = 2 into @ts2');
+prepare stmt from @str; execute stmt; drop prepare stmt;
+set @str= concat('select row_start from t1 partition (pn) into @ts3');
+prepare stmt from @str; execute stmt; drop prepare stmt;
+
+select @ts0 = @ts1;
+select @ts2 = @ts3;
+
+--echo ## rotation by LIMIT
+--error ER_PART_WRONG_VALUE
+create or replace table t1 (x int)
+with system versioning
+partition by system_time limit 0 (
+ partition p0 history,
+ partition p1 history,
+ partition pn current);
+
+create or replace table t1 (x int)
+with system versioning
+partition by system_time limit 2 (
+ partition p0 history,
+ partition p1 history,
+ partition pn current);
+
+--replace_result $default_engine DEFAULT_ENGINE $sys_datatype SYS_DATATYPE
+show create table t1;
+
+--error ER_DROP_PARTITION_NON_EXISTENT
+alter table t1 drop partition non_existent;
+
+insert into t1 values (1), (2), (3);
+select * from t1 partition (pn);
+--echo ### warn about partition switching
+delete from t1;
+select * from t1 partition (p0);
+select * from t1 partition (p1);
+
+insert into t1 values (4), (5);
+--echo ### warn about full partition
+delete from t1;
+select * from t1 partition (p1) order by x;
+
+--echo ### Assertion in ALTER on warning from partitioning LIMIT [#446]
+create or replace table t1 (x int) with system versioning;
+insert into t1 values (1), (2);
+delete from t1;
+alter table t1 partition by system_time limit 1 (
+ partition p1 history,
+ partition pn current);
+
+--echo ## rotation by INTERVAL
+--error ER_PART_WRONG_VALUE
+create or replace table t1 (x int)
+with system versioning
+partition by system_time interval 0 second (
+ partition p0 history,
+ partition p1 history,
+ partition pn current);
+
+create or replace table t1 (x int)
+with system versioning
+partition by system_time interval 1 second (
+ partition p0 history,
+ partition p1 history,
+ partition pn current);
+
+insert into t1 values (1), (2), (3);
+select * from t1 partition (pn);
+delete from t1;
+select * from t1 partition (p0);
+
+--sleep 2
+insert into t1 values (4);
+delete from t1;
+select * from t1 partition (p1);
+
+--echo ## Subpartitions
+create or replace table t1 (x int)
+with system versioning
+partition by system_time limit 2
+subpartition by key (x)
+subpartitions 2 (
+ partition p0 history,
+ partition p1 history,
+ partition pn current);
+
+insert into t1 (x) values (1), (2), (3), (4), (5);
+select * from t1 partition (pnsp0);
+select * from t1 partition (pnsp1);
+
+--echo ### warn about partition switching and about full partition
+delete from t1;
+select * from t1 partition (p0sp0);
+select * from t1 partition (p0sp1);
+select * from t1 partition (p1sp0);
+select * from t1 partition (p1sp1);
+
+create or replace table t1 (a bigint)
+with system versioning
+partition by range (a)
+(partition p0 values less than (20) engine innodb,
+ partition p1 values less than maxvalue engine innodb);
+insert into t1 values (1);
+
+create or replace table t1 (
+ f_int1 integer default 0
+) with system versioning
+partition by range(f_int1)
+subpartition by hash(f_int1)
+( partition part1 values less than (1000)
+(subpartition subpart11 storage engine = 'innodb',
+subpartition subpart12 storage engine = 'innodb'));
+insert into t1 values (1);
+
+create or replace table t1 (i int) engine=innodb partition by key(i);
+alter table t1 add system versioning;
+insert into t1 values();
+
+--echo # MDEV-14722 Assertion in ha_commit_trans for sub-statement
+create or replace table t1 (i int) with system versioning
+partition by system_time interval 1 day (
+ partition p1 history,
+ partition pc current);
+create or replace table t2 (f int);
+create or replace trigger tr before insert on t2
+for each row select table_rows from information_schema.tables
+where table_name = 't1' into @a;
+insert into t2 values (1);
+
+--echo # MDEV-14740 Locking assertion for system_time partitioning
+create or replace table t1 (i int) with system versioning
+partition by system_time interval 1 week (
+ partition p1 history,
+ partition pn current);
+create or replace table t2 (f int);
+create or replace trigger tr before insert on t2
+for each row select count(*) from t1 into @a;
+insert into t2 values (1);
+
+--echo # MDEV-14741 Assertion `(trx)->start_file == 0' failed in row_truncate_table_for_mysql()
+create or replace table t1 (i int) with system versioning
+partition by system_time interval 1 hour (
+ partition p1 history,
+ partition pn current);
+set autocommit= off;
+truncate table t1;
+set autocommit= on;
+
+--echo # MDEV-14747 ALTER PARTITION BY SYSTEM_TIME after LOCK TABLES
+create or replace table t1 (x int) with system versioning;
+lock table t1 write;
+alter table t1 partition by system_time interval 1 week (
+ partition p1 history,
+ partition pn current);
+unlock tables;
+
+--echo # MDEV-14748 Assertion in ha_myisammrg::attach_children()
+create or replace table t1 (x int) engine=myisam with system versioning
+ partition by system_time interval 1 month (partition p1 history, partition pn current);
+create or replace table t2 (x int) engine=myisam;
+create or replace table t3 (x int) engine=merge union=(t2);
+create or replace table t4 (x int) engine=myisam;
+create or replace trigger tr after insert on t4 for each row insert into t2
+ ( select x from t3 ) union ( select x from t1 );
+insert into t4 values (1);
+
+--echo # MDEV-14821 Assertion failure
+create or replace table t1 (x int) with system versioning;
+insert into t1 values (0), (1);
+update t1 set x= x + 1;
+alter table t1 partition by system_time limit 1 (
+ partition p1 history,
+ partition p2 history,
+ partition pn current);
+delete from t1 where x = 1;
+delete from t1 where x = 2;
+
+--echo # Test cleanup
+drop database test;
+create database test;
diff --git a/mysql-test/suite/versioning/t/replace.test b/mysql-test/suite/versioning/t/replace.test
new file mode 100644
index 00000000000..8f1c2d8d637
--- /dev/null
+++ b/mysql-test/suite/versioning/t/replace.test
@@ -0,0 +1,13 @@
+--source suite/versioning/common.inc
+--source suite/versioning/key_type.inc
+--source suite/versioning/engines.inc
+
+call create_table('t', 'x int');
+
+insert t values (1, 2);
+replace t values (1, 3);
+select *, current_row(row_end) as current from t for system_time all
+order by x;
+
+drop database test;
+create database test;
diff --git a/mysql-test/suite/versioning/t/rpl.test b/mysql-test/suite/versioning/t/rpl.test
new file mode 100644
index 00000000000..342d58626b7
--- /dev/null
+++ b/mysql-test/suite/versioning/t/rpl.test
@@ -0,0 +1,108 @@
+--source include/master-slave.inc
+
+if ($MTR_COMBINATION_STMT)
+{
+ --source include/have_binlog_format_statement.inc
+}
+if ($MTR_COMBINATION_ROW)
+{
+ --source include/have_binlog_format_row.inc
+}
+if ($MTR_COMBINATION_MIX)
+{
+ --source include/have_binlog_format_mixed.inc
+}
+--source suite/versioning/engines.inc
+
+#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;
+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;
+
+# check unversioned -> versioned replication
+connection master;
+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;
+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);
+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;
+
+# 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);
+insert into t2 values (2);
+update t1, t2 set t1.x=11, t2.x=22;
+sync_slave_with_master;
+select * from t1;
+select * from t2;
+select * from t1 for system_time all;
+select * from t2 for system_time all;
+
+
+connection master;
+drop table t1, t2;
+
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test
new file mode 100644
index 00000000000..8fba9a7f68b
--- /dev/null
+++ b/mysql-test/suite/versioning/t/select.test
@@ -0,0 +1,291 @@
+--source suite/versioning/engines.inc
+--source suite/versioning/common.inc
+
+# test_01
+
+--replace_result $sys_datatype_expl SYS_DATATYPE
+eval create or replace table t1 (
+ x int unsigned,
+ y int unsigned,
+ sys_trx_start $sys_datatype_expl as row start invisible,
+ sys_trx_end $sys_datatype_expl as row end invisible,
+ period for system_time (sys_trx_start, sys_trx_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);
+
+set @t0= now(6);
+if ($MTR_COMBINATION_TRX_ID)
+{
+--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 ($MTR_COMBINATION_TRX_ID)
+{
+--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 ALL_x, y from t1 for system_time all;
+
+--disable_query_log
+if ($MTR_COMBINATION_TRX_ID)
+{
+ 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;
+}
+if ($MTR_COMBINATION_TIMESTAMP)
+{
+ 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 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;
+}
+--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;
+
+#384
+explain extended select * from (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 as t;
+explain extended select * from (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 as t;
+#383
+explain extended select * from (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 as t;
+
+select * from (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 as t;
+select * from (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 as t;
+select * from (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 as t;
+
+drop table t1;
+drop table t2;
+
+# 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_VERS_NOT_VERSIONED
+select * from t1 for system_time all;
+
+create or replace table t1 (x int) with system versioning;
+insert into t1 values (1);
+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.row_end;
+update t1 set a=2;
+--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;
+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 for system_time all;
+
+--error ER_VERS_NOT_VERSIONED
+select * from (select * from t1 for system_time all, t2 for system_time all)
+for system_time all as t;
+
+--echo # TRANSACTION/TIMESTAMP specifier in SYSTEM_TIME [MDEV-14645, Issue #396]
+create or replace table t1 (x int) with system versioning engine myisam;
+--error ER_VERS_ENGINE_UNSUPPORTED
+select * from t1 for system_time as of transaction 1;
+
+create or replace table t1 (
+ x int,
+ sys_trx_start bigint unsigned as row start invisible,
+ sys_trx_end bigint unsigned as row end invisible,
+ period for system_time (sys_trx_start, sys_trx_end)
+) with system versioning engine innodb;
+insert into t1 values (1);
+set @ts= now(6);
+delete from t1;
+select sys_trx_start from t1 for system_time all into @trx_start;
+
+--echo ## ensure @trx_start is much lower than unix timestamp
+select @trx_start < unix_timestamp(@ts) - 100 as trx_start_good;
+
+--echo ## TIMESTAMP specifier
+select x from t1 for system_time as of timestamp @ts;
+select x from t1 for system_time as of timestamp unix_timestamp(@ts);
+select x from t1 for system_time as of timestamp @trx_start;
+
+set @ts= timestamp'1-1-1 0:0:0';
+
+--echo ## TRANSACTION specifier
+select x from t1 for system_time as of transaction @ts;
+select x from t1 for system_time as of transaction unix_timestamp(@ts);
+select x from t1 for system_time as of transaction @trx_start;
+
+--echo ## no specifier (auto-detection)
+select x from t1 for system_time as of @ts;
+select x from t1 for system_time as of unix_timestamp(@ts);
+select x from t1 for system_time as of @trx_start;
+
+
+--echo ### Issue #365, bug 4 (related to #226, optimized fields)
+create or replace table t1 (i int, b int) with system versioning;
+insert into t1 values (0, 0), (0, 0);
+select min(i) over (partition by b) as f
+from (select i + 0 as i, b from t1) as tt
+order by i;
+
+--echo ### Issue #365, bug 5 (dangling AND)
+create or replace table t1 (a int);
+create or replace table t2 (b int) with system versioning;
+select * from t1
+where exists (select 1 from t2 where t2.b = t1.a and t2.b = t1.a);
+
+--echo ### Issue #365, bug 9 (not a derived subquery)
+create or replace table t1 (x int) with system versioning;
+select t1.x in (select x from t1) a from t1, (select x from t1) b;
+
+--echo ### Issue #365, bug 10 (WHERE cond freed prematurely for PS)
+create or replace table t1 (x int) with system versioning;
+insert into t1 values (1);
+create or replace view v1 as select x from t1 where x = 1;
+prepare stmt from "
+select x from t1 where x in (select x from v1);";
+execute stmt;
+execute stmt;
+
+--echo ### Issue #365, bug 11 (WHERE cond not top level item)
+create or replace table t1 (a int, b int, key idx(a)) with system versioning;
+insert into t1 values (1, 1), (2, 2);
+select * from t1 where (a, 2) in ((1, 1), (2, 2)) and b = 1;
+
+--echo ### Issue #398, NOW is now non-magic
+create or replace table t1 (x int) with system versioning;
+select * from t1 for system_time as of current_timestamp;
+--error ER_BAD_FIELD_ERROR
+select * from t1 for system_time as of now;
+
+--echo ### Issue #405, NATURAL JOIN failure
+create or replace table t1 (a int) with system versioning;
+create or replace table t2 (b int);
+create or replace view v1 as select a, row_start, row_end from t1 where a > round(rand()*1000);
+select * from v1 natural join t2;
+
+--echo ### Issue #406, MDEV-14633 Assertion on TRT read
+create or replace table t1 (pk int primary key, i int, t time, key (i)) with system versioning;
+insert into t1 values (1, 10, '15:01:53'), (2, 20, '00:00:00');
+delete from t1;
+--disable_warnings
+select * from t1 where t = '00:00:00' and i > 0 and row_end <> '2012-12-12 00:00:00';
+--enable_warnings
+
+drop view v1;
+drop table t1, t2;
+
+call verify_vtq_dummy(34);
+
+-- source suite/versioning/common_finish.inc
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..41022259b4f
--- /dev/null
+++ b/mysql-test/suite/versioning/t/select_sp.test
@@ -0,0 +1,232 @@
+--source suite/versioning/engines.inc
+--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(default_engine());
+
+ set @str= concat('
+ create table t1(
+ x int unsigned,
+ y int unsigned,
+ sys_start ', sys_type, ' as row start invisible,
+ sys_end ', sys_type, ' as row end invisible,
+ 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 '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 @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;
+ else
+ 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;
+ 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(default_engine());
+
+ set @str0= concat('(
+ x int,
+ y int,
+ sys_start ', sys_type, ' as row start invisible,
+ sys_end ', sys_type, ' as row end invisible,
+ 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 IJ2_x1,y1,x2,y2 from (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 as t;
+ select LJ2_x1,y1,x2,y2 from (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 as t;
+ select RJ2_x1,y1,x2,y2 from (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 as t;
+
+ drop table t1;
+ drop table t2;
+end~~
+delimiter ;~~
+
+call test_01();
+call test_02();
+
+--echo # MDEV-14686 Server crashes in Item_field::used_tables on 2nd call of SP [#422]
+create or replace table t1 (called int, bad int) with system versioning;
+create or replace procedure bad() select * from t1 where bad in (select called from t1);
+--disable_query_log
+call bad; call bad; call bad; call bad; call bad; call bad; call bad; call bad;
+drop procedure bad;
+--enable_query_log
+--echo # bad() is good.
+
+--echo # MDEV-14751 Server crashes in TABLE::versioned on 2nd execution of SP [#431]
+create or replace table t1 (called_bad int);
+create or replace table t2 (b int);
+create or replace procedure bad() select * from t1 where ( 5, 6 ) in ( select b, b from t2 ) and called_bad in ( select max(b) from t2 );
+--disable_query_log
+call bad; call bad; call bad; call bad; call bad; call bad; call bad; call bad;
+drop procedure bad;
+--enable_query_log
+--echo # bad() is good.
+
+--echo # MDEV-14786 Server crashes in Item_cond::transform on 2nd execution of SP querying from a view [#436]
+create or replace table t1 (called_bad int) with system versioning;
+create or replace view v1 as select called_bad from t1 where called_bad < 5;
+create or replace procedure bad() select called_bad from v1;
+--disable_query_log
+call bad; call bad; call bad; call bad; call bad; call bad; call bad; call bad;
+drop procedure bad;
+--enable_query_log
+--echo # bad() is good.
+
+--echo # wildcard expansion on hidden fields.
+create or replace 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_VERS_NOT_VERSIONED
+select * from t1 for system_time all;
+
+create or replace table t1 (x int) with system versioning;
+insert into t1 values (1);
+select * from t1 for system_time as of now() 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 or replace 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.row_end;
+update t1 set a=2;
+--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;
+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 for system_time all;
+
+--error ER_VERS_NOT_VERSIONED
+select * from (select * from t1 for system_time all, t2 for system_time all) for system_time all as t;
+--error ER_PARSE_ERROR
+select * from (t1 for system_time all join t2 for system_time all) for system_time all;
+
+drop view v1;
+drop table t1, t2;
+
+drop procedure test_01;
+drop procedure test_02;
+
+-- source suite/versioning/common_finish.inc
diff --git a/mysql-test/suite/versioning/t/simple.test b/mysql-test/suite/versioning/t/simple.test
new file mode 100644
index 00000000000..3790f0b8978
--- /dev/null
+++ b/mysql-test/suite/versioning/t/simple.test
@@ -0,0 +1,73 @@
+-- source include/have_innodb.inc
+set default_storage_engine=innodb;
+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 row_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 row_start into @ts_2 from emp where name="bill";
+
+select * from emp;
+
+update emp set salary=2000 where name="bill";
+commit;
+
+select row_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 for system_time from timestamp @ts_1 to timestamp @ts_2 e,
+ dept for system_time from timestamp @ts_1 to timestamp @ts_2 d
+where d.dept_id = 10
+ and d.dept_id = e.dept_id;
+
+set statement system_versioning_asof=@ts_0 for
+select * from emp e, dept d
+where d.dept_id = 10
+ and d.dept_id = e.dept_id;
+
+set statement system_versioning_asof=@ts_1 for
+select * from emp e, dept d
+where d.dept_id = 10
+ and d.dept_id = e.dept_id;
+
+set statement system_versioning_asof=@ts_2 for
+select * from emp e, dept d
+where d.dept_id = 10
+ and d.dept_id = e.dept_id;
+
+set statement system_versioning_asof=@ts_3 for
+select * from emp e, dept d
+where d.dept_id = 10
+ and d.dept_id = e.dept_id;
+
+drop table emp, dept;
diff --git a/mysql-test/suite/versioning/t/sysvars.test b/mysql-test/suite/versioning/t/sysvars.test
new file mode 100644
index 00000000000..08b520e959e
--- /dev/null
+++ b/mysql-test/suite/versioning/t/sysvars.test
@@ -0,0 +1,87 @@
+create table t (a int) with system versioning;
+insert into t values (1);
+update t set a= 2;
+
+show global variables like 'system_versioning_asof';
+show variables like 'system_versioning_asof';
+select * from t;
+
+set system_versioning_asof= '2031-1-1 0:0:0';
+show variables like 'system_versioning_asof';
+select * from t;
+
+set system_versioning_asof= '2011-1-1 0:0:0';
+show variables like 'system_versioning_asof';
+select * from t;
+
+# global
+--error ER_WRONG_VALUE_FOR_VAR
+set global system_versioning_asof= 'alley';
+--error ER_WRONG_VALUE_FOR_VAR
+set global system_versioning_asof= null;
+--error ER_WRONG_TYPE_FOR_VAR
+set global system_versioning_asof= 1;
+--error ER_WRONG_TYPE_FOR_VAR
+set global system_versioning_asof= 1.1;
+
+# session
+--error ER_WRONG_VALUE_FOR_VAR
+set system_versioning_asof= 'alley';
+--error ER_WRONG_VALUE_FOR_VAR
+set system_versioning_asof= null;
+--error ER_WRONG_TYPE_FOR_VAR
+set system_versioning_asof= 1;
+--error ER_WRONG_TYPE_FOR_VAR
+set system_versioning_asof= 1.1;
+
+--echo # GLOBAL @@system_versioning_asof
+set global system_versioning_asof= '1911-11-11 11:11:11.1111119';
+show global variables like 'system_versioning_asof';
+
+set global system_versioning_asof= '1900-01-01 00:00:00';
+show global variables like 'system_versioning_asof';
+
+set global system_versioning_asof= timestamp'1911-11-11 11:11:11.1111119';
+show global variables like 'system_versioning_asof';
+
+set @ts= timestamp'1900-01-01 00:00:00';
+set global system_versioning_asof= @ts;
+show global variables like 'system_versioning_asof';
+
+set global system_versioning_asof= default;
+select @@global.system_versioning_asof;
+
+--echo # SESSION @@system_versioning_asof
+set system_versioning_asof= '1911-11-11 11:11:11.1111119';
+show variables like 'system_versioning_asof';
+
+set system_versioning_asof= '1900-01-01 00:00:00';
+show variables like 'system_versioning_asof';
+
+set system_versioning_asof= timestamp'1911-11-11 11:11:11.1111119';
+show variables like 'system_versioning_asof';
+
+set @ts= timestamp'1900-01-01 00:00:00';
+set system_versioning_asof= @ts;
+show variables like 'system_versioning_asof';
+
+--echo # DEFAULT: value is copied from GLOBAL to SESSION
+set global system_versioning_asof= timestamp'1911-11-11 11:11:11.111111';
+set system_versioning_asof= '1900-01-01 00:00:00';
+select @@global.system_versioning_asof != @@system_versioning_asof as different;
+set system_versioning_asof= default;
+select @@global.system_versioning_asof = @@system_versioning_asof as equal;
+
+set global system_versioning_asof= DEFAULT;
+set system_versioning_asof= DEFAULT;
+select @@global.system_versioning_asof, @@system_versioning_asof;
+
+select * from t for system_time all;
+
+select * from t;
+select * from t for system_time as of timestamp current_timestamp(6);
+select * from t for system_time all;
+select * from t for system_time from '0-0-0' to current_timestamp(6);
+select * from t for system_time between '0-0-0' and current_timestamp(6);
+
+drop table t;
diff --git a/mysql-test/suite/versioning/t/truncate.opt b/mysql-test/suite/versioning/t/truncate.opt
new file mode 100644
index 00000000000..b0c5b9c8188
--- /dev/null
+++ b/mysql-test/suite/versioning/t/truncate.opt
@@ -0,0 +1 @@
+--partition
diff --git a/mysql-test/suite/versioning/t/truncate.test b/mysql-test/suite/versioning/t/truncate.test
new file mode 100644
index 00000000000..0f9e7052511
--- /dev/null
+++ b/mysql-test/suite/versioning/t/truncate.test
@@ -0,0 +1,72 @@
+--source suite/versioning/engines.inc
+
+create table t (a int);
+--error ER_VERS_NOT_VERSIONED
+delete history from t before 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;
+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';
+delete history from t;
+select @test from t;
+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;
+--real_sleep 0.01
+set @ts1=now(6);
+--real_sleep 0.01
+update t set a=22 where a=2;
+select * from t for system_time all;
+delete history from t before system_time timestamp @ts1;
+select * from t for system_time all;
+prepare stmt from 'delete history from t';
+execute stmt; drop prepare stmt;
+select * from t for system_time all;
+delete from t;
+
+delimiter ~~;
+create or replace procedure truncate_sp()
+begin
+ delete history from t before system_time timestamp now(6);
+end~~
+delimiter ;~~
+call truncate_sp;
+select * from t for system_time all;
+
+drop procedure truncate_sp;
+
+--echo ### Issue #399, truncate partitioned table is now unimplemented
+
+create or replace table t (a int)
+with system versioning
+engine myisam
+partition by system_time (
+ partition p0 history,
+ partition pn current);
+
+--error ER_NOT_ALLOWED_COMMAND
+delete history from t;
+
+create or replace table t (i int) with system versioning;
+delete history from t;
+create or replace view v as select * from t;
+--error ER_VERS_TRUNCATE_VIEW
+delete history from v;
+
+create or replace table t (i int);
+--error ER_VERS_NOT_VERSIONED
+delete history from t;
+create or replace view v as select * from t;
+--error ER_VERS_TRUNCATE_VIEW
+delete history from v;
+--error ER_VERS_NOT_VERSIONED
+prepare stmt from 'delete history from t';
+
+drop table t;
+drop view v;
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..dcdad59039a
--- /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
+delete history from mysqltest.t before system_time now();
+
+connection root;
+grant delete history on mysqltest.* to mysqltest_1@localhost;
+grant delete history on mysqltest.t to mysqltest_1@localhost;
+
+connection user1;
+show grants;
+delete history from mysqltest.t before 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/trx_id.test b/mysql-test/suite/versioning/t/trx_id.test
new file mode 100644
index 00000000000..d42333d56d9
--- /dev/null
+++ b/mysql-test/suite/versioning/t/trx_id.test
@@ -0,0 +1,97 @@
+-- source include/have_innodb.inc
+-- source include/not_embedded.inc
+
+select @@system_versioning_transaction_registry;
+
+--error ER_VERS_TRT_IS_DISABLED
+create or replace table t1 (
+ x int,
+ sys_trx_start bigint(20) unsigned as row start invisible,
+ sys_trx_end bigint(20) unsigned as row end invisible,
+ period for system_time (sys_trx_start, sys_trx_end)
+) with system versioning engine innodb;
+
+set global system_versioning_transaction_registry= 1;
+
+create or replace table t1 (
+ x int,
+ sys_trx_start bigint(20) unsigned as row start invisible,
+ sys_trx_end bigint(20) unsigned as row end invisible,
+ period for system_time (sys_trx_start, sys_trx_end)
+) with system versioning engine innodb;
+
+insert into t1 (x) values (1);
+
+set global system_versioning_transaction_registry= 0;
+--error ER_VERS_TRT_IS_DISABLED
+insert into t1 (x) values (2);
+--error ER_VERS_TRT_IS_DISABLED
+delete from t1;
+--error ER_VERS_TRT_IS_DISABLED
+update t1 set x= 3;
+
+--echo # ALTER ADD SYSTEM VERSIONING should write to mysql.transaction_registry
+create function check_result (cond boolean)
+ returns char(50) deterministic
+ return if(cond = 1, '[CORRECT]', '[INCORRECT]');
+
+set @@system_versioning_alter_history=keep;
+set global system_versioning_transaction_registry=on;
+
+create or replace table t1 (x int) engine innodb;
+insert into t1 values (1);
+alter table t1
+ add column s bigint unsigned as row start,
+ add column e bigint unsigned as row end,
+ add period for system_time(s, e),
+ add system versioning,
+ algorithm=inplace;
+select s from t1 into @trx_start;
+select check_result(count(*) = 1) from mysql.transaction_registry where transaction_id = @trx_start;
+
+create or replace table t1 (x int) engine innodb;
+select count(*) from mysql.transaction_registry into @tmp;
+alter table t1
+ add column s bigint unsigned as row start,
+ add column e bigint unsigned as row end,
+ add period for system_time(s, e),
+ add system versioning,
+ algorithm=inplace;
+select check_result(count(*) = @tmp) from mysql.transaction_registry;
+
+create or replace table t1 (x int) engine innodb;
+insert into t1 values (1);
+alter table t1
+ add column s bigint unsigned as row start,
+ add column e bigint unsigned as row end,
+ add period for system_time(s, e),
+ add system versioning,
+ algorithm=copy;
+select s from t1 into @trx_start;
+select check_result(count(*) = 1) from mysql.transaction_registry where transaction_id = @trx_start;
+
+create or replace table t1 (x int) engine innodb;
+select count(*) from mysql.transaction_registry into @tmp;
+alter table t1
+ add column s bigint unsigned as row start,
+ add column e bigint unsigned as row end,
+ add period for system_time(s, e),
+ add system versioning,
+ algorithm=copy;
+select check_result(count(*) = @tmp) from mysql.transaction_registry;
+
+
+--echo # TRX_ID to TIMESTAMP versioning switch
+create or replace table t1 (
+ x int,
+ sys_start bigint unsigned as row start invisible,
+ sys_end bigint unsigned as row end invisible,
+ period for system_time (sys_start, sys_end)
+) engine innodb with system versioning;
+insert into t1 values (1);
+alter table t1 drop column sys_start, drop column sys_end;
+select sys_end = 18446744073709551615 as transaction_based from t1 for system_time all;
+
+drop table t1;
+set global system_versioning_transaction_registry=off;
+drop function check_result;
diff --git a/mysql-test/suite/versioning/t/update.test b/mysql-test/suite/versioning/t/update.test
new file mode 100644
index 00000000000..bda908f4b54
--- /dev/null
+++ b/mysql-test/suite/versioning/t/update.test
@@ -0,0 +1,289 @@
+-- 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_trx_start ', sys_type, ' as row start invisible,
+ sys_trx_end ', sys_type, ' as row end invisible,
+ period for system_time (sys_trx_start, sys_trx_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,
+ x int,
+ y int without system versioning,
+ sys_trx_start ', sys_type, ' as row start invisible,
+ sys_trx_end ', sys_type, ' as row end invisible,
+ period for system_time (sys_trx_start, sys_trx_end))
+ 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 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 y= 1 where id = 1;
+ select @tmp1 = sys_trx_start as A2, x 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,
+ sys_trx_start bigint unsigned as row start invisible,
+ sys_trx_end bigint unsigned as row end invisible,
+ period for system_time (sys_trx_start, sys_trx_end)
+ ) 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), (4, 1), (5, 1);
+
+ start transaction;
+ update t1 set y= y + 1 where x = 3;
+ update t1 set y= y + 1 where x = 2;
+ update t1 set y= y + 1 where x = 3;
+ update t1 set y= y + 1 where x > 3;
+ update t1 set y= y + 1 where x > 4;
+ commit;
+
+ select x, y, sys_trx_end = 18446744073709551615 as current from t1 for system_time all;
+
+ 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,
+ sys_trx_start ', sys_type, ' as row start invisible,
+ sys_trx_end ', sys_type, ' as row end invisible,
+ period for system_time (sys_trx_start, sys_trx_end))
+ 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,
+ sys_trx_end ', sys_type, ' as row end invisible,
+ sys_trx_start ', sys_type, ' as row start invisible,
+ y int unsigned,
+ period for system_time (sys_trx_start, sys_trx_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),
+ (3, 3000),
+ (4, 4000),
+ (5, 5000);
+ insert into t1(x, y) values(3, 3000) 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 all;
+ 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_trx_start ', sys_type, ' as row start invisible,
+ sys_trx_end ', sys_type, ' as row end invisible,
+ period for system_time (sys_trx_start, sys_trx_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 without system versioning,
+ name varchar(128),
+ salary bigint without system versioning,
+ sys_trx_start ', sys_type, ' as row start invisible,
+ sys_trx_end ', sys_type, ' as row end invisible,
+ period for system_time (sys_trx_start, sys_trx_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 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_trx_end');
+call test_01('timestamp(6)', 'innodb', 'vtq_commit_ts(sys_trx_end)');
+call test_01('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_trx_end)');
+call verify_vtq;
+
+call test_02('timestamp(6)', 'myisam', 'sys_trx_end');
+call test_02('timestamp(6)', 'innodb', 'vtq_commit_ts(sys_trx_end)');
+call test_02('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_trx_end)');
+call verify_vtq;
+
+--echo # Multiple UPDATE of same rows in single transaction create historical
+--echo # rows only once (applicable to transaction-based only).
+call test_03('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_trx_end)');
+call verify_vtq;
+
+call test_04('timestamp(6)', 'myisam', 'sys_trx_end');
+call test_04('timestamp(6)', 'innodb', 'vtq_commit_ts(sys_trx_end)');
+call test_04('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_trx_end)');
+call verify_vtq;
+
+call test_05('timestamp(6)', 'myisam', 'sys_trx_end');
+call test_05('timestamp(6)', 'innodb', 'vtq_commit_ts(sys_trx_end)');
+call test_05('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_trx_end)');
+call verify_vtq;
+
+call test_06('timestamp(6)', 'myisam', 'sys_trx_end');
+call test_06('timestamp(6)', 'innodb', 'vtq_commit_ts(sys_trx_end)');
+call test_06('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_trx_end)');
+call verify_vtq;
+
+--echo # Optimized fields
+call test_07('timestamp(6)', 'myisam', 'sys_trx_end');
+call test_07('timestamp(6)', 'innodb', 'vtq_commit_ts(sys_trx_end)');
+call test_07('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_trx_end)');
+call verify_vtq;
+
+--echo ### Issue #365, bug 7 (duplicate of historical row)
+set timestamp= 1000000019;
+create or replace table t1 (a int primary key, b int)
+with system versioning engine myisam;
+insert into t1 (a) values (1);
+update t1 set b= 2;
+--error ER_DUP_ENTRY
+insert into t1 (a) values (1) on duplicate key update a= 2;
+
+drop database test;
+create database test;
diff --git a/mysql-test/suite/versioning/t/view.test b/mysql-test/suite/versioning/t/view.test
new file mode 100644
index 00000000000..56e322477e7
--- /dev/null
+++ b/mysql-test/suite/versioning/t/view.test
@@ -0,0 +1,102 @@
+--source suite/versioning/engines.inc
+--source suite/versioning/common.inc
+
+create or replace table t1 (x int) with system versioning;
+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 or replace 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 or replace view vt2 as select *, row_end from t1 for system_time as of timestamp '", @t2, "'");
+prepare stmt from @vt2; execute stmt; drop prepare stmt;
+
+select * from t1;
+
+create or replace view vt1 as select * from t1;
+--replace_result 18446744073709551615 MAX_RESULT "TIMESTAMP'2038-01-19 03:14:07.999999'" MAX_RESULT
+show create view vt1;
+
+drop view vt1;
+drop view vt2;
+
+create or replace view vt1 as select * from t1 for system_time all;
+select * from vt1;
+prepare stmt from 'select * from vt1'; execute stmt; drop prepare stmt;
+
+set @str= concat('create or replace view vt1 as
+select * from t1 for system_time as of timestamp "', @t1, '"');
+prepare stmt from @str; execute stmt; drop prepare stmt;
+select * from t1 for system_time as of timestamp @t1;
+select * from vt1;
+
+insert into vt1 values (3);
+select * from t1;
+select * from vt1;
+
+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;
+
+select * from vt1;
+
+--echo # VIEW with parameters [#151]
+create or replace table t1 (x int) with system versioning;
+create or replace view vt1(c) as select x from t1;
+--replace_result 18446744073709551615 MAX_RESULT "TIMESTAMP'2038-01-19 03:14:07.999999'" MAX_RESULT
+show create view vt1;
+
+--echo # VIEW over JOIN of versioned tables [#153]
+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;
+
+--echo # VIEW improvements [#183]
+create or replace table t3 (x int);
+create or replace view vt1 as select * from t1, t2, t3;
+--replace_result 18446744073709551615 MAX_RESULT "TIMESTAMP'2038-01-19 03:14:07.999999'" MAX_RESULT
+show create view vt1;
+create or replace view vt1 as select * from t3, t2, t1;
+--replace_result 18446744073709551615 MAX_RESULT "TIMESTAMP'2038-01-19 03:14:07.999999'" MAX_RESULT
+show create view vt1;
+create or replace view vt1 as select a, t2.row_end as endo from t3, t1, t2;
+--replace_result 18446744073709551615 MAX_RESULT "TIMESTAMP'2038-01-19 03:14:07.999999'" MAX_RESULT
+show create view vt1;
+
+--echo # VIEW over UNION [#269]
+create or replace view vt1 as select * from t1 union select * from t1;
+select * from vt1;
+
+--echo # VIEW over UNION with non-versioned [#393]
+create or replace table t2 (a int);
+create or replace view vt1 as select * from t1 union select * from t2;
+select * from vt1;
+
+--echo # MDEV-14689 crash on second PS execute
+create or replace table t1 (a int);
+create or replace view v1 as select * from t1;
+create or replace table t2 (b int) with system versioning;
+prepare stmt from 'select a from v1 inner join t2 group by a order by a';
+execute stmt;
+execute stmt;
+
+
+drop database test;
+create database test;
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..56bdb3d2546
--- /dev/null
+++ b/mysql-test/suite/versioning/t/vtmd.test
@@ -0,0 +1,204 @@
+-- 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, '
+ 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;
+
+ 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 with system versioning as
+ 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;
+ 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 ;~~
+
+delimiter ~~;
+create or replace procedure show_tables()
+begin
+ show tables;
+ select table_name, table_schema from information_schema.tables
+ where table_schema not in ('mysql', 'performance_schema', 'information_schema', 'mtr')
+ order by table_name;
+end~~
+delimiter ;~~
+
+# create
+set versioning_alter_history= keep;
+create table t0 (z int) with system versioning;
+show tables;
+set versioning_alter_history= survive;
+create or replace table t0 (y int) with system versioning;
+show tables;
+show create table t0_vtmd;
+call check_vtmd('t0_vtmd');
+
+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
+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');
+drop table t0_vtmd;
+alter table t0 drop column y;
+call check_vtmd('t0_vtmd');
+
+call drop_archives('t0_vtmd');
+set versioning_alter_history= keep;
+drop tables t0, t0_vtmd;
+set versioning_alter_history= survive;
+
+# rename
+set versioning_alter_history= keep;
+create or replace table x0 (x int) with system versioning;
+set versioning_alter_history= survive;
+rename table x0 to d0;
+show tables;
+
+set versioning_alter_history= keep;
+drop table d0;
+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_alter_history= keep;
+drop table d0;
+set versioning_alter_history= survive;
+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;
+show tables;
+call test.check_vtmd('db0.t0_vtmd');
+
+create database db1;
+rename table t0 to db1.other_name;
+show tables;
+use db1;
+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;
+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');
+
+# hide archive tables
+set versioning_hide= auto;
+call show_tables();
+
+set versioning_hide= implicit;
+call show_tables();
+
+set versioning_hide= full;
+call show_tables();
+
+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;
+
+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;
+create database test;
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..4397198c839
--- /dev/null
+++ b/mysql-test/suite/versioning/t/vtmd_show.test
@@ -0,0 +1,90 @@
+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, '
+ 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;
+
+ 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_VERS_VTMD_ERROR
+show create table t for system_time as of now;
+
+set versioning_alter_history=survive;
+
+create or replace table t (a int) with system versioning;
+--error ER_VERS_RANGE_PROHIBITED
+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_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/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test
index 85f60964c3b..6dde5aa7bc6 100644
--- a/mysql-test/t/mysqldump.test
+++ b/mysql-test/t/mysqldump.test
@@ -1453,7 +1453,7 @@ insert into u1 values (4);
create view v1 (c1) as select * from t1;
# Backup should not fail for Bug#21527. Flush priviliges test begins.
---exec $MYSQL_DUMP --skip-comments --add-drop-table --flush-privileges --ignore-table=mysql.general_log --ignore-table=mysql.slow_log --databases mysqldump_myDB mysql > $MYSQLTEST_VARDIR/tmp/bug21527.sql
+--exec $MYSQL_DUMP --skip-comments --add-drop-table --flush-privileges --ignore-table=mysql.general_log --ignore-table=mysql.slow_log --ignore-table=mysql.transaction_registry --databases mysqldump_myDB mysql > $MYSQLTEST_VARDIR/tmp/bug21527.sql
# Clean up
connection root;
diff --git a/mysql-test/t/partition_alter.test b/mysql-test/t/partition_alter.test
index ce6672c4b9d..62a3e1c0777 100644
--- a/mysql-test/t/partition_alter.test
+++ b/mysql-test/t/partition_alter.test
@@ -114,3 +114,14 @@ insert into t1 values(0, 1, 1, NULL, now(), now());
alter online table t1 delay_key_write=1;
show create table t1;
drop table t1;
+
+#
+# MDEV-14817 Server crashes in prep_alter_part_table() after table lock and multiple add partition
+#
+create or replace table t1 (x int) partition by hash (x) (partition p1, partition p2);
+lock table t1 write;
+--error ER_SAME_NAME_PARTITION
+alter table t1 add partition (partition p1);
+--error ER_SAME_NAME_PARTITION
+alter table t1 add partition (partition p1);
+drop table t1;
diff --git a/mysql-test/t/system_mysql_db_fix40123.test b/mysql-test/t/system_mysql_db_fix40123.test
index fd1212d4ce6..2d17a0964e5 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, transaction_registry, 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..9506c3465e7 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, transaction_registry, 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..f8bef3da162 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, transaction_registry, table_stats, column_stats, index_stats, roles_mapping, gtid_slave_pos;
-- enable_query_log
diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c
index 678bfc459c7..42d144b3856 100644
--- a/mysys/my_thr_init.c
+++ b/mysys/my_thr_init.c
@@ -341,14 +341,12 @@ void my_thread_end(void)
tmp, pthread_self(), tmp ? (long) tmp->id : 0L);
#endif
-#ifdef HAVE_PSI_INTERFACE
/*
Remove the instrumentation for this thread.
This must be done before trashing st_my_thread_var,
because the LF_HASH depends on it.
*/
- PSI_THREAD_CALL(delete_current_thread)();
-#endif
+ PSI_CALL_delete_current_thread();
/*
We need to disable DBUG early for this thread to ensure that the
diff --git a/plugin/versioning/CMakeLists.txt b/plugin/versioning/CMakeLists.txt
new file mode 100644
index 00000000000..fc741121e10
--- /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(test_versioning versioning.cc RECOMPILE_FOR_EMBEDDED
+ MODULE_ONLY COMPONENT Test)
diff --git a/plugin/versioning/versioning.cc b/plugin/versioning/versioning.cc
new file mode 100644
index 00000000000..e48f74bc4cb
--- /dev/null
+++ b/plugin/versioning/versioning.cc
@@ -0,0 +1,204 @@
+/* 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 */
+
+#define MYSQL_SERVER 1
+#include <my_global.h>
+#include <mysql_version.h>
+#include <mysqld.h>
+#include <mysql/plugin.h>
+#include "sql_plugin.h" // st_plugin_int
+#include "sql_class.h"
+#include "item.h"
+#include "vers_utils.h"
+
+/* System Versioning: VTQ_TRX_ID(), VTQ_COMMIT_ID(), VTQ_BEGIN_TS(), VTQ_COMMIT_TS(), VTQ_ISO_LEVEL() */
+template <TR_table::field_id_t VTQ_FIELD>
+class Create_func_vtq : public Create_native_func
+{
+public:
+ virtual Item *create_native(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
+
+ static Create_func_vtq<VTQ_FIELD> s_singleton;
+
+protected:
+ Create_func_vtq<VTQ_FIELD>() {}
+ virtual ~Create_func_vtq<VTQ_FIELD>() {}
+};
+
+template<TR_table::field_id_t VTQ_FIELD>
+Create_func_vtq<VTQ_FIELD> Create_func_vtq<VTQ_FIELD>::s_singleton;
+
+template <TR_table::field_id_t VTQ_FIELD>
+Item*
+Create_func_vtq<VTQ_FIELD>::create_native(THD *thd, LEX_CSTRING *name,
+ List<Item> *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 TR_table::FLD_BEGIN_TS:
+ case TR_table::FLD_COMMIT_TS:
+ func= new (thd->mem_root) Item_func_vtq_ts(thd, param_1, VTQ_FIELD);
+ break;
+ case TR_table::FLD_TRX_ID:
+ case TR_table::FLD_COMMIT_ID:
+ case TR_table::FLD_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 TR_table::FLD_TRX_ID:
+ case TR_table::FLD_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 Item_func_vtq_trx_seesX>
+class Create_func_vtq_trx_sees : public Create_native_func
+{
+public:
+ virtual Item *create_native(THD *thd, LEX_CSTRING *name, List<Item> *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<Item_func_vtq_trx_seesX> s_singleton;
+
+protected:
+ Create_func_vtq_trx_sees<Item_func_vtq_trx_seesX>() {}
+ virtual ~Create_func_vtq_trx_sees<Item_func_vtq_trx_seesX>() {}
+};
+
+template<class X>
+Create_func_vtq_trx_sees<X> Create_func_vtq_trx_sees<X>::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<TR_table::FLD_BEGIN_TS>)},
+ { { C_STRING_WITH_LEN("VTQ_COMMIT_ID") }, BUILDER(Create_func_vtq<TR_table::FLD_COMMIT_ID>)},
+ { { C_STRING_WITH_LEN("VTQ_COMMIT_TS") }, BUILDER(Create_func_vtq<TR_table::FLD_COMMIT_TS>)},
+ { { C_STRING_WITH_LEN("VTQ_ISO_LEVEL") }, BUILDER(Create_func_vtq<TR_table::FLD_ISO_LEVEL>)},
+ { { C_STRING_WITH_LEN("VTQ_TRX_ID") }, BUILDER(Create_func_vtq<TR_table::FLD_TRX_ID>)},
+ { { C_STRING_WITH_LEN("VTQ_TRX_SEES") }, BUILDER(Create_func_vtq_trx_sees<Item_func_vtq_trx_sees>)},
+ { { C_STRING_WITH_LEN("VTQ_TRX_SEES_EQ") }, BUILDER(Create_func_vtq_trx_sees<Item_func_vtq_trx_sees_eq>)},
+ { {0, 0}, NULL}
+};
+
+
+/*
+ Disable __attribute__() on non-gcc compilers.
+*/
+#if !defined(__attribute__) && !defined(__GNUC__)
+#define __attribute__(A)
+#endif
+
+static int versioning_plugin_init(void *p __attribute__ ((unused)))
+{
+ 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);
+ }
+
+ DBUG_RETURN(0);
+}
+
+static int versioning_plugin_deinit(void *p __attribute__ ((unused)))
+{
+ DBUG_ENTER("versioning_plugin_deinit");
+ DBUG_RETURN(0);
+}
+
+struct st_mysql_daemon versioning_plugin=
+{ MYSQL_REPLICATION_INTERFACE_VERSION };
+
+/*
+ Plugin library descriptor
+*/
+
+maria_declare_plugin(versioning)
+{
+ MYSQL_REPLICATION_PLUGIN, // initialized after MYSQL_STORAGE_ENGINE_PLUGIN
+ &versioning_plugin,
+ "test_versioning",
+ "MariaDB Corp",
+ "System Vesioning testing features",
+ PLUGIN_LICENSE_GPL,
+ versioning_plugin_init, /* Plugin Init */
+ versioning_plugin_deinit, /* Plugin Deinit */
+ 0x0100 /* 1.0 */,
+ NULL, /* status variables */
+ NULL, /* system variables */
+ "1.0", /* string version */
+ MariaDB_PLUGIN_MATURITY_EXPERIMENTAL
+}
+maria_declare_plugin_end;
diff --git a/scripts/mysql_system_tables.sql b/scripts/mysql_system_tables.sql
index a4935361e18..a607c096337 100644
--- a/scripts/mysql_system_tables.sql
+++ b/scripts/mysql_system_tables.sql
@@ -23,17 +23,19 @@ set sql_mode='';
set @orig_storage_engine=@@storage_engine;
set storage_engine=myisam;
+set system_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, Truncate_versioning_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, Truncate_versioning_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;
@@ -49,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';
@@ -129,6 +131,19 @@ 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_transaction_registry="CREATE TABLE IF NOT EXISTS transaction_registry (
+ transaction_id BIGINT UNSIGNED NOT NULL,
+ commit_id BIGINT UNSIGNED NOT NULL,
+ begin_timestamp TIMESTAMP(6) NOT NULL DEFAULT '0000-00-00 00:00:00.000000',
+ commit_timestamp TIMESTAMP(6) NOT NULL DEFAULT '0000-00-00 00:00:00.000000',
+ isolation_level ENUM('READ-UNCOMMITTED', 'READ-COMMITTED',
+ 'REPEATABLE-READ', 'SERIALIZABLE') NOT NULL,
+ PRIMARY KEY (transaction_id),
+ UNIQUE KEY (commit_id),
+ INDEX (begin_timestamp),
+ INDEX (commit_timestamp, transaction_id)
+) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_bin STATS_PERSISTENT=0";
+
SET @str=IF(@have_innodb <> 0, @create_innodb_table_stats, "SET @dummy = 0");
PREPARE stmt FROM @str;
EXECUTE stmt;
@@ -139,6 +154,11 @@ PREPARE stmt FROM @str;
EXECUTE stmt;
DROP PREPARE stmt;
+SET @str=IF(@have_innodb <> 0, @create_transaction_registry, "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.',
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 127e06cda52..44a95483564 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';
@@ -744,3 +744,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 Truncate_versioning_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL DEFAULT 'N' after Trigger_priv;
+ALTER TABLE user modify Truncate_versioning_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL DEFAULT 'N';
+ALTER TABLE db add Truncate_versioning_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL DEFAULT 'N' after Trigger_priv;
+ALTER TABLE db modify Truncate_versioning_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL DEFAULT 'N';
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index 9f796896a41..a412a65ccc9 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -143,6 +143,7 @@ SET (SQL_SOURCE
sql_type.cc
item_windowfunc.cc sql_window.cc
sql_cte.cc
+ item_vers.cc
sql_sequence.cc sql_sequence.h ha_sequence.h
sql_tvc.cc sql_tvc.h
opt_split.cc
@@ -152,6 +153,7 @@ SET (SQL_SOURCE
${CMAKE_CURRENT_BINARY_DIR}/sql_builtin.cc
${GEN_SOURCES}
${MYSYS_LIBWRAP_SOURCE}
+ vtmd.cc
)
IF (CMAKE_SYSTEM_NAME MATCHES "Linux" OR
diff --git a/sql/event_queue.cc b/sql/event_queue.cc
index e46326afe18..9e30534dd14 100644
--- a/sql/event_queue.cc
+++ b/sql/event_queue.cc
@@ -617,7 +617,7 @@ Event_queue::get_top_for_execution_if_time(THD *thd,
top= (Event_queue_element*) queue_top(&queue);
- thd->set_current_time(); /* Get current time */
+ thd->set_start_time(); /* Get current time */
next_activation_at= top->execute_at;
if (next_activation_at > thd->query_start())
diff --git a/sql/field.cc b/sql/field.cc
index 39815adb4b0..642ad6a65e9 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1603,7 +1603,7 @@ String *Field::val_int_as_str(String *val_buffer, bool unsigned_val)
Field::Field(uchar *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,
uchar null_bit_arg,
utype unireg_check_arg, const LEX_CSTRING *field_name_arg)
- :ptr(ptr_arg), field_visibility(NOT_INVISIBLE),
+ :ptr(ptr_arg), invisible(VISIBLE),
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),
@@ -2002,6 +2002,48 @@ bool Field_num::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
}
+bool Field_vers_trx_id::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(VERS_TRX_ID) ||
+ (table->versioned() && table->s->table_category == TABLE_CATEGORY_TEMPORARY));
+ if (!trx_id)
+ return true;
+
+ THD *thd= get_thd();
+ DBUG_ASSERT(thd);
+ if (trx_id == ULONGLONG_MAX)
+ {
+ 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)
+ {
+ *ltime= cache;
+ return false;
+ }
+
+ TR_table trt(thd);
+ bool found= trt.query(trx_id);
+ if (found)
+ {
+ trt[TR_table::FLD_COMMIT_TS]->get_date(&cache, fuzzydate);
+ *ltime= cache;
+ cached= trx_id;
+ return false;
+ }
+
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_VERS_NO_TRX_ID, ER_THD(thd, ER_VERS_NO_TRX_ID),
+ trx_id);
+ 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 LEX_CSTRING *field_name_arg,
@@ -2194,9 +2236,11 @@ Field *Field::make_new_field(MEM_ROOT *root, TABLE *new_table,
*/
tmp->unireg_check= Field::NONE;
tmp->flags&= (NOT_NULL_FLAG | BLOB_FLAG | UNSIGNED_FLAG |
- ZEROFILL_FLAG | BINARY_FLAG | ENUM_FLAG | SET_FLAG);
+ ZEROFILL_FLAG | BINARY_FLAG | ENUM_FLAG | SET_FLAG |
+ VERS_SYS_START_FLAG | VERS_SYS_END_FLAG |
+ VERS_UPDATE_UNVERSIONED_FLAG);
tmp->reset_fields();
- tmp->field_visibility= NOT_INVISIBLE;
+ tmp->invisible= VISIBLE;
return tmp;
}
@@ -4312,6 +4356,26 @@ void Field_longlong::sql_type(String &res) const
add_zerofill_and_unsigned(res);
}
+void Field_longlong::set_max()
+{
+ ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ set_notnull();
+ int8store(ptr, unsigned_flag ? ULONGLONG_MAX : LONGLONG_MAX);
+}
+
+bool Field_longlong::is_max()
+{
+ ASSERT_COLUMN_MARKED_FOR_READ;
+ if (unsigned_flag)
+ {
+ ulonglong j;
+ j= uint8korr(ptr);
+ return j == ULONGLONG_MAX;
+ }
+ longlong j;
+ j= sint8korr(ptr);
+ return j == LONGLONG_MAX;
+}
/*
Floating-point numbers
@@ -5354,6 +5418,27 @@ void Field_timestampf::store_TIME(my_time_t timestamp, ulong sec_part)
my_timestamp_to_binary(&tm, ptr, dec);
}
+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);
+ mi_int3store(ptr + 4, TIME_MAX_SECOND_PART);
+
+ DBUG_VOID_RETURN;
+}
+
+bool Field_timestampf::is_max()
+{
+ DBUG_ENTER("Field_timestampf::is_max");
+ ASSERT_COLUMN_MARKED_FOR_READ;
+
+ 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,
ulong *sec_part) const
@@ -10372,7 +10457,8 @@ Field *make_field(TABLE_SHARE *share,
Field::geometry_type geom_type, uint srid,
Field::utype unireg_check,
TYPELIB *interval,
- const LEX_CSTRING *field_name)
+ const LEX_CSTRING *field_name,
+ uint32 flags)
{
uchar *UNINIT_VAR(bit_ptr);
uchar UNINIT_VAR(bit_offset);
@@ -10557,11 +10643,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_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);
+ }
+ 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 ?
@@ -10638,6 +10735,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. */
@@ -10659,7 +10761,8 @@ Column_definition::Column_definition(THD *thd, Field *old_field,
option_list= old_field->option_list;
pack_flag= 0;
compression_method_ptr= 0;
- field_visibility= old_field->field_visibility;
+ versioning= VERSIONING_NOT_SET;
+ invisible= old_field->invisible;
if (orig_field)
{
@@ -10797,7 +10900,7 @@ Column_definition::redefine_stage1_common(const Column_definition *dup_field,
flags= dup_field->flags;
interval= dup_field->interval;
vcol_info= dup_field->vcol_info;
- field_visibility= dup_field->field_visibility;
+ invisible= dup_field->invisible;
}
diff --git a/sql/field.h b/sql/field.h
index 0bff381360b..9fd584e88c2 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -675,9 +675,17 @@ public:
static void operator delete(void *ptr, MEM_ROOT *mem_root)
{ DBUG_ASSERT(0); }
+ /**
+ Used by System Versioning.
+ */
+ virtual void set_max()
+ { DBUG_ASSERT(0); }
+ virtual bool is_max()
+ { DBUG_ASSERT(0); return false; }
+
uchar *ptr; // Position to field in record
- field_visible_type field_visibility;
+ field_visibility_t invisible;
/**
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.
@@ -1008,6 +1016,13 @@ public:
}
bool set_explicit_default(Item *value);
+ virtual my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const
+ { DBUG_ASSERT(0); return 0; }
+ my_time_t get_timestamp(ulong *sec_part) const
+ {
+ return get_timestamp(ptr, sec_part);
+ }
+
/**
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,
@@ -1449,6 +1464,25 @@ public:
FIELD_FLAGS_COLUMN_FORMAT;
}
+ bool vers_sys_field() const
+ {
+ return flags & (VERS_SYS_START_FLAG | VERS_SYS_END_FLAG);
+ }
+
+ bool vers_update_unversioned() const
+ {
+ return flags & VERS_UPDATE_UNVERSIONED_FLAG;
+ }
+
+#ifdef VERS_EXPERIMENTAL
+ bool vers_sys_invisible(THD *thd) const;
+#endif
+
+ 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.
@@ -2156,6 +2190,57 @@ public:
{
return unpack_int64(to, from, from_end);
}
+
+ void set_max();
+ bool is_max();
+};
+
+
+class Field_vers_trx_id :public Field_longlong {
+ MYSQL_TIME cache;
+ ulonglong cached;
+public:
+ Field_vers_trx_id(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ uchar null_bit_arg, enum utype unireg_check_arg,
+ const LEX_CSTRING *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_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;
+ }
};
@@ -2438,7 +2523,7 @@ public:
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(const uchar *pos, ulong *sec_part) const;
my_time_t get_timestamp(ulong *sec_part) const
{
return get_timestamp(ptr, sec_part);
@@ -2568,8 +2653,14 @@ public:
{
return memcmp(a_ptr, b_ptr, pack_length());
}
+ void 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(ulong *sec_part) const
+ {
+ return get_timestamp(ptr, sec_part);
+ }
uint size_of() const { return sizeof(*this); }
};
@@ -3990,7 +4081,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 LEX_CSTRING *field_name);
+ TYPELIB *interval, const LEX_CSTRING *field_name,
+ uint32 flags);
/*
Create field class for CREATE TABLE
@@ -4044,13 +4136,19 @@ class Column_definition: public Sql_alloc,
public:
LEX_CSTRING field_name;
LEX_CSTRING comment; // Comment for field
+ enum enum_column_versioning
+ {
+ VERSIONING_NOT_SET,
+ WITH_VERSIONING,
+ WITHOUT_VERSIONING
+ };
Item *on_update; // ON UPDATE NOW()
/*
At various stages in execution this can be length of field in bytes or
max number of characters.
*/
ulonglong length;
- field_visible_type field_visibility;
+ field_visibility_t invisible;
/*
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.
@@ -4077,19 +4175,23 @@ public:
*default_value, // Default value
*check_constraint; // Check constraint
+ enum_column_versioning versioning;
+
Column_definition()
:Type_handler_hybrid_field_type(&type_handler_null),
compression_method_ptr(0),
comment(null_clex_str),
- on_update(NULL), length(0),field_visibility(NOT_INVISIBLE), decimals(0),
+ on_update(NULL), length(0), invisible(VISIBLE), 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), 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();
}
+
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_null()
@@ -4216,7 +4318,7 @@ public:
(uint32)length, null_pos, null_bit,
pack_flag, type_handler(), 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 LEX_CSTRING *field_name_arg) const
@@ -4558,6 +4660,21 @@ bool check_expression(Virtual_column_info *vcol, LEX_CSTRING *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_visibility(x) (static_cast<field_visible_type> ((x) & 3))
+#define f_visibility(x) (static_cast<field_visibility_t> ((x) & INVISIBLE_MAX_BITS))
+
+inline
+ulonglong TABLE::vers_end_id() const
+{
+ DBUG_ASSERT(versioned(VERS_TRX_ID));
+ return static_cast<ulonglong>(vers_end_field()->val_int());
+}
+
+inline
+ulonglong TABLE::vers_start_id() const
+{
+ DBUG_ASSERT(versioned(VERS_TRX_ID));
+ return static_cast<ulonglong>(vers_start_field()->val_int());
+}
+
#endif /* FIELD_INCLUDED */
diff --git a/sql/gen_lex_token.cc b/sql/gen_lex_token.cc
index 4b5e0746eac..b36df5e94be 100644
--- a/sql/gen_lex_token.cc
+++ b/sql/gen_lex_token.cc
@@ -130,6 +130,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(VALUES_IN_SYM, "VALUES IN");
set_token(VALUES_LESS_SYM, "VALUES LESS");
set_token(NOT2_SYM, "!");
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index 44ae66c76c8..20fa2eabea1 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -155,9 +155,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;
@@ -1285,12 +1282,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, ...)
@@ -2121,7 +2118,7 @@ void ha_partition::update_create_info(HA_CREATE_INFO *create_info)
HA_STATUS_AUTO is optimized so it will not always be forwarded
to all partitions, but HA_STATUS_VARIABLE will.
*/
- info(HA_STATUS_VARIABLE);
+ info(HA_STATUS_VARIABLE | HA_STATUS_OPEN);
info(HA_STATUS_AUTO);
@@ -3610,7 +3607,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_VARIABLE | HA_STATUS_CONST | HA_STATUS_OPEN);
DBUG_RETURN(0);
err_handler:
@@ -4374,6 +4371,15 @@ int ha_partition::update_row(const uchar *old_data, const 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 HISTORY 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);
@@ -5822,6 +5828,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 a13d9bd7618..ac41de16f20 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -79,6 +79,10 @@ struct st_partition_ft_info
};
+#ifdef HAVE_PSI_MUTEX_INTERFACE
+extern PSI_mutex_key key_partition_auto_inc_mutex;
+#endif
+
/**
Partition specific Handler_share.
*/
@@ -96,24 +100,86 @@ public:
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),
+ 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);
- DBUG_VOID_RETURN;
+ }
}
+
bool init(uint num_parts);
- void lock_auto_inc()
+
+ /**
+ 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);
};
typedef struct st_partition_key_multi_range
@@ -679,6 +745,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
@@ -1406,6 +1476,31 @@ public:
return h;
}
+ virtual ha_rows part_records(void *_part_elem)
+ {
+ partition_element *part_elem= reinterpret_cast<partition_element *>(_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_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_OPEN);
+ 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);
friend int cmp_key_part_id(void *key_p, uchar *ref1, uchar *ref2);
};
diff --git a/sql/ha_sequence.cc b/sql/ha_sequence.cc
index 93f6f32d473..4afa2168b8d 100644
--- a/sql/ha_sequence.cc
+++ b/sql/ha_sequence.cc
@@ -259,7 +259,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;
}
diff --git a/sql/handler.cc b/sql/handler.cc
index b16f8b88c20..a7530723c79 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -1415,6 +1415,40 @@ int ha_commit_trans(THD *thd, bool all)
goto err;
}
+#if 1 // FIXME: This should be done in ha_prepare().
+ if (rw_trans || (thd->lex->sql_command == SQLCOM_ALTER_TABLE &&
+ thd->lex->alter_info.flags & Alter_info::ALTER_ADD_SYSTEM_VERSIONING))
+ {
+ ulonglong trx_start_id= 0, trx_end_id= 0;
+ for (Ha_trx_info *ha_info= trans->ha_list; ha_info; ha_info= ha_info->next())
+ {
+ if (ha_info->ht()->prepare_commit_versioned)
+ {
+ trx_end_id= ha_info->ht()->prepare_commit_versioned(thd, &trx_start_id);
+ if (trx_end_id)
+ break; // FIXME: use a common ID for cross-engine transactions
+ }
+ }
+
+ if (trx_end_id)
+ {
+ if (!use_transaction_registry)
+ {
+ my_error(ER_VERS_TRT_IS_DISABLED, MYF(0));
+ goto err;
+ }
+ DBUG_ASSERT(trx_start_id);
+ TR_table trt(thd, true);
+ if (trt.update(trx_start_id, trx_end_id))
+ goto err;
+ // Here, the call will not commit inside InnoDB. It is only working
+ // around closing thd->transaction.stmt open by TR_table::open().
+ if (all)
+ commit_one_phase_2(thd, false, &thd->transaction.stmt, false);
+ }
+ }
+#endif
+
if (trans->no_2pc || (rw_ha_count <= 1))
{
error= ha_commit_one_phase(thd, all);
@@ -3025,45 +3059,6 @@ void handler::adjust_next_insert_id_after_explicit_value(ulonglong nr)
}
-/** @brief
- Computes the largest number X:
- - smaller than or equal to "nr"
- - of the form: auto_increment_offset + N * auto_increment_increment
- where N>=0.
-
- SYNOPSIS
- prev_insert_id
- nr Number to "round down"
- variables variables struct containing auto_increment_increment and
- auto_increment_offset
-
- RETURN
- The number X if it exists, "nr" otherwise.
-*/
-inline ulonglong
-prev_insert_id(ulonglong nr, struct system_variables *variables)
-{
- if (unlikely(nr < variables->auto_increment_offset))
- {
- /*
- There's nothing good we can do here. That is a pathological case, where
- the offset is larger than the column's max possible value, i.e. not even
- the first sequence value may be inserted. User will receive warning.
- */
- DBUG_PRINT("info",("auto_increment: nr: %lu cannot honour "
- "auto_increment_offset: %lu",
- (ulong) nr, variables->auto_increment_offset));
- return nr;
- }
- if (variables->auto_increment_increment == 1)
- return nr; // optimization of the formula below
- nr= (((nr - variables->auto_increment_offset)) /
- (ulonglong) variables->auto_increment_increment);
- return (nr * (ulonglong) variables->auto_increment_increment +
- variables->auto_increment_offset);
-}
-
-
/**
Update the auto_increment field if necessary.
@@ -3176,6 +3171,25 @@ int handler::update_auto_increment()
DBUG_RETURN(0);
}
+ // ALTER TABLE ... ADD COLUMN ... AUTO_INCREMENT
+ if (thd->lex->sql_command == SQLCOM_ALTER_TABLE)
+ {
+ if (table->versioned())
+ {
+ Field *end= table->vers_end_field();
+ DBUG_ASSERT(end);
+ bitmap_set_bit(table->read_set, end->field_index);
+ if (!end->is_max())
+ {
+ if (!table->next_number_field->real_maybe_null())
+ DBUG_RETURN(HA_ERR_UNSUPPORTED);
+ table->next_number_field->set_null();
+ DBUG_RETURN(0);
+ }
+ }
+ table->next_number_field->set_notnull();
+ }
+
if ((nr= next_insert_id) >= auto_inc_interval_for_cur_row.maximum())
{
/* next_insert_id is beyond what is reserved, so we reserve more. */
@@ -3275,7 +3289,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
@@ -4395,6 +4409,9 @@ handler::check_if_supported_inplace_alter(TABLE *altered_table,
HA_CREATE_INFO *create_info= ha_alter_info->create_info;
+ if (altered_table->versioned(VERS_TIMESTAMP))
+ DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+
Alter_inplace_info::HA_ALTER_FLAGS inplace_offline_operations=
Alter_inplace_info::ALTER_COLUMN_EQUAL_PACK_LENGTH |
Alter_inplace_info::ALTER_COLUMN_NAME |
@@ -5853,8 +5870,10 @@ 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 (table->versioned(VERS_TRX_ID))
+ 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)))
@@ -6003,10 +6022,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;
@@ -6041,16 +6060,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)
{
@@ -6200,7 +6209,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);
@@ -6232,7 +6242,8 @@ int handler::ha_update_row(const uchar *old_data, const 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))
+ error= binlog_log_row(table, old_data, new_data, log_func);
}
return error;
}
@@ -6287,7 +6298,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;
}
@@ -6820,3 +6832,699 @@ int del_global_index_stat(THD *thd, TABLE* table, KEY* key_info)
mysql_mutex_unlock(&LOCK_global_index_stats);
DBUG_RETURN(res);
}
+
+bool Vers_parse_info::is_start(const char *name) const
+{
+ DBUG_ASSERT(name);
+ return as_row.start && as_row.start == LString_i(name);
+}
+bool Vers_parse_info::is_end(const char *name) const
+{
+ DBUG_ASSERT(name);
+ return as_row.end && as_row.end == LString_i(name);
+}
+bool Vers_parse_info::is_start(const Create_field &f) const
+{
+ return f.flags & VERS_SYS_START_FLAG;
+}
+bool Vers_parse_info::is_end(const Create_field &f) const
+{
+ return f.flags & VERS_SYS_END_FLAG;
+}
+
+static Create_field *vers_init_sys_field(THD *thd, const char *field_name, int flags, bool integer)
+{
+ Create_field *f= new (thd->mem_root) Create_field();
+ if (!f)
+ return NULL;
+
+ memset(f, 0, sizeof(*f));
+ f->field_name.str= field_name;
+ f->field_name.length= strlen(field_name);
+ f->charset= system_charset_info;
+ f->flags= flags;
+ if (integer)
+ {
+ f->set_handler(&type_handler_longlong);
+ f->length= MY_INT64_NUM_DECIMAL_DIGITS - 1;
+ f->flags|= UNSIGNED_FLAG;
+ }
+ else
+ {
+ f->set_handler(&type_handler_timestamp2);
+ f->length= MAX_DATETIME_PRECISION;
+ }
+ f->invisible= INVISIBLE_SYSTEM;
+
+ 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)
+{
+ Create_field *f= vers_init_sys_field(thd, field_name, flags, false);
+ if (!f)
+ return true;
+
+ alter_info->flags|= Alter_info::ALTER_ADD_COLUMN;
+ alter_info->create_list.push_back(f);
+
+ return false;
+}
+
+const LString Vers_parse_info::default_start= "row_start";
+const LString Vers_parse_info::default_end= "row_end";
+
+bool Vers_parse_info::fix_implicit(THD *thd, Alter_info *alter_info, int *added)
+{
+ // If user specified some of these he must specify the others too. Do nothing.
+ if (*this)
+ return false;
+
+ alter_info->flags|= Alter_info::ALTER_ADD_COLUMN;
+
+ system_time= start_end_t(default_start, default_end);
+ as_row= system_time;
+
+ if (vers_create_sys_field(thd, default_start, alter_info, VERS_SYS_START_FLAG) ||
+ vers_create_sys_field(thd, default_end, alter_info, VERS_SYS_END_FLAG))
+ {
+ return true;
+ }
+ if (added)
+ *added+= 2;
+ return false;
+}
+
+bool Table_scope_and_contents_source_st::vers_native(THD *thd) const
+{
+ if (ha_check_storage_engine_flag(db_type, HTON_NATIVE_SYS_VERSIONING))
+ return true;
+
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ partition_info *info= thd->work_part_info;
+ if (info && !(used_fields & HA_CREATE_USED_ENGINE))
+ {
+ if (handlerton *hton= info->default_engine_type)
+ return ha_check_storage_engine_flag(hton, HTON_NATIVE_SYS_VERSIONING);
+
+ List_iterator_fast<partition_element> it(info->partitions);
+ while (partition_element *partition_element= it++)
+ {
+ if (partition_element->find_engine_flag(HTON_NATIVE_SYS_VERSIONING))
+ return true;
+ }
+ }
+#endif
+ return false;
+}
+
+bool Table_scope_and_contents_source_st::vers_fix_system_fields(
+ THD *thd,
+ Alter_info *alter_info,
+ const TABLE_LIST &create_table,
+ const TABLE_LIST *select_tables,
+ List<Item> *items,
+ bool *versioned_write)
+{
+ DBUG_ASSERT(!(alter_info->flags & Alter_info::ALTER_DROP_SYSTEM_VERSIONING));
+ int vers_tables= 0;
+
+ if (select_tables)
+ {
+ for (const TABLE_LIST *table= select_tables; table; table= table->next_local)
+ {
+ if (table->table && table->table->versioned())
+ vers_tables++;
+ }
+ }
+
+#ifdef VERS_EXPERIMENTAL
+ if (thd->variables.vers_force)
+ {
+ alter_info->flags|= Alter_info::ALTER_ADD_SYSTEM_VERSIONING;
+ options|= HA_VERSIONED_TABLE;
+ }
+#endif
+
+ // Possibly override default storage engine to match one used in source table.
+ if (vers_tables && alter_info->flags & Alter_info::ALTER_ADD_SYSTEM_VERSIONING &&
+ !(used_fields & HA_CREATE_USED_ENGINE))
+ {
+ List_iterator_fast<Create_field> it(alter_info->create_list);
+ while (Create_field *f= it++)
+ {
+ if (vers_info.is_start(*f) || vers_info.is_end(*f))
+ {
+ if (f->field)
+ {
+ db_type= f->field->orig_table->file->ht;
+ }
+ break;
+ }
+ }
+ }
+
+ if (!vers_info.need_check(alter_info))
+ return false;
+
+ if (!vers_info.versioned_fields && vers_info.unversioned_fields &&
+ !(alter_info->flags & Alter_info::ALTER_ADD_SYSTEM_VERSIONING))
+ {
+ // All is correct but this table is not versioned.
+ options&= ~HA_VERSIONED_TABLE;
+ return false;
+ }
+
+ if (!(alter_info->flags & Alter_info::ALTER_ADD_SYSTEM_VERSIONING) && vers_info)
+ {
+ my_error(ER_MISSING, MYF(0), create_table.table_name, "WITH SYSTEM VERSIONING");
+ return true;
+ }
+
+ if (vers_tables)
+ {
+ DBUG_ASSERT(options & HA_VERSIONED_TABLE);
+ DBUG_ASSERT(versioned_write);
+ *versioned_write= true;
+ }
+
+ List_iterator<Create_field> it(alter_info->create_list);
+ bool explicit_declared= vers_info.as_row.start || vers_info.as_row.end;
+ while (Create_field *f= it++)
+ {
+ if ((f->versioning == Column_definition::VERSIONING_NOT_SET &&
+ !(alter_info->flags & Alter_info::ALTER_ADD_SYSTEM_VERSIONING)) ||
+ f->versioning == Column_definition::WITHOUT_VERSIONING)
+ {
+ f->flags|= VERS_UPDATE_UNVERSIONED_FLAG;
+ }
+
+ /* Assign selected implicit fields when no explicit fields */
+ if (!vers_tables || explicit_declared)
+ continue;
+
+ DBUG_ASSERT(versioned_write);
+ if (vers_info.is_start(*f) &&
+ vers_info.default_start == f->field_name)
+ {
+ if (vers_info.as_row.start)
+ it.remove();
+ else
+ {
+ vers_info.set_start(f->field_name);
+ *versioned_write= false;
+ }
+ continue;
+ }
+ if (vers_info.is_end(*f) &&
+ vers_info.default_end == f->field_name)
+ {
+ if (vers_info.as_row.end)
+ it.remove();
+ else
+ {
+ vers_info.set_end(f->field_name);
+ *versioned_write= false;
+ }
+ continue;
+ }
+ } // while (Create_field *f= it++)
+
+ /* Assign selected system fields to explicit system fields if any */
+ if (vers_tables)
+ {
+ it.rewind();
+ while (Create_field *f= it++)
+ {
+ uint flags_left= VERS_SYSTEM_FIELD;
+ if (flags_left && (vers_info.is_start(*f) || vers_info.is_end(*f)) && !f->field)
+ {
+ uint sys_flag= f->flags & flags_left;
+ flags_left-= sys_flag;
+ List_iterator_fast<Item> it2(*items);
+ while (Item *item= it2++)
+ {
+ if (item->type() != Item::FIELD_ITEM)
+ continue;
+ Field *fld= static_cast<Item_field *>(item)->field;
+ DBUG_ASSERT(fld);
+ if ((fld->flags & sys_flag) &&
+ LString_i(f->field_name) == fld->field_name)
+ {
+ f->field= fld;
+ *versioned_write= false;
+ }
+ } // while (item)
+ } // if (flags_left ...
+ } // while (Create_field *f= it++)
+ } // if (vers_tables)
+
+ int added= 0;
+ if (vers_info.fix_implicit(thd, alter_info, &added))
+ return true;
+
+ DBUG_ASSERT(added >= 0);
+ if (vers_tables)
+ {
+ DBUG_ASSERT(items);
+ while (added--)
+ {
+ Item_default_value *item= new (thd->mem_root)
+ Item_default_value(thd, thd->lex->current_context());
+ items->push_back(item, thd->mem_root);
+ }
+ }
+
+ int plain_cols= 0; // columns don't have WITH or WITHOUT SYSTEM VERSIONING
+ int vers_cols= 0; // columns have WITH SYSTEM VERSIONING
+ it.rewind();
+ while (const Create_field *f= it++)
+ {
+ if (vers_info.is_start(*f) || vers_info.is_end(*f))
+ continue;
+
+ if (f->versioning == Column_definition::VERSIONING_NOT_SET)
+ plain_cols++;
+ else if (f->versioning == Column_definition::WITH_VERSIONING)
+ vers_cols++;
+ }
+
+ if (!thd->lex->tmp_table() &&
+ // CREATE from SELECT (Create_fields are not yet added)
+ !select_tables &&
+ vers_cols == 0 &&
+ (plain_cols == 0 || !vers_info))
+ {
+ my_error(ER_VERS_TABLE_MUST_HAVE_COLUMNS, MYF(0), create_table.table_name);
+ return true;
+ }
+
+ if (vers_info.check_with_conditions(create_table.table_name))
+ return true;
+
+ bool native= vers_native(thd);
+ if (vers_info.check_sys_fields(create_table.table_name, alter_info, native))
+ return true;
+
+ return false;
+}
+
+static bool add_field_to_drop_list(THD *thd, Alter_info *alter_info,
+ Field *field)
+{
+ DBUG_ASSERT(field);
+ DBUG_ASSERT(field->field_name.str);
+ alter_info->flags|= Alter_info::ALTER_DROP_COLUMN;
+ Alter_drop *ad= new (thd->mem_root)
+ Alter_drop(Alter_drop::COLUMN, field->field_name.str, false);
+ return !ad || alter_info->drop_list.push_back(ad, thd->mem_root);
+}
+
+static bool is_dropping_primary_key(Alter_info *alter_info)
+{
+ List_iterator_fast<Alter_drop> it(alter_info->drop_list);
+ while (Alter_drop *ad= it++)
+ {
+ if (ad->type == Alter_drop::KEY &&
+ !my_strcasecmp(system_charset_info, ad->name, primary_key_name))
+ return true;
+ }
+ return false;
+}
+
+static bool is_adding_primary_key(Alter_info *alter_info)
+{
+ List_iterator_fast<Key> it(alter_info->key_list);
+ while (Key *key= it++)
+ {
+ if (key->type == Key::PRIMARY)
+ return true;
+ }
+ return false;
+}
+
+bool Vers_parse_info::fix_alter_info(THD *thd, Alter_info *alter_info,
+ HA_CREATE_INFO *create_info,
+ TABLE *table)
+{
+ TABLE_SHARE *share= table->s;
+ const char *table_name= share->table_name.str;
+
+ if (!need_check(alter_info) && !share->versioned)
+ return false;
+
+ if (share->tmp_table && share->tmp_table != INTERNAL_TMP_TABLE
+#ifdef VERS_EXPERIMENTAL
+ && !thd->variables.vers_force
+#endif
+ )
+ {
+ my_error(ER_VERS_TEMPORARY, MYF(0));
+ return true;
+ }
+
+ if (alter_info->flags & Alter_info::ALTER_ADD_SYSTEM_VERSIONING && table->versioned())
+ {
+ my_error(ER_VERS_ALREADY_VERSIONED, MYF(0), table_name);
+ return true;
+ }
+
+ if (alter_info->flags & Alter_info::ALTER_DROP_SYSTEM_VERSIONING)
+ {
+ if (!share->versioned)
+ {
+ my_error(ER_VERS_NOT_VERSIONED, MYF(0), table_name);
+ return true;
+ }
+
+ if (share->vers_start_field()->invisible < INVISIBLE_SYSTEM)
+ {
+ my_error(ER_VERS_SYS_FIELD_EXISTS, MYF(0),
+ share->vers_start_field()->field_name.str);
+ return true;
+ }
+ if (share->vers_end_field()->invisible < INVISIBLE_SYSTEM)
+ {
+ my_error(ER_VERS_SYS_FIELD_EXISTS, MYF(0),
+ share->vers_end_field()->field_name.str);
+ 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;
+
+ if (share->primary_key != MAX_KEY && !is_adding_primary_key(alter_info) &&
+ !is_dropping_primary_key(alter_info))
+ {
+ alter_info->flags|= Alter_info::ALTER_DROP_INDEX;
+ Alter_drop *ad= new (thd->mem_root)
+ Alter_drop(Alter_drop::KEY, primary_key_name, false);
+ if (!ad || alter_info->drop_list.push_back(ad, thd->mem_root))
+ return true;
+
+ alter_info->flags|= Alter_info::ALTER_ADD_INDEX;
+ LEX_CSTRING key_name= {NULL, 0};
+ DDL_options_st options;
+ options.init();
+ Key *pk= new (thd->mem_root)
+ Key(Key::PRIMARY, &key_name, HA_KEY_ALG_UNDEF, false, options);
+ if (!pk)
+ return true;
+
+ st_key &key= table->key_info[share->primary_key];
+ for (st_key_part_info *it= key.key_part,
+ *end= it + key.user_defined_key_parts;
+ it != end; ++it)
+ {
+ if (it->field->vers_sys_field())
+ continue;
+
+ Key_part_spec *key_part_spec= new (thd->mem_root)
+ Key_part_spec(&it->field->field_name, it->length);
+ if (!key_part_spec ||
+ pk->columns.push_back(key_part_spec, thd->mem_root))
+ return true;
+ }
+
+ alter_info->key_list.push_back(pk);
+ }
+
+ return false;
+ }
+
+ {
+ List_iterator_fast<Create_field> it(alter_info->create_list);
+ while (Create_field *f= it++)
+ {
+ if (f->change.length && f->flags & VERS_SYSTEM_FIELD)
+ {
+ my_error(ER_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN, MYF(0));
+ return true;
+ }
+ }
+ }
+
+ if ((versioned_fields || unversioned_fields) && !share->versioned)
+ {
+ my_error(ER_VERS_NOT_VERSIONED, MYF(0), table_name);
+ 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());
+ LString start(share->vers_start_field()->field_name);
+ LString end(share->vers_end_field()->field_name);
+ DBUG_ASSERT(start.ptr() && end.ptr());
+
+ as_row= start_end_t(start, end);
+ system_time= as_row;
+
+ if (alter_info->create_list.elements)
+ {
+ List_iterator_fast<Create_field> it(alter_info->create_list);
+ while (Create_field *f= it++)
+ {
+ if (f->versioning == Column_definition::WITHOUT_VERSIONING)
+ f->flags|= VERS_UPDATE_UNVERSIONED_FLAG;
+
+ if (f->change.str && (start == f->change || end == f->change))
+ {
+ my_error(ER_VERS_ALTER_SYSTEM_FIELD, MYF(0), f->change.str);
+ return true;
+ }
+ }
+ }
+
+ if (alter_info->drop_list.elements)
+ {
+ bool done_start= false;
+ bool done_end= false;
+ List_iterator<Alter_drop> it(alter_info->drop_list);
+ while (Alter_drop *d= it++)
+ {
+ const char *name= d->name;
+ Field *f= NULL;
+ if (!done_start && is_start(name))
+ {
+ f= share->vers_start_field();
+ done_start= true;
+ }
+ else if (!done_end && is_end(name))
+ {
+ f= share->vers_end_field();
+ done_end= true;
+ }
+ else
+ continue;
+ if (f->invisible > INVISIBLE_USER)
+ {
+ my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0), d->type_name(), name);
+ return true;
+ }
+
+ bool integer= table->vers_start_field()->type() == MYSQL_TYPE_LONGLONG;
+ Create_field *field= vers_init_sys_field(thd, name, f->flags & VERS_SYSTEM_FIELD, integer);
+ if (!field)
+ return true;
+
+ field->change= f->field_name;
+
+ alter_info->flags|= Alter_info::ALTER_CHANGE_COLUMN;
+ alter_info->create_list.push_back(field);
+
+ it.remove();
+
+ if (done_start && done_end)
+ break;
+ }
+ }
+
+ return false;
+ }
+
+ if (fix_implicit(thd, alter_info))
+ return true;
+
+ if (alter_info->flags & Alter_info::ALTER_ADD_SYSTEM_VERSIONING)
+ {
+ if (check_with_conditions(table_name))
+ return true;
+ bool native= create_info->vers_native(thd);
+ if (check_sys_fields(table_name, alter_info, native))
+ return true;
+ }
+
+ return false;
+}
+
+bool
+Vers_parse_info::fix_create_like(Alter_info &alter_info, HA_CREATE_INFO &create_info,
+ TABLE_LIST &src_table, TABLE_LIST &table)
+{
+ List_iterator<Create_field> it(alter_info.create_list);
+ Create_field *f, *f_start=NULL, *f_end= NULL;
+
+ DBUG_ASSERT(alter_info.create_list.elements > 2);
+
+ if (create_info.tmp_table())
+ {
+ int remove= 2;
+ while (remove && (f= it++))
+ {
+ if (f->flags & (VERS_SYS_START_FLAG|VERS_SYS_END_FLAG))
+ {
+ it.remove();
+ remove--;
+ }
+ }
+ DBUG_ASSERT(remove == 0);
+ push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_UNKNOWN_ERROR,
+ "System versioning is stripped from temporary `%s.%s`",
+ table.db, table.table_name);
+ return false;
+ }
+
+ 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_MISSING, MYF(0), src_table.table_name,
+ f_start ? "AS ROW END" : "AS ROW START");
+ return true;
+ }
+
+ 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;
+}
+
+bool Vers_parse_info::need_check(const Alter_info *alter_info) const
+{
+ return versioned_fields || unversioned_fields ||
+ alter_info->flags & Alter_info::ALTER_ADD_SYSTEM_VERSIONING ||
+ alter_info->flags & Alter_info::ALTER_DROP_SYSTEM_VERSIONING || *this;
+}
+
+bool Vers_parse_info::check_with_conditions(const char *table_name) const
+{
+ if (!as_row.start || !as_row.end)
+ {
+ my_error(ER_MISSING, MYF(0), table_name,
+ as_row.start ? "AS ROW END" : "AS ROW START");
+ return true;
+ }
+
+ if (!system_time.start || !system_time.end)
+ {
+ my_error(ER_MISSING, MYF(0), table_name, "PERIOD FOR SYSTEM_TIME");
+ return true;
+ }
+
+ if (as_row.start != system_time.start || as_row.end != system_time.end)
+ {
+ my_error(ER_VERS_PERIOD_COLUMNS, MYF(0), as_row.start.str, as_row.end.str);
+ return true;
+ }
+
+ return false;
+}
+
+bool Vers_parse_info::check_sys_fields(const char *table_name,
+ Alter_info *alter_info,
+ bool native) const
+{
+ List_iterator<Create_field> it(alter_info->create_list);
+ vers_sys_type_t found= VERS_UNDEFINED;
+ uint found_flag= 0;
+ while (Create_field *f= it++)
+ {
+ vers_sys_type_t check_unit= VERS_UNDEFINED;
+ uint sys_flag= f->flags & VERS_SYSTEM_FIELD;
+
+ if (!sys_flag)
+ continue;
+
+ if (sys_flag & found_flag)
+ {
+ my_error(ER_VERS_DUPLICATE_ROW_START_END, MYF(0),
+ found_flag & VERS_SYS_START_FLAG ? "START" : "END", f->field_name.str);
+ return true;
+ }
+
+ sys_flag|= found_flag;
+
+ if ((f->type_handler() == &type_handler_datetime2 ||
+ f->type_handler() == &type_handler_timestamp2) &&
+ f->length == MAX_DATETIME_FULL_WIDTH)
+ {
+ check_unit= VERS_TIMESTAMP;
+ }
+ else if (native
+ && f->type_handler() == &type_handler_longlong
+ && (f->flags & UNSIGNED_FLAG)
+ && f->length == (MY_INT64_NUM_DECIMAL_DIGITS - 1))
+ {
+ check_unit= VERS_TRX_ID;
+ }
+ else
+ {
+ if (!found)
+ found= VERS_TIMESTAMP;
+ goto error;
+ }
+
+ if (check_unit)
+ {
+ if (found)
+ {
+ if (found == check_unit)
+ {
+ if (found == VERS_TRX_ID && !use_transaction_registry)
+ {
+ my_error(ER_VERS_TRT_IS_DISABLED, MYF(0));
+ return true;
+ }
+ return false;
+ }
+ error:
+ my_error(ER_VERS_FIELD_WRONG_TYPE, MYF(0), f->field_name.str,
+ found == VERS_TIMESTAMP ?
+ "TIMESTAMP(6)" :
+ "BIGINT(20) UNSIGNED",
+ table_name);
+ return true;
+ }
+ found= check_unit;
+ }
+ }
+
+ my_error(ER_MISSING, MYF(0), table_name, found_flag & VERS_SYS_START_FLAG ?
+ "ROW END" : found_flag ? "ROW START" : "ROW START/END");
+ return true;
+}
diff --git a/sql/handler.h b/sql/handler.h
index da18a8954de..1a4e83c093d 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -34,6 +34,7 @@
#include "structs.h" /* SHOW_COMP_OPTION */
#include "sql_array.h" /* Dynamic_array<> */
#include "mdl.h"
+#include "vers_string.h"
#include "sql_analyze_stmt.h" // for Exec_time_tracker
@@ -412,6 +413,8 @@ 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_VTMD 64U
#define HA_MAX_REC_LENGTH 65535
@@ -1409,6 +1412,16 @@ struct handlerton
*/
int (*discover_table_structure)(handlerton *hton, THD* thd,
TABLE_SHARE *share, HA_CREATE_INFO *info);
+
+ /*
+ System Versioning
+ */
+ /** Determine if system-versioned data was modified by the transaction.
+ @param[in,out] thd current session
+ @param[out] trx_id transaction start ID
+ @return transaction commit ID
+ @retval 0 if no system-versioned data was affected by the transaction */
+ ulonglong (*prepare_commit_versioned)(THD *thd, ulonglong *trx_id);
};
@@ -1456,6 +1469,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_NATIVE_SYS_VERSIONING (1 << 11) //Engine supports System Versioning
// MySQL compatibility. Unused.
#define HTON_SUPPORTS_FOREIGN_KEYS (1 << 0) //Foreign key constraint supported.
@@ -1705,6 +1719,77 @@ struct Schema_specification_st
}
};
+class Create_field;
+
+struct Vers_parse_info
+{
+ Vers_parse_info() :
+ versioned_fields(false),
+ unversioned_fields(false)
+ {}
+
+ struct start_end_t
+ {
+ start_end_t()
+ {}
+ start_end_t(LEX_CSTRING _start, LEX_CSTRING _end) :
+ start(_start),
+ end(_end) {}
+ LString_i start;
+ LString_i end;
+ };
+
+ start_end_t system_time;
+ start_end_t as_row;
+
+ void set_system_time(LString start, LString end)
+ {
+ system_time.start= start;
+ system_time.end= end;
+ }
+
+protected:
+ friend struct Table_scope_and_contents_source_st;
+ void set_start(const LEX_CSTRING field_name)
+ {
+ as_row.start= field_name;
+ system_time.start= field_name;
+ }
+ void set_end(const LEX_CSTRING field_name)
+ {
+ as_row.end= field_name;
+ system_time.end= field_name;
+ }
+ bool is_start(const char *name) const;
+ bool is_end(const char *name) const;
+ bool is_start(const Create_field &f) const;
+ bool is_end(const Create_field &f) const;
+ bool fix_implicit(THD *thd, Alter_info *alter_info, int *added= NULL);
+ operator bool() const
+ {
+ return as_row.start || as_row.end || system_time.start || system_time.end;
+ }
+ bool need_check(const Alter_info *alter_info) const;
+ bool check_with_conditions(const char *table_name) const;
+ bool check_sys_fields(const char *table_name, Alter_info *alter_info,
+ bool native) const;
+
+public:
+ static const LString default_start;
+ static const LString default_end;
+
+ bool fix_alter_info(THD *thd, Alter_info *alter_info,
+ HA_CREATE_INFO *create_info, TABLE *table);
+ bool fix_create_like(Alter_info &alter_info, HA_CREATE_INFO &create_info,
+ TABLE_LIST &src_table, TABLE_LIST &table);
+
+ /**
+ At least one field was specified 'WITH/WITHOUT SYSTEM VERSIONING'.
+ Useful for error handling.
+ */
+ bool versioned_fields : 1;
+ bool unversioned_fields : 1;
+};
/**
A helper struct for table DDL statements, e.g.:
@@ -1780,6 +1865,16 @@ struct Table_scope_and_contents_source_st
bool table_was_deleted;
sequence_definition *seq_create_info;
+ Vers_parse_info vers_info;
+
+ bool vers_fix_system_fields(THD *thd, Alter_info *alter_info,
+ const TABLE_LIST &create_table,
+ const TABLE_LIST *select_table= NULL,
+ List<Item> *items= NULL,
+ bool *versioned_write= NULL);
+
+ bool vers_native(THD *thd) const;
+
void init()
{
bzero(this, sizeof(*this));
@@ -1790,6 +1885,16 @@ struct Table_scope_and_contents_source_st
db_type= tmp_table() ? ha_default_tmp_handlerton(thd)
: ha_default_handlerton(thd);
}
+
+ bool versioned() const
+ {
+ return options & HA_VERSIONED_TABLE;
+ }
+
+ bool vtmd() const
+ {
+ return options & HA_VTMD;
+ }
};
@@ -2063,6 +2168,14 @@ public:
static const HA_ALTER_FLAGS ALTER_DROP_CHECK_CONSTRAINT= 1ULL << 40;
+ static const HA_ALTER_FLAGS ALTER_DROP_HISTORICAL = 1ULL << 41;
+
+ static const HA_ALTER_FLAGS ALTER_COLUMN_UNVERSIONED = 1ULL << 42;
+
+ static const HA_ALTER_FLAGS ALTER_ADD_SYSTEM_VERSIONING= 1ULL << 43;
+
+ static const HA_ALTER_FLAGS ALTER_DROP_SYSTEM_VERSIONING= 1ULL << 44;
+
/**
Create options (like MAX_ROWS) for the new version of table.
@@ -3311,6 +3424,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()
{
@@ -3392,7 +3517,7 @@ public:
virtual int pre_ft_end() { return 0; }
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;
@@ -4166,8 +4291,8 @@ protected:
virtual int delete_table(const char *name);
public:
- inline bool check_table_binlog_row_based(bool binlog_row);
-private:
+ bool check_table_binlog_row_based(bool binlog_row);
+
/* Cache result to avoid extra calls */
inline void mark_trx_read_write()
{
@@ -4177,6 +4302,8 @@ private:
mark_trx_read_write_internal();
}
}
+
+private:
void mark_trx_read_write_internal();
bool check_table_binlog_row_based_internal(bool binlog_row);
@@ -4338,6 +4465,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:
@@ -4461,6 +4593,15 @@ public:
*/
virtual int find_unique_row(uchar *record, uint unique_ref)
{ return -1; /*unsupported */}
+
+ 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; }
+ 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/item.cc b/sql/item.cc
index ddc0813933a..d916e4328d7 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -6062,6 +6062,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,
@@ -6916,7 +6917,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.str, value, max_length);
+ return new (thd->mem_root) Item_int(thd, name.str, value, max_length, unsigned_flag);
}
@@ -7246,6 +7247,26 @@ bool Item_temporal_literal::eq(const Item *item, bool binary_cmp) const
&((Item_temporal_literal *) item)->cached_time);
}
+bool Item_temporal_literal::operator<(const MYSQL_TIME &ltime) const
+{
+ if (my_time_compare(&cached_time, &ltime) < 0)
+ return true;
+ return false;
+}
+
+bool Item_temporal_literal::operator>(const MYSQL_TIME &ltime) const
+{
+ if (my_time_compare(&cached_time, &ltime) > 0)
+ return true;
+ return false;
+}
+
+bool Item_temporal_literal::operator==(const MYSQL_TIME &ltime) const
+{
+ if (my_time_compare(&cached_time, &ltime) == 0)
+ return true;
+ return false;
+}
void Item_date_literal::print(String *str, enum_query_type query_type)
{
@@ -10605,6 +10626,30 @@ Item_field::excl_dep_on_grouping_fields(st_select_lex *sel)
return find_matching_grouping_field(this, sel) != NULL;
}
+Item *Item_field::vers_transformer(THD *thd, uchar *)
+{
+ if (!field)
+ return this;
+
+ if (field->vers_update_unversioned() && context &&
+ field->table->pos_in_table_list &&
+ field->table->pos_in_table_list->vers_conditions)
+ {
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_NON_VERSIONED_FIELD_IN_HISTORICAL_QUERY,
+ ER_THD(thd, ER_NON_VERSIONED_FIELD_IN_HISTORICAL_QUERY),
+ field_name.str);
+ }
+
+ 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 fb7edfd3d1a..d178d9f97d6 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -301,6 +301,28 @@ public:
}
};
+class Name_resolution_context_backup
+{
+ Name_resolution_context &ctx;
+ TABLE_LIST &table_list;
+ table_map save_map;
+ Name_resolution_context_state ctx_state;
+
+public:
+ Name_resolution_context_backup(Name_resolution_context &_ctx, TABLE_LIST &_table_list)
+ : ctx(_ctx), table_list(_table_list), save_map(_table_list.map)
+ {
+ ctx_state.save_state(&ctx, &table_list);
+ ctx.table_list= &table_list;
+ ctx.first_name_resolution_table= &table_list;
+ }
+ ~Name_resolution_context_backup()
+ {
+ ctx_state.restore_state(&ctx, &table_list);
+ table_list.map= save_map;
+ }
+};
+
/*
This enum is used to report information about monotonicity of function
@@ -541,7 +563,6 @@ public:
String_copier_for_item(THD *thd): m_thd(thd) { }
};
-
class Item: public Value_source,
public Type_all_attributes
{
@@ -774,6 +795,10 @@ public:
return type_handler()->field_type();
}
virtual const Type_handler *type_handler() const= 0;
+ virtual uint field_flags() const
+ {
+ return 0;
+ }
const Type_handler *type_handler_for_comparison() const
{
return type_handler()->type_handler_for_comparison();
@@ -1742,6 +1767,10 @@ public:
virtual Item_field *field_for_view_update() { return 0; }
+ virtual Item *vers_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; }
@@ -2803,6 +2832,10 @@ public:
return field->type_handler();
}
TYPELIB *get_typelib() const { return field->get_typelib(); }
+ uint32 field_flags() const
+ {
+ return field->flags;
+ }
enum_monotonicity_info get_monotonicity_info() const
{
return MONOTONIC_STRICT_INCREASING;
@@ -2899,6 +2932,8 @@ 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_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);
@@ -3463,6 +3498,14 @@ public:
name.str= str_arg; name.length= safe_strlen(name.str);
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.str= str_arg; name.length= safe_strlen(name.str);
+ fixed= 1;
+ unsigned_flag= flag;
+ }
Item_int(THD *thd, const char *str_arg, uint length=64);
enum Type type() const { return INT_ITEM; }
const Type_handler *type_handler() const
@@ -3913,10 +3956,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; }
const Type_handler *type_handler() const
{
return Type_handler::get_handler_by_field_type(date_time_field_type);
@@ -4157,6 +4200,13 @@ 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 operator>(const MYSQL_TIME &ltime) const;
+ bool operator<(const MYSQL_TIME &ltime) const;
+ bool operator==(const MYSQL_TIME &ltime) const;
};
@@ -4216,7 +4266,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);
@@ -4716,6 +4766,12 @@ public:
return 0;
return cleanup_processor(arg);
}
+ virtual bool vers_trx_id() const
+ {
+ DBUG_ASSERT(ref);
+ DBUG_ASSERT(*ref);
+ return (*ref)->vers_trx_id();
+ }
};
@@ -5232,6 +5288,7 @@ public:
#include "item_xmlfunc.h"
#include "item_jsonfunc.h"
#include "item_create.h"
+#include "item_vers.h"
#endif
/**
@@ -6172,37 +6229,59 @@ class Item_type_holder: public Item,
{
protected:
TYPELIB *enum_set_typelib;
+private:
+ void init_flags(Item *item)
+ {
+ if (item->real_type() == Item::FIELD_ITEM)
+ {
+ Item_field *item_field= (Item_field *)item->real_item();
+ m_flags|= (item_field->field->flags &
+ (VERS_SYS_START_FLAG | VERS_SYS_END_FLAG));
+ // TODO: additional field flag?
+ m_vers_trx_id= item_field->field->vers_trx_id();
+ }
+ }
public:
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),
+ m_flags(0),
+ m_vers_trx_id(false)
{
DBUG_ASSERT(item->fixed);
maybe_null= item->maybe_null;
+ init_flags(item);
}
Item_type_holder(THD *thd,
- const LEX_CSTRING *name_arg,
+ Item *item,
const Type_handler *handler,
const Type_all_attributes *attr,
bool maybe_null_arg)
:Item(thd),
Type_handler_hybrid_field_type(handler),
Type_geometry_attributes(handler, attr),
- enum_set_typelib(attr->get_typelib())
+ enum_set_typelib(attr->get_typelib()),
+ m_flags(0),
+ m_vers_trx_id(false)
{
- name= *name_arg;
+ name= item->name;
Type_std_attributes::set(*attr);
maybe_null= maybe_null_arg;
+ init_flags(item);
}
const Type_handler *type_handler() const
{
- const Type_handler *handler= Type_handler_hybrid_field_type::type_handler();
+ const Type_handler *handler= m_vers_trx_id ?
+ &type_handler_vers_trx_id :
+ Type_handler_hybrid_field_type::type_handler();
return handler->type_handler_for_item_field();
}
const Type_handler *real_type_handler() const
{
+ if (m_vers_trx_id)
+ return &type_handler_vers_trx_id;
return Type_handler_hybrid_field_type::type_handler();
}
@@ -6227,6 +6306,19 @@ public:
Type_geometry_attributes::set_geometry_type(type);
}
Item* get_copy(THD *thd) { return 0; }
+
+private:
+ uint m_flags;
+ bool m_vers_trx_id;
+public:
+ uint32 field_flags() const
+ {
+ return m_flags;
+ }
+ virtual bool vers_trx_id() const
+ {
+ return m_vers_trx_id;
+ }
};
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 00ee42ac487..780c60e4eb3 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]);
}
@@ -5303,7 +5306,6 @@ bool fix_escape_item(THD *thd, Item *escape_item, String *tmp_str,
return FALSE;
}
-
bool Item_func_like::fix_fields(THD *thd, Item **ref)
{
DBUG_ASSERT(fixed == 0);
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 5d6d9742c7a..d73a5327d25 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -43,38 +43,6 @@
*/
/**
- Adapter for native functions with a variable number of arguments.
- The main use of this class is to discard the following calls:
- <code>foo(expr1 AS name1, expr2 AS name2, ...)</code>
- 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_CSTRING *name,
- List<Item> *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_CSTRING *name,
- List<Item> *item_list) = 0;
-
-protected:
- /** Constructor. */
- Create_native_func() {}
- /** Destructor. */
- virtual ~Create_native_func() {}
-};
-
-
-/**
Adapter for functions that takes exactly zero arguments.
*/
@@ -6827,12 +6795,6 @@ Create_func_year_week::create_native(THD *thd, LEX_CSTRING *name,
}
-struct Native_func_registry
-{
- LEX_CSTRING name;
- Create_func *builder;
-};
-
#define BUILDER(F) & F::s_singleton
#ifdef HAVE_SPATIAL
@@ -7218,8 +7180,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,
@@ -7232,7 +7192,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 128a19a1c15..e0beca37082 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;
/**
@@ -67,6 +69,38 @@ protected:
/**
+ Adapter for native functions with a variable number of arguments.
+ The main use of this class is to discard the following calls:
+ <code>foo(expr1 AS name1, expr2 AS name2, ...)</code>
+ 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_CSTRING *name,
+ List<Item> *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_CSTRING *name,
+ List<Item> *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
syntax, as in <code>db.func(expr, expr, ...)</code>.
@@ -172,7 +206,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<DYNCALL_CREATE_DEF> &list);
diff --git a/sql/item_func.h b/sql/item_func.h
index 86924384d74..c226d82c7b8 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
{
@@ -985,6 +988,30 @@ public:
};
+class Item_longlong_typecast :public Item_int_func
+{
+public:
+ Item_longlong_typecast(THD *thd, Item *a): Item_int_func(thd, a)
+ {
+ }
+ const char *func_name() const { return "cast_as_longlong"; }
+ const char *cast_type() const { return "longlong"; }
+ const Type_handler *type_handler() const { return &type_handler_longlong; }
+ longlong val_int()
+ {
+ return args[0]->val_int();
+ }
+ void fix_length_and_dec_generic() {}
+ void fix_length_and_dec()
+ {
+ args[0]->type_handler()->Item_longlong_typecast_fix_length_and_dec(this);
+ }
+ bool need_parentheses_in_default() { return true; }
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_longlong_typecast>(thd, this); }
+};
+
+
class Item_func_additive_op :public Item_num_op
{
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index fd170a707c9..ed4b2839170 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -2652,6 +2652,27 @@ bool Item_datetime_typecast::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
}
+void Item_datetime_from_unixtime_typecast::fix_length_and_dec()
+{
+ Item_datetime_typecast::fix_length_and_dec();
+
+ switch (args[0]->result_type())
+ {
+ case INT_RESULT:
+ case REAL_RESULT:
+ case DECIMAL_RESULT:
+ {
+ Query_arena_stmt on_stmt_arena(thd);
+ Item_func_from_unixtime *a= new (thd->mem_root) Item_func_from_unixtime(thd, args[0]);
+ a->fix_length_and_dec();
+ args[0]= a;
+ break;
+ }
+ default:;
+ }
+}
+
+
/**
MAKEDATE(a,b) is a date function that creates a date value
from a year and day value.
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index adc7b2535a9..878179105be 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -1184,6 +1184,20 @@ public:
};
+class Item_datetime_from_unixtime_typecast :public Item_datetime_typecast
+{
+ THD *thd;
+public:
+ Item_datetime_from_unixtime_typecast(THD *_thd, Item *a, uint dec_arg):
+ Item_datetime_typecast(_thd, a, dec_arg), thd(_thd) {}
+ const char *func_name() const { return "cast_as_datetime_from_unixtime"; }
+ const char *cast_type() const { return "datetime"; }
+ void fix_length_and_dec();
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_datetime_from_unixtime_typecast>(thd, this); }
+};
+
+
class Item_func_makedate :public Item_datefunc
{
bool check_arguments() const
diff --git a/sql/item_vers.cc b/sql/item_vers.cc
new file mode 100644
index 00000000000..8aa1321e396
--- /dev/null
+++ b/sql/item_vers.cc
@@ -0,0 +1,182 @@
+/* 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 "mariadb.h"
+#include "sql_priv.h"
+
+#include "sql_class.h"
+#include "tztime.h"
+#include "item.h"
+
+Item_func_vtq_ts::Item_func_vtq_ts(THD *thd, Item* a, TR_table::field_id_t _vtq_field) :
+ Item_datetimefunc(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)
+{
+ 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)
+ {
+ null_value= false;
+ thd->variables.time_zone->gmt_sec_to_TIME(res, TIMESTAMP_MAX_VALUE);
+ res->second_part= TIME_MAX_SECOND_PART;
+ return false;
+ }
+
+ TR_table trt(thd);
+
+ null_value= !trt.query(trx_id);
+ if (null_value)
+ {
+ my_error(ER_VERS_NO_TRX_ID, MYF(0), trx_id);
+ return true;
+ }
+
+ return trt[vtq_field]->get_date(res, fuzzy_date);
+}
+
+
+Item_func_vtq_id::Item_func_vtq_id(THD *thd, Item* a, TR_table::field_id_t _vtq_field,
+ bool _backwards) :
+ Item_longlong_func(thd, a),
+ vtq_field(_vtq_field),
+ backwards(_backwards)
+{
+ 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, TR_table::field_id_t _vtq_field) :
+ Item_longlong_func(thd, a, b),
+ vtq_field(_vtq_field),
+ backwards(false)
+{
+ 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)
+{
+ THD *thd= current_thd;
+ DBUG_ASSERT(thd);
+
+ if (trx_id == ULONGLONG_MAX)
+ {
+ null_value= true;
+ return 0;
+ }
+
+ TR_table trt(thd);
+ null_value= !trt.query(trx_id);
+ if (null_value)
+ return 0;
+
+ return trt[vtq_field]->val_int();
+}
+
+longlong
+Item_func_vtq_id::get_by_commit_ts(MYSQL_TIME &commit_ts, bool backwards)
+{
+ THD *thd= current_thd;
+ DBUG_ASSERT(thd);
+
+ TR_table trt(thd);
+ null_value= !trt.query(commit_ts, backwards);
+ if (null_value)
+ return 0;
+
+ return trt[vtq_field]->val_int();
+}
+
+longlong
+Item_func_vtq_id::val_int()
+{
+ if (args[0]->is_null())
+ {
+ if (arg_count < 2 || vtq_field == TR_table::FLD_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) :
+ Item_bool_func(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);
+
+ DBUG_ASSERT(arg_count > 1);
+ ulonglong trx_id1= args[0]->val_uint();
+ ulonglong trx_id0= args[1]->val_uint();
+ bool result= accept_eq;
+
+ TR_table trt(thd);
+ null_value= trt.query_sees(result, trx_id1, trx_id0);
+ return result;
+}
diff --git a/sql/item_vers.h b/sql/item_vers.h
new file mode 100644
index 00000000000..39ed4ecda1f
--- /dev/null
+++ b/sql/item_vers.h
@@ -0,0 +1,114 @@
+#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 */
+
+#ifdef USE_PRAGMA_INTERFACE
+#pragma interface /* gcc class implementation */
+#endif
+
+class Item_func_vtq_ts: public Item_datetimefunc
+{
+ TR_table::field_id_t vtq_field;
+public:
+ Item_func_vtq_ts(THD *thd, Item* a, TR_table::field_id_t _vtq_field);
+ const char *func_name() const
+ {
+ if (vtq_field == TR_table::FLD_BEGIN_TS)
+ {
+ return "vtq_begin_ts";
+ }
+ return "vtq_commit_ts";
+ }
+ bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_vtq_ts>(thd, this); }
+ void fix_length_and_dec() { fix_attributes_datetime(decimals); }
+};
+
+class Item_func_vtq_id : public Item_longlong_func
+{
+ TR_table::field_id_t vtq_field;
+ 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, TR_table::field_id_t _vtq_field, bool _backwards= false);
+ Item_func_vtq_id(THD *thd, Item* a, Item* b, TR_table::field_id_t _vtq_field);
+
+ const char *func_name() const
+ {
+ switch (vtq_field)
+ {
+ case TR_table::FLD_TRX_ID:
+ return "vtq_trx_id";
+ case TR_table::FLD_COMMIT_ID:
+ return "vtq_commit_id";
+ case TR_table::FLD_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)
+ { return get_item_copy<Item_func_vtq_id>(thd, this); }
+};
+
+class Item_func_vtq_trx_sees : public Item_bool_func
+{
+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)
+ { return get_item_copy<Item_func_vtq_trx_sees>(thd, 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 */
diff --git a/sql/lex.h b/sql/lex.h
index da985ad26a6..41a81c737f7 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -273,7 +273,7 @@ static SYMBOL symbols[] = {
{ "HAVING", SYM(HAVING)},
{ "HELP", SYM(HELP_SYM)},
{ "HIGH_PRIORITY", SYM(HIGH_PRIORITY)},
- { "INVISIBLE", SYM(INVISIBLE_SYM)},
+ { "HISTORY", SYM(HISTORY_SYM)},
{ "HOST", SYM(HOST_SYM)},
{ "HOSTS", SYM(HOSTS_SYM)},
{ "HOUR", SYM(HOUR_SYM)},
@@ -309,6 +309,7 @@ static SYMBOL symbols[] = {
{ "INT8", SYM(BIGINT)},
{ "INTEGER", SYM(INT_SYM)},
{ "INTERVAL", SYM(INTERVAL_SYM)},
+ { "INVISIBLE", SYM(INVISIBLE_SYM)},
{ "INTO", SYM(INTO)},
{ "IO", SYM(IO_SYM)},
{ "IO_THREAD", SYM(RELAY_THREAD)},
@@ -460,6 +461,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)},
@@ -629,6 +631,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)},
@@ -694,6 +698,7 @@ static SYMBOL symbols[] = {
{ "VIA", SYM(VIA_SYM)},
{ "VIEW", SYM(VIEW_SYM)},
{ "VIRTUAL", SYM(VIRTUAL_SYM)},
+ { "VERSIONING", SYM(VERSIONING_SYM)},
{ "WAIT", SYM(WAIT_SYM)},
{ "WARNINGS", SYM(WARNINGS)},
{ "WEEK", SYM(WEEK_SYM)},
@@ -704,6 +709,7 @@ static SYMBOL symbols[] = {
{ "WINDOW", SYM(WINDOW_SYM)},
{ "WITH", SYM(WITH)},
{ "WITHIN", SYM(WITHIN)},
+ { "WITHOUT", SYM(WITHOUT)},
{ "WORK", SYM(WORK_SYM)},
{ "WRAPPER", SYM(WRAPPER_SYM)},
{ "WRITE", SYM(WRITE_SYM)},
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 0a46bf44d7b..ca659085228 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -43,6 +43,7 @@
#include <strfunc.h>
#include "compat56.h"
#include "wsrep_mysqld.h"
+#include "sql_insert.h"
#else
#include "mysqld_error.h"
#endif /* MYSQL_CLIENT */
@@ -13020,6 +13021,17 @@ 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(VERS_TIMESTAMP))
+ {
+ ulong sec_part;
+ 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(&sec_part) == 0 && sec_part == 0)
+ table->vers_update_fields();
+ }
+
/*
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
@@ -13346,7 +13358,10 @@ static bool record_compare(TABLE *table)
/* Compare fields */
for (Field **ptr=table->field ; *ptr ; ptr++)
{
-
+ if (table->versioned() && (*ptr)->vers_sys_field())
+ {
+ continue;
+ }
/**
We only compare field contents that are not null.
NULL fields (i.e., their null bits) were compared
@@ -13541,6 +13556,27 @@ 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 *row_end= table->vers_end_field();
+ DBUG_ASSERT(table->read_set);
+ bitmap_set_bit(table->read_set, row_end->field_index);
+ // check whether master table is unversioned
+ if (row_end->val_int() == 0)
+ {
+ // row_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, row_end->field_index);
+ // Plain source table may have a PRIMARY KEY. And row_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;
+ }
+ }
+
DBUG_PRINT("info",("looking for the following record"));
DBUG_DUMP("record[0]", table->record[0], table->s->reclength);
@@ -13922,7 +13958,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(VERS_TIMESTAMP))
+ {
+ 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 &&
@@ -14185,9 +14233,17 @@ 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(VERS_TIMESTAMP))
+ m_table->vers_update_fields();
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(VERS_TIMESTAMP))
+ {
+ 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 1feaee86ec7..700301a7f34 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -4608,6 +4608,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 */
@@ -4758,6 +4760,7 @@ public:
__attribute__((unused)),
const uchar *after_record)
{
+ DBUG_ASSERT(!table->versioned(VERS_TRX_ID));
return thd->binlog_write_row(table, is_transactional, after_record);
}
#endif
@@ -4839,6 +4842,7 @@ public:
const uchar *before_record,
const uchar *after_record)
{
+ DBUG_ASSERT(!table->versioned(VERS_TRX_ID));
return thd->binlog_update_row(table, is_transactional,
before_record, after_record);
}
@@ -4928,6 +4932,7 @@ public:
const uchar *after_record
__attribute__((unused)))
{
+ DBUG_ASSERT(!table->versioned(VERS_TRX_ID));
return thd->binlog_delete_row(table, is_transactional,
before_record);
}
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 0ec99d6eb96..c0d55306871 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -100,6 +100,8 @@
#include "semisync_master.h"
#include "semisync_slave.h"
+#include "transaction.h"
+
#ifdef HAVE_SYS_PRCTL_H
#include <sys/prctl.h>
#endif
@@ -534,6 +536,8 @@ ulonglong slave_skipped_errors;
ulong feature_files_opened_with_delayed_keys= 0, feature_check_constraint= 0;
ulonglong denied_connections;
my_decimal decimal_zero;
+my_bool opt_transaction_registry= 1;
+my_bool use_transaction_registry= 1;
/*
Maximum length of parameter value which can be set through
@@ -949,6 +953,9 @@ PSI_mutex_key key_LOCK_prepare_ordered, key_LOCK_commit_ordered,
PSI_mutex_key key_TABLE_SHARE_LOCK_share;
PSI_mutex_key key_LOCK_ack_receiver;
+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
@@ -1011,6 +1018,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},
@@ -1033,8 +1041,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_LOCK_SEQUENCE;
-
+ key_LOCK_SEQUENCE,
+ key_rwlock_LOCK_vers_stats, key_rwlock_LOCK_stat_serial;
static PSI_rwlock_info all_server_rwlocks[]=
{
@@ -1047,7 +1055,9 @@ static PSI_rwlock_info all_server_rwlocks[]=
{ &key_rwlock_LOCK_sys_init_slave, "LOCK_sys_init_slave", PSI_FLAG_GLOBAL},
{ &key_LOCK_SEQUENCE, "LOCK_SEQUENCE", 0},
{ &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
@@ -1136,7 +1146,8 @@ static PSI_cond_info all_server_conds[]=
{ &key_COND_wait_gtid, "COND_wait_gtid", 0},
{ &key_COND_gtid_ignore_duplicates, "COND_gtid_ignore_duplicates", 0},
{ &key_COND_ack_receiver, "Ack_receiver::cond", 0},
- { &key_COND_binlog_send, "COND_binlog_send", 0}
+ { &key_COND_binlog_send, "COND_binlog_send", 0},
+ { &key_TABLE_SHARE_COND_rotation, "TABLE_SHARE::COND_rotation", 0}
};
PSI_thread_key key_thread_bootstrap, key_thread_delayed_insert,
@@ -2966,13 +2977,11 @@ static bool cache_thread(THD *thd)
DBUG_PRINT("info", ("Adding thread to cache"));
cached_thread_count++;
-#ifdef HAVE_PSI_THREAD_INTERFACE
/*
Delete the instrumentation for the job that just completed,
before parking this pthread in the cache (blocked on COND_thread_cache).
*/
- PSI_THREAD_CALL(delete_current_thread)();
-#endif
+ PSI_CALL_delete_current_thread();
#ifndef DBUG_OFF
while (_db_is_pushed_())
@@ -3019,15 +3028,13 @@ static bool cache_thread(THD *thd)
*/
thd->store_globals();
-#ifdef HAVE_PSI_THREAD_INTERFACE
/*
Create new instrumentation for the new THD job,
and attach it to this running pthread.
*/
- PSI_thread *psi= PSI_THREAD_CALL(new_thread)(key_thread_one_connection,
+ PSI_thread *psi= PSI_CALL_new_thread(key_thread_one_connection,
thd, thd->thread_id);
- PSI_THREAD_CALL(set_thread)(psi);
-#endif
+ PSI_CALL_set_thread(psi);
/* reset abort flag for the thread */
thd->mysys_var->abort= 0;
@@ -3558,10 +3565,8 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused)))
if (!abort_loop)
{
abort_loop=1; // mark abort for threads
-#ifdef HAVE_PSI_THREAD_INTERFACE
/* Delete the instrumentation for the signal thread */
- PSI_THREAD_CALL(delete_current_thread)();
-#endif
+ PSI_CALL_delete_current_thread();
#ifdef USE_ONE_SIGNAL_HAND
pthread_t tmp;
if ((error= mysql_thread_create(0, /* Not instrumented */
@@ -5825,8 +5830,8 @@ int mysqld_main(int argc, char **argv)
*/
init_server_psi_keys();
/* Instrument the main thread */
- PSI_thread *psi= PSI_THREAD_CALL(new_thread)(key_thread_main, NULL, 0);
- PSI_THREAD_CALL(set_thread)(psi);
+ PSI_thread *psi= PSI_CALL_new_thread(key_thread_main, NULL, 0);
+ PSI_CALL_set_thread(psi);
/*
Now that some instrumentation is in place,
@@ -6018,6 +6023,36 @@ int mysqld_main(int argc, char **argv)
if (Events::init((THD*) 0, opt_noacl || opt_bootstrap))
unireg_abort(1);
+ if (opt_transaction_registry)
+ {
+ use_transaction_registry= true;
+ if (opt_bootstrap)
+ {
+ use_transaction_registry= false;
+ }
+ else
+ {
+ THD *thd = new THD(0);
+ thd->thread_stack= (char*) &thd;
+ thd->store_globals();
+ {
+ TR_table trt(thd);
+ if (trt.check())
+ {
+ use_transaction_registry= false;
+ }
+ }
+
+ trans_commit_stmt(thd);
+ delete thd;
+ }
+ }
+ else
+ use_transaction_registry= false;
+
+ if (opt_transaction_registry && !use_transaction_registry)
+ sql_print_information("Disabled transaction registry.");
+
if (WSREP_ON)
{
if (opt_bootstrap)
@@ -6145,13 +6180,11 @@ int mysqld_main(int argc, char **argv)
mysql_mutex_unlock(&LOCK_start_thread);
#endif /* __WIN__ */
-#ifdef HAVE_PSI_THREAD_INTERFACE
/*
Disable the main thread instrumentation,
to avoid recording events during the shutdown.
*/
- PSI_THREAD_CALL(delete_current_thread)();
-#endif
+ PSI_CALL_delete_current_thread();
/* Wait until cleanup is done */
mysql_mutex_lock(&LOCK_thread_count);
@@ -9850,7 +9883,12 @@ static int get_options(int *argc_ptr, char ***argv_ptr)
/* Ensure that some variables are not set higher than needed */
if (thread_cache_size > max_connections)
SYSVAR_AUTOSIZE(thread_cache_size, max_connections);
-
+
+#ifdef VERS_EXPERIMENTAL
+ if (opt_bootstrap)
+ global_system_variables.vers_force= 0;
+#endif
+
return 0;
}
diff --git a/sql/mysqld.h b/sql/mysqld.h
index 9a2cde9b145..3175a1a385c 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -179,6 +179,45 @@ 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;
+
+/* System Versioning begin */
+enum vers_system_time_t
+{
+ SYSTEM_TIME_UNSPECIFIED = 0,
+ SYSTEM_TIME_AS_OF,
+ SYSTEM_TIME_FROM_TO,
+ SYSTEM_TIME_BETWEEN,
+ SYSTEM_TIME_BEFORE,
+ SYSTEM_TIME_ALL
+};
+
+struct vers_asof_timestamp_t
+{
+ ulong type;
+ MYSQL_TIME ltime;
+ vers_asof_timestamp_t() :
+ type(SYSTEM_TIME_UNSPECIFIED)
+ {}
+};
+
+#ifdef VERS_EXPERIMENTAL
+enum vers_show_enum
+{
+ VERS_SHOW_OFF= 0,
+ VERS_SHOW_RANGE,
+ VERS_SHOW_ALWAYS
+};
+#endif
+
+enum vers_alter_history_enum
+{
+ VERS_ALTER_HISTORY_ERROR= 0,
+ VERS_ALTER_HISTORY_KEEP,
+ VERS_ALTER_HISTORY_SURVIVE,
+ VERS_ALTER_HISTORY_DROP
+};
+/* 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];
@@ -276,6 +315,8 @@ extern my_bool encrypt_tmp_disk_tables, encrypt_tmp_files;
extern ulong encryption_algorithm;
extern const char *encryption_algorithm_names[];
extern const char *quoted_string;
+extern my_bool opt_transaction_registry;
+extern my_bool use_transaction_registry;
#ifdef HAVE_PSI_INTERFACE
#ifdef HAVE_MMAP
@@ -315,13 +356,16 @@ 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,
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_LOCK_SEQUENCE;
+ key_LOCK_SEQUENCE,
+ 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;
#endif /* HAVE_MMAP */
@@ -350,6 +394,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/opt_range.cc b/sql/opt_range.cc
index 25a125dce1f..369729127dd 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -3455,6 +3455,13 @@ 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))
+ {
+ retval= TRUE;
+ goto end2;
+ }
dbug_tmp_use_all_columns(table, old_sets,
table->read_set, table->write_set);
@@ -3555,6 +3562,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
@@ -3981,7 +3989,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];
@@ -7340,6 +7348,7 @@ SEL_TREE *Item_func_in::get_func_row_mm_tree(RANGE_OPT_PARAM *param,
key_col->bring_value();
key_col_info.comparator= row_cmp_item->get_comparator(i);
+ DBUG_ASSERT(key_col_info.comparator);
key_col_info.comparator->store_value(key_col);
col_comparators++;
diff --git a/sql/opt_range.h b/sql/opt_range.h
index a436b0e684d..bd85a12d4a1 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -1666,6 +1666,38 @@ class SQL_SELECT :public Sql_alloc {
};
+class SQL_SELECT_auto
+{
+ SQL_SELECT *select;
+public:
+ SQL_SELECT_auto(): select(NULL)
+ {}
+ ~SQL_SELECT_auto()
+ {
+ delete select;
+ }
+ SQL_SELECT_auto&
+ operator= (SQL_SELECT *_select)
+ {
+ select= _select;
+ return *this;
+ }
+ operator SQL_SELECT * () const
+ {
+ return select;
+ }
+ SQL_SELECT *
+ operator-> () const
+ {
+ return select;
+ }
+ operator bool () const
+ {
+ return select;
+ }
+};
+
+
class FT_SELECT: public QUICK_RANGE_SELECT
{
public:
diff --git a/sql/partition_element.h b/sql/partition_element.h
index c774994b7f5..535c320c626 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,8 +90,76 @@ typedef struct p_elem_val
struct st_ddl_log_memory_entry;
-class partition_element :public Sql_alloc {
+/* Used for collecting MIN/MAX stats on row_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];
+ uchar max_buf[buf_size];
+ Field_timestampf min_value;
+ Field_timestampf max_value;
+ mysql_rwlock_t lock;
+
public:
+ Vers_min_max_stats(const LEX_CSTRING *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);
+ }
+ ~Vers_min_max_stats()
+ {
+ 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()
+ {
+ mysql_rwlock_rdlock(&lock);
+ ulong sec_part;
+ my_time_t res= min_value.get_timestamp(&sec_part);
+ mysql_rwlock_unlock(&lock);
+ return res;
+ }
+ my_time_t max_time()
+ {
+ mysql_rwlock_rdlock(&lock);
+ ulong sec_part;
+ my_time_t res= max_value.get_timestamp(&sec_part);
+ mysql_rwlock_unlock(&lock);
+ return res;
+ }
+};
+
+enum stat_trx_field
+{
+ STAT_TRX_END= 0
+};
+
+class partition_element :public Sql_alloc
+{
+public:
+ enum elem_type
+ {
+ CONVENTIONAL= 0,
+ CURRENT,
+ HISTORY
+ };
+
List<partition_element> subpartitions;
List<part_elem_value> list_val_list;
ha_rows part_max_rows;
@@ -109,6 +178,21 @@ public:
bool has_null_value;
bool signed_flag; // Range value signed
bool max_value; // MAXVALUE range
+ uint32 id;
+ bool empty;
+
+ // TODO: subclass partition_element by partitioning type to avoid such semantic
+ // mixup
+ elem_type type()
+ {
+ return (elem_type)(signed_flag << 1 | max_value);
+ }
+
+ 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),
@@ -117,9 +201,10 @@ public:
data_file_name(NULL), index_file_name(NULL),
engine_type(NULL), connect_string(null_clex_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),
+ empty(true)
+ {}
partition_element(partition_element *part_elem)
: part_max_rows(part_elem->part_max_rows),
part_min_rows(part_elem->part_min_rows),
@@ -132,10 +217,35 @@ public:
connect_string(null_clex_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),
+ empty(part_elem->empty)
+ {}
+ ~partition_element() {}
+
+ part_column_list_val& get_col_val(uint idx)
{
+ 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];
+ }
+
+ bool find_engine_flag(uint32 flag)
+ {
+ if (ha_check_storage_engine_flag(engine_type, flag))
+ return true;
+
+ List_iterator_fast<partition_element> it(subpartitions);
+ while (partition_element *element= it++)
+ {
+ if (element->find_engine_flag(flag))
+ return true;
+ }
+
+ return false;
}
- ~partition_element() {}
};
#endif /* PARTITION_ELEMENT_INCLUDED */
diff --git a/sql/partition_info.cc b/sql/partition_info.cc
index c47c7fc8de9..8133f15012c 100644
--- a/sql/partition_info.cc
+++ b/sql/partition_info.cc
@@ -21,6 +21,8 @@
#endif
#include "mariadb.h"
+#include <my_global.h>
+#include <tztime.h>
#include "sql_priv.h"
// Required to get server definitions for mysql/plugin.h right
#include "sql_plugin.h"
@@ -30,6 +32,9 @@
#include "sql_parse.h"
#include "sql_acl.h" // *_ACL
#include "sql_base.h" // fill_record
+#include "sql_statistics.h" // vers_stat_end
+#include "vers_utils.h"
+#include "lock.h"
#ifdef WITH_PARTITION_STORAGE_ENGINE
#include "ha_partition.h"
@@ -113,6 +118,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<partition_element> 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);
}
@@ -199,6 +217,48 @@ bool partition_info::set_named_partition_bitmap(const char *part_name,
@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<char> *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<char> 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.
+
+ @param table_list Table list pointing to table to prune.
+
+ @return Operation status
@retval true Failure
@retval false Success
*/
@@ -779,6 +839,501 @@ 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;
+ num_columns= 1;
+ 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 || i.second_part)
+ return true;
+
+ DBUG_ASSERT(vers_info);
+
+ // TODO: INTERVAL conversion to seconds leads to mismatch with calendar intervals (MONTH and YEAR)
+ vers_info->interval= static_cast<my_time_t>(
+ 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)
+ return true;
+
+ return false;
+}
+
+bool partition_info::vers_set_limit(ulonglong limit)
+{
+ if (limit < 1)
+ 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);
+ 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,
+ thd->lex->sql_command == SQLCOM_ALTER_TABLE ?
+ Sql_condition::WARN_LEVEL_NOTE :
+ Sql_condition::WARN_LEVEL_WARN,
+ WARN_VERS_PART_FULL,
+ ER_THD(thd, WARN_VERS_PART_FULL),
+ table->s->db.str, table->s->error_table_name(),
+ vers_info->hist_part->partition_name);
+ return vers_info->hist_part;
+ }
+
+ table->s->hist_part_id++;
+ 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),
+ table->s->db.str, table->s->error_table_name(),
+ old_part_name,
+ vers_info->hist_part->partition_name);
+
+ return vers_info->hist_part;
+}
+
+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::CURRENT)
+ {
+ 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(VERS_TIMESTAMP))
+ {
+ my_error(ER_VERS_ENGINE_UNSUPPORTED, MYF(0), table->s->table_name.str);
+ return true;
+ }
+
+ if (alter_add)
+ {
+ DBUG_ASSERT(partitions.elements > alter_add + 1);
+ Vers_min_max_stats** old_array= table->s->stat_trx;
+ table->s->stat_trx= static_cast<Vers_min_max_stats**>(
+ alloc_root(&table->s->mem_root, sizeof(void *) * (partitions.elements * num_columns + 1)));
+ memcpy(table->s->stat_trx, old_array, sizeof(void *) * (partitions.elements - alter_add) * num_columns);
+ table->s->stat_trx[partitions.elements * num_columns]= NULL;
+ }
+ else
+ {
+ /* Prepare part_field_list */
+ Field *row_end= table->vers_end_field();
+ part_field_list.push_back(row_end->field_name.str, thd->mem_root);
+ DBUG_ASSERT(part_field_list.elements == num_columns);
+ // needed in handle_list_of_fields()
+ row_end->flags|= GET_FIXED_FIELDS_FLAG;
+ }
+
+ List_iterator<partition_element> 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 (alter_add)
+ {
+ /* Non-empty historical partitions are left as is. */
+ if (el->type() == partition_element::HISTORY && !el->empty)
+ {
+ ++id;
+ continue;
+ }
+ /* Newly added element is inserted before AS_OF_NOW. */
+ if (el->id == UINT32_MAX || el->type() == partition_element::CURRENT)
+ {
+ 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::CURRENT)
+ break;
+ 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)
+ {
+ part_column_list_val &col_val= el->get_col_val(i);
+ static_cast<Item_datetime_literal *>(col_val.item_expression)->set_time(&t);
+ col_val.fixed= 0;
+ }
+ ++id;
+ continue;
+ }
+
+ set_expression:
+ thd->variables.time_zone->gmt_sec_to_TIME(&t, ts);
+ if (vers_set_expression(thd, el, t))
+ return true;
+ }
+ return false;
+}
+
+
+class Table_locker
+{
+ THD *thd;
+ TABLE &table;
+ thr_lock_type saved_type;
+ MYSQL_LOCK *saved_lock;
+ enum_locked_tables_mode saved_mode;
+ TABLE_LIST **saved_query_tables_own_last;
+ TABLE_LIST table_list;
+ bool locked;
+
+public:
+ Table_locker(THD *_thd, TABLE &_table, thr_lock_type lock_type) :
+ thd(_thd),
+ table(_table),
+ saved_type(table.reginfo.lock_type),
+ saved_lock(_thd->lock),
+ saved_mode(_thd->locked_tables_mode),
+ saved_query_tables_own_last(_thd->lex->query_tables_own_last),
+ table_list(_table, lock_type),
+ locked(false)
+ {
+ table.reginfo.lock_type= lock_type;
+ }
+ bool lock()
+ {
+ DBUG_ASSERT(table.file);
+ // FIXME: check consistency with table.reginfo.lock_type
+ if (table.file->get_lock_type() != F_UNLCK
+ || table.s->tmp_table)
+ {
+ return false;
+ }
+ thd->lock= NULL;
+ thd->locked_tables_mode= LTM_NONE;
+ thd->lex->query_tables_own_last= NULL;
+ bool res= lock_tables(thd, &table_list, 1, 0);
+ locked= !res;
+ return res;
+ }
+ ~Table_locker()
+ {
+ if (locked)
+ mysql_unlock_tables(thd, thd->lock);
+ table.reginfo.lock_type= saved_type;
+ thd->lock= saved_lock;
+ thd->locked_tables_mode= saved_mode;
+ thd->lex->query_tables_own_last= saved_query_tables_own_last;
+ if (locked && !thd->in_sub_stmt)
+ {
+ ha_commit_trans(thd, false);
+ ha_commit_trans(thd, true);
+ }
+ }
+};
+
+
+// scan table for min/max row_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;
+ DBUG_ASSERT(part->empty);
+ DBUG_ASSERT(part->type() == partition_element::HISTORY);
+ DBUG_ASSERT(table->s->stat_trx);
+
+ Table_locker l(thd, *table, TL_READ);
+ if (l.lock())
+ {
+ my_error(ER_INTERNAL_ERROR, MYF(0), "min/max scan failed on lock_tables()");
+ return true;
+ }
+
+ 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);
+
+ table->default_column_bitmaps();
+ bitmap_set_bit(table->read_set, table->vers_end_field()->field_index);
+ file->column_bitmaps_signal();
+
+ int rc= file->ha_rnd_init(true);
+ if (!rc)
+ {
+ 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();
+ file->update_partition(part_id);
+ ha_commit_trans(thd, false);
+ return true;
+ }
+ if (rc)
+ {
+ if (rc == HA_ERR_RECORD_DELETED)
+ continue;
+ break;
+ }
+ 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(VERS_TRX_ID))
+ {
+ 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->update_partition(part_id);
+ if (rc != HA_ERR_END_OF_FILE)
+ {
+ // TODO: print rc code
+ my_error(ER_INTERNAL_ERROR, MYF(0), "min/max scan failed in versioned partitions setup (see warnings)");
+ return true;
+ }
+ }
+ 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_min_max_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<Item_datetime_literal*>(col_val->item_expression);
+ DBUG_ASSERT(val_item);
+ 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)
+ {
+ ts= stat_trx_x->max_time() + 1;
+ thd->variables.time_zone->gmt_sec_to_TIME(&t, ts);
+ val_item= static_cast<Item_datetime_literal*>(col_val->item_expression);
+ DBUG_ASSERT(val_item);
+ if (*val_item < t)
+ {
+ val_item->set_time(&t);
+ col_val->fixed= 0;
+ }
+ }
+ }
+}
+
+
+// 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));
+ DBUG_ASSERT(table && table->s);
+
+ bool error= false;
+
+ TABLE_LIST tl(*table, TL_READ);
+ MDL_auto_lock mdl_lock(thd, tl);
+ if (mdl_lock.acquire_error())
+ 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);
+
+ DBUG_ASSERT(part_field_list.elements == num_columns);
+
+ bool dont_stat= true;
+ bool col_val_updated= false;
+ // initialize stat_trx
+ if (!table->s->stat_trx)
+ {
+ DBUG_ASSERT(partitions.elements > 1);
+ table->s->stat_trx= static_cast<Vers_min_max_stats**>(
+ alloc_root(&table->s->mem_root, sizeof(void *) * (partitions.elements * num_columns + 1)));
+ table->s->stat_trx[partitions.elements * num_columns]= NULL;
+ dont_stat= false;
+ }
+
+ // build freelist, scan min/max, assign hist_part
+ List_iterator<partition_element> it(partitions);
+ partition_element *el= NULL, *prev;
+ while ((prev= el, el= it++))
+ {
+ if (el->type() == partition_element::HISTORY && dont_stat)
+ {
+ if (el->id == table->s->hist_part_id)
+ {
+ vers_info->hist_part= el;
+ break;
+ }
+ continue;
+ }
+
+ {
+ 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;
+ }
+
+ if (!is_create_table_ind)
+ {
+ if (el->type() == partition_element::CURRENT)
+ {
+ 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))
+ {
+ table->s->stat_trx= NULL; // may be a leak on endless table open
+ error= true;
+ break;
+ }
+ if (!el->empty)
+ {
+ vers_update_col_vals(thd, prev, el);
+ col_val_updated= true;
+ }
+ }
+
+ if (el->type() == partition_element::CURRENT)
+ break;
+
+ DBUG_ASSERT(el->type() == partition_element::HISTORY);
+
+ if (vers_info->hist_part)
+ {
+ if (!el->empty)
+ goto set_hist_part;
+ }
+ else
+ {
+ set_hist_part:
+ vers_info->hist_part= el;
+ continue;
+ }
+ } // while
+
+ if (!error && !dont_stat)
+ {
+ if (col_val_updated)
+ table->s->stat_serial++;
+
+ table->s->hist_part_id= vers_info->hist_part->id;
+ }
+ 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 error;
+}
+
/*
Check that the partition/subpartition is setup to use the correct
@@ -962,7 +1517,7 @@ error:
called for RANGE PARTITIONed tables.
*/
-bool partition_info::check_range_constants(THD *thd)
+bool partition_info::check_range_constants(THD *thd, bool alloc)
{
partition_element* part_def;
bool first= TRUE;
@@ -979,12 +1534,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 (alloc)
{
- 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;
@@ -1017,11 +1575,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 (alloc)
{
- 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
@@ -1385,6 +1946,8 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type,
uint i, tot_partitions;
bool result= TRUE, table_engine_set;
const char *same_name;
+ uint32 hist_parts= 0;
+ uint32 now_parts= 0;
DBUG_ENTER("partition_info::check_partition_info");
DBUG_ASSERT(default_engine_type != partition_hton);
@@ -1426,7 +1989,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));
@@ -1488,6 +2052,19 @@ 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)
+ {
+ DBUG_ASSERT(vers_info);
+ if (num_parts < 2 || !vers_info->now_part)
+ {
+ DBUG_ASSERT(info && info->alias);
+ my_error(ER_VERS_WRONG_PARTS, MYF(0), info->alias);
+ goto end;
+ }
+ DBUG_ASSERT(vers_info->initialized(false));
+ DBUG_ASSERT(num_parts == partitions.elements);
+ }
i= 0;
{
List_iterator<partition_element> part_it(partitions);
@@ -1568,6 +2145,18 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type,
}
}
}
+ if (part_type == VERSIONING_PARTITION)
+ {
+ if (part_elem->type() == partition_element::HISTORY)
+ {
+ hist_parts++;
+ }
+ else
+ {
+ DBUG_ASSERT(part_elem->type() == partition_element::CURRENT);
+ now_parts++;
+ }
+ }
} while (++i < num_parts);
if (!table_engine_set &&
num_parts_not_set != 0 &&
@@ -1599,12 +2188,29 @@ 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))))
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 HISTORY partitions.");
+ }
+ }
+ if (now_parts > 1)
+ {
+ my_error(ER_VERS_WRONG_PARTS, MYF(0), info->alias);
+ goto end;
+ }
result= FALSE;
end:
DBUG_RETURN(result);
@@ -2389,6 +2995,7 @@ bool partition_info::error_if_requires_values() const
switch (part_type) {
case NOT_A_PARTITION:
case HASH_PARTITION:
+ case VERSIONING_PARTITION:
break;
case RANGE_PARTITION:
my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), "RANGE", "LESS THAN");
@@ -2834,6 +3441,30 @@ bool partition_info::has_same_partitioning(partition_info *new_part_info)
}
+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();
+ TR_table trt(thd);
+ bool found= trt.query(trx_id);
+ 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;
+ }
+ MYSQL_TIME ts;
+ trt[TR_table::FLD_COMMIT_TS]->get_date(&ts, 0);
+ out_ts.store_time_dec(&ts, 6);
+ return false;
+}
+
+
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 fc13d48e5ee..6f1414efb02 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;
@@ -34,6 +35,45 @@ 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),
+ stat_serial(0)
+ {
+ }
+ Vers_part_info(Vers_part_info &src) :
+ interval(src.interval),
+ limit(src.limit),
+ now_part(NULL),
+ hist_part(NULL),
+ stat_serial(src.stat_serial)
+ {
+ }
+ bool initialized(bool fully= true)
+ {
+ if (now_part)
+ {
+ DBUG_ASSERT(now_part->id != UINT32_MAX);
+ DBUG_ASSERT(now_part->type() == partition_element::CURRENT);
+ DBUG_ASSERT(!fully || (bool) hist_part);
+ DBUG_ASSERT(!hist_part || (
+ hist_part->id != UINT32_MAX &&
+ hist_part->type() == partition_element::HISTORY));
+ return true;
+ }
+ return false;
+ }
+ my_time_t interval;
+ ulonglong limit;
+ partition_element *now_part;
+ partition_element *hist_part;
+ ulonglong stat_serial;
+};
+
class partition_info : public Sql_alloc
{
public:
@@ -143,6 +183,8 @@ public:
part_column_list_val *range_col_array;
part_column_list_val *list_col_array;
};
+
+ Vers_part_info *vers_info;
/********************************************
* INTERVAL ANALYSIS
@@ -250,7 +292,7 @@ public:
part_expr(NULL), subpart_expr(NULL), item_free_list(NULL),
first_log_entry(NULL), exec_log_entry(NULL), frm_log_entry(NULL),
bitmaps_are_initialized(FALSE),
- list_array(NULL), err_value(0),
+ list_array(NULL), vers_info(NULL), err_value(0),
part_info_string(NULL),
curr_part_elem(NULL), current_partition(NULL),
curr_list_object(0), num_columns(0), table(NULL),
@@ -302,7 +344,7 @@ public:
const 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 alloc= true);
bool check_list_constants(THD *thd);
bool check_partition_info(THD *thd, handlerton **eng_type,
handler *file, HA_CREATE_INFO *info,
@@ -343,10 +385,170 @@ 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<char> *partition_names);
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_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);
+
+ 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<partition_element> it(partitions);
+ partition_element *el;
+ while ((el= it++))
+ {
+ DBUG_ASSERT(el->type() != partition_element::CONVENTIONAL);
+ if (el->type() == partition_element::HISTORY &&
+ el->id == table->s->hist_part_id)
+ {
+ vers_info->hist_part= el;
+ return vers_info->hist_part;
+ }
+ }
+ DBUG_ASSERT(0);
+ return NULL;
+ }
+ partition_element *get_partition(uint part_id)
+ {
+ List_iterator<partition_element> 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);
+ 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_records(part) >= vers_info->limit;
+ }
+ 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_min_max_stats* res= table->s->stat_trx[part_element_id * num_columns + fld];
+ DBUG_ASSERT(res);
+ return *res;
+ }
+ Vers_min_max_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);
+ if (!vers_info->interval)
+ return false;
+ if (!part)
+ {
+ DBUG_ASSERT(vers_info->initialized());
+ part= vers_hist_part();
+ }
+ 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)
+ {
+ 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());
+ }
+ 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::HISTORY);
+ bool updated;
+ mysql_rwlock_wrlock(&table->s->LOCK_stat_serial);
+ el->empty= false;
+ if (table->versioned(VERS_TRX_ID))
+ {
+ // transaction is not yet pushed to VTQ, so we use now-time
+ my_time_t end_ts= my_time_t(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);
+ 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));
+ }
+ bool 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 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);
+ }
+ MEM_ROOT *old_root= thd->mem_root;
+ thd->mem_root= &table->mem_root;
+ result= check_range_constants(thd, false);
+ thd->mem_root= old_root;
+ vers_info->stat_serial= table->s->stat_serial;
+ mysql_rwlock_unlock(&table->s->LOCK_stat_serial);
+ return result;
+ }
};
uint32 get_next_partition_id_range(struct st_partition_iter* part_iter);
diff --git a/sql/semisync_master_ack_receiver.cc b/sql/semisync_master_ack_receiver.cc
index 90d2190ef2c..aa588a5f300 100644
--- a/sql/semisync_master_ack_receiver.cc
+++ b/sql/semisync_master_ack_receiver.cc
@@ -17,9 +17,13 @@
#include "semisync_master.h"
#include "semisync_master_ack_receiver.h"
+#ifdef HAVE_PSI_MUTEX_INTERFACE
extern PSI_mutex_key key_LOCK_ack_receiver;
extern PSI_cond_key key_COND_ack_receiver;
+#endif
+#ifdef HAVE_PSI_THREAD_INTERFACE
extern PSI_thread_key key_thread_ack_receiver;
+#endif
extern Repl_semi_sync_master repl_semisync;
/* Callback function of ack receive thread */
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index 349e8f2c533..5a404997a56 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -5752,8 +5752,8 @@ ER_MAX_PREPARED_STMT_COUNT_REACHED 42000
eng "Can't create more than max_prepared_stmt_count statements (current value: %lu)"
ger "Kann nicht mehr Anweisungen als max_prepared_stmt_count erzeugen (aktueller Wert: %lu)"
ER_VIEW_RECURSIVE
- eng "`%-.192s`.`%-.192s` contains view recursion"
- ger "`%-.192s`.`%-.192s` enthält View-Rekursion"
+ eng "%`s.%`s contains view recursion"
+ ger "%`s.%`s enthält View-Rekursion"
ER_NON_GROUPING_FIELD_USED 42000
eng "Non-grouping field '%-.192s' is used in %-.64s clause"
ger "In der %-.192s-Klausel wird das die Nicht-Gruppierungsspalte '%-.64s' verwendet"
@@ -6249,37 +6249,37 @@ ER_BINLOG_LOGGING_IMPOSSIBLE
eng "Binary logging not possible. Message: %s"
ger "Binärlogging nicht möglich. Meldung: %s"
ER_VIEW_NO_CREATION_CTX
- eng "View `%-.64s`.`%-.64s` has no creation context"
- ger "View `%-.64s`.`%-.64s` hat keinen Erzeugungskontext"
+ eng "View %`s.%`s has no creation context"
+ ger "View %`s.%`s hat keinen Erzeugungskontext"
ER_VIEW_INVALID_CREATION_CTX
- eng "Creation context of view `%-.64s`.`%-.64s' is invalid"
- ger "Erzeugungskontext des Views`%-.64s`.`%-.64s' ist ungültig"
+ eng "Creation context of view %`s.%`s is invalid"
+ ger "Erzeugungskontext des Views%`s.%`s ist ungültig"
ER_SR_INVALID_CREATION_CTX
- eng "Creation context of stored routine `%-.64s`.`%-.64s` is invalid"
- ger "Erzeugungskontext der gespeicherten Routine`%-.64s`.`%-.64s` ist ungültig"
+ eng "Creation context of stored routine %`s.%`s is invalid"
+ ger "Erzeugungskontext der gespeicherten Routine%`s.%`s ist ungültig"
ER_TRG_CORRUPTED_FILE
- eng "Corrupted TRG file for table `%-.64s`.`%-.64s`"
- ger "Beschädigte TRG-Datei für Tabelle `%-.64s`.`%-.64s`"
+ eng "Corrupted TRG file for table %`s.%`s"
+ ger "Beschädigte TRG-Datei für Tabelle %`s.%`s"
ER_TRG_NO_CREATION_CTX
- eng "Triggers for table `%-.64s`.`%-.64s` have no creation context"
- ger "Trigger für Tabelle `%-.64s`.`%-.64s` haben keinen Erzeugungskontext"
+ eng "Triggers for table %`s.%`s have no creation context"
+ ger "Trigger für Tabelle %`s.%`s haben keinen Erzeugungskontext"
ER_TRG_INVALID_CREATION_CTX
- eng "Trigger creation context of table `%-.64s`.`%-.64s` is invalid"
- ger "Trigger-Erzeugungskontext der Tabelle `%-.64s`.`%-.64s` ist ungültig"
+ eng "Trigger creation context of table %`s.%`s is invalid"
+ ger "Trigger-Erzeugungskontext der Tabelle %`s.%`s ist ungültig"
ER_EVENT_INVALID_CREATION_CTX
- eng "Creation context of event `%-.64s`.`%-.64s` is invalid"
- ger "Erzeugungskontext des Events `%-.64s`.`%-.64s` ist ungültig"
+ eng "Creation context of event %`s.%`s is invalid"
+ ger "Erzeugungskontext des Events %`s.%`s ist ungültig"
ER_TRG_CANT_OPEN_TABLE
- eng "Cannot open table for trigger `%-.64s`.`%-.64s`"
- ger "Kann Tabelle für den Trigger `%-.64s`.`%-.64s` nicht öffnen"
+ eng "Cannot open table for trigger %`s.%`s"
+ ger "Kann Tabelle für den Trigger %`s.%`s nicht öffnen"
ER_CANT_CREATE_SROUTINE
- eng "Cannot create stored routine `%-.64s`. Check warnings"
- ger "Kann gespeicherte Routine `%-.64s` nicht erzeugen. Beachten Sie die Warnungen"
+ eng "Cannot create stored routine %`s. Check warnings"
+ ger "Kann gespeicherte Routine %`s nicht erzeugen. Beachten Sie die Warnungen"
ER_UNUSED_11
eng "You should never see it"
ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT
- eng "The BINLOG statement of type `%s` was not preceded by a format description BINLOG statement"
- ger "Der BINLOG-Anweisung vom Typ `%s` ging keine BINLOG-Anweisung zur Formatbeschreibung voran"
+ eng "The BINLOG statement of type %s was not preceded by a format description BINLOG statement"
+ ger "Der BINLOG-Anweisung vom Typ %s ging keine BINLOG-Anweisung zur Formatbeschreibung voran"
ER_SLAVE_CORRUPT_EVENT
eng "Corrupted replication event was detected"
ger "Beschädigtes Replikationsereignis entdeckt"
@@ -6596,7 +6596,7 @@ ER_MULTI_UPDATE_KEY_CONFLICT
# When translating this error message make sure to include "ALTER TABLE" in the
# message as mysqlcheck parses the error message looking for ALTER TABLE.
ER_TABLE_NEEDS_REBUILD
- eng "Table rebuild required. Please do \"ALTER TABLE `%-.32s` FORCE\" or dump/reload to fix it!"
+ eng "Table rebuild required. Please do \"ALTER TABLE %`s FORCE\" or dump/reload to fix it!"
WARN_OPTION_BELOW_LIMIT
eng "The value of '%s' should be no less than the value of '%s'"
@@ -7812,3 +7812,99 @@ ER_INVALID_VALUE_TO_LIMIT
eng "Limit only accepts integer values"
ER_INVISIBLE_NOT_NULL_WITHOUT_DEFAULT
eng "Invisible column %`s must have a default value"
+
+
+# MariaDB error numbers related to System Versioning
+
+ER_UPDATE_INFO_WITH_SYSTEM_VERSIONING
+ eng "Rows matched: %ld Changed: %ld Inserted: %ld Warnings: %ld"
+
+ER_VERS_FIELD_WRONG_TYPE
+ eng "%`s must be of type %s for system-versioned table %`s"
+
+ER_VERS_ENGINE_UNSUPPORTED
+ eng "Transaction system versioning for %`s is not supported"
+
+ER_NON_VERSIONED_FIELD_IN_HISTORICAL_QUERY
+ eng "Non-versioned field %`s in historical query"
+
+ER_PARTITION_WRONG_TYPE
+ eng "Wrong partitioning type, expected type: %`s"
+
+WARN_VERS_PART_FULL
+ eng "Versioned table %`s.%`s: partition %`s is full, add more HISTORY partitions"
+
+WARN_VERS_PARAMETERS
+ eng "Maybe missing parameters: %s"
+
+WARN_VERS_PART_ROTATION
+ eng "Versioned table %`s.%`s: 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_ALTER_NOT_ALLOWED
+ eng "Not allowed for system-versioned %`s.%`s. Change @@system_versioning_alter_history to proceed with ALTER."
+
+ER_VERS_ALTER_ENGINE_PROHIBITED
+ eng "Not allowed for system-versioned %`s.%`s. Change to/from native system versioning engine is prohibited."
+
+ER_VERS_RANGE_PROHIBITED
+ eng "SYSTEM_TIME range selector is prohibited"
+
+ER_VERS_VTMD_ERROR
+ eng "VTMD error: %s"
+
+ER_VERS_TABLE_MUST_HAVE_COLUMNS
+ eng "Table %`s must have at least one versioned column"
+
+ER_VERS_NOT_VERSIONED
+ eng "Table %`s is not system-versioned"
+
+ER_MISSING
+ eng "Wrong parameters for %`s: missing '%s'"
+
+ER_VERS_PERIOD_COLUMNS
+ eng "PERIOD FOR SYSTEM_TIME must use columns %`s and %`s"
+
+ER_PART_WRONG_VALUE
+ eng "Wrong parameters for partitioned %`s: wrong value for '%s'"
+
+ER_VERS_WRONG_PARTS
+ eng "Wrong partitions for %`s: must have at least one HISTORY and exactly one last CURRENT"
+
+ER_VERS_NO_TRX_ID
+ eng "TRX_ID %lu not found in `mysql.transaction_registry`"
+
+ER_VERS_ALTER_SYSTEM_FIELD
+ eng "Can not change system versioning field %`s"
+
+ER_VERS_SYS_FIELD_EXISTS
+ eng "System versioning field %`s exists"
+
+ER_NOT_LOG_TABLE
+ eng "Table %`s.%`s is not a log table"
+
+ER_VERS_TRT_IS_DISABLED
+ eng "Temporal operation requires `mysql.transaction_registry` (@@system_versioning_transaction_registry)."
+
+ER_VERS_DUPLICATE_ROW_START_END
+ eng "Duplicate ROW %s column %`s"
+
+ER_VERS_ALREADY_VERSIONED
+ eng "Table %`s is already system-versioned"
+
+WARN_VERS_TRT_EXPERIMENTAL
+ eng "Transaction-based system versioning is EXPERIMENTAL and is subject to change in future."
+
+ER_VERS_TRUNCATE_VIEW
+ eng "DELETE HISTORY from VIEW is prohibited"
+
+ER_VERS_TEMPORARY
+ eng "System versioning prohibited for TEMPORARY tables"
+
+ER_VERS_INPLACE_NOT_IMPLEMENTED
+ eng "Not implemented for system-versioned tables"
diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc
index 342673bf619..0fd6fe92d1f 100644
--- a/sql/sp_cache.cc
+++ b/sql/sp_cache.cc
@@ -23,7 +23,7 @@
#include "sp_head.h"
static mysql_mutex_t Cversion_lock;
-static ulong volatile Cversion= 0;
+static ulong volatile Cversion= 1;
/*
@@ -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 a045ff5d3c5..59e0fc186dd 100644
--- a/sql/sp_cache.h
+++ b/sql/sp_cache.h
@@ -60,6 +60,7 @@ void sp_cache_insert(sp_cache **cp, sp_head *sp);
sp_head *sp_cache_lookup(sp_cache **cp, const Database_qualified_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 0b72c76b05b..decf007b2d8 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -2541,6 +2541,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 %p returned from thd mem root %p",
&mem_root, &thd->mem_root));
@@ -3271,7 +3272,7 @@ sp_instr_stmt::execute(THD *thd, uint *nextp)
int res;
bool save_enable_slow_log;
const CSET_STRING query_backup= thd->query_string;
- QUERY_START_TIME_INFO time_info;
+ Backup_query_start_time time_info;
Sub_statement_state backup_state;
DBUG_ENTER("sp_instr_stmt::execute");
DBUG_PRINT("info", ("command: %d", m_lex_keeper.sql_command()));
@@ -3287,7 +3288,7 @@ sp_instr_stmt::execute(THD *thd, uint *nextp)
Save start time info for the CALL statement and overwrite it with the
current time for log_slow_statement() to log the individual query timing.
*/
- thd->get_time(&time_info);
+ time_info.backup(*thd);
thd->set_time();
}
thd->store_slow_query_state(&backup_state);
@@ -3353,9 +3354,6 @@ sp_instr_stmt::execute(THD *thd, uint *nextp)
thd->get_stmt_da()->reset_diagnostics_area();
}
}
- /* Restore the original query start time */
- if (thd->enable_slow_log)
- thd->set_time(&time_info);
DBUG_RETURN(res || thd->is_error());
}
diff --git a/sql/sp_head.h b/sql/sp_head.h
index 7e477544958..04b67941226 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -213,7 +213,7 @@ public:
ulong sp_cache_version() const { return m_sp_cache_version; }
/** Set the value of the SP cache version. */
- void set_sp_cache_version(ulong version_arg)
+ void set_sp_cache_version(ulong version_arg) const
{
m_sp_cache_version= version_arg;
}
@@ -235,7 +235,7 @@ private:
is obsolete and should not be used --
sp_cache_flush_obsolete() will purge it.
*/
- ulong m_sp_cache_version;
+ mutable ulong m_sp_cache_version;
Stored_program_creation_ctx *m_creation_ctx;
/**
Boolean combination of (1<<flag), where flag is a member of
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 85df471a3c0..d3edaa2b56a 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("Truncate_versioning_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, const 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)
@@ -2013,6 +2018,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_HISTORY_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;
@@ -8488,13 +8496,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,
};
@@ -12449,12 +12458,10 @@ read_client_connect_attrs(char **ptr, char *end, CHARSET_INFO *from_cs)
if (length > 65535)
return true;
-#ifdef HAVE_PSI_THREAD_INTERFACE
- if (PSI_THREAD_CALL(set_thread_connect_attrs)(*ptr, (size_t)length, from_cs) &&
+ if (PSI_CALL_set_thread_connect_attrs(*ptr, (size_t)length, from_cs) &&
current_thd->variables.log_warnings)
sql_print_warning("Connection attributes of length %llu were truncated",
length);
-#endif
return false;
}
@@ -13527,11 +13534,9 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len)
else
my_ok(thd);
-#ifdef HAVE_PSI_THREAD_INTERFACE
- PSI_THREAD_CALL(set_thread_user_host)
+ PSI_CALL_set_thread_user_host
(thd->main_security_ctx.user, strlen(thd->main_security_ctx.user),
thd->main_security_ctx.host_or_ip, strlen(thd->main_security_ctx.host_or_ip));
-#endif
/* Ready to handle queries */
DBUG_RETURN(0);
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index e299844a71a..bafb9ca23d8 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -49,6 +49,7 @@
#define EVENT_ACL (1UL << 26)
#define TRIGGER_ACL (1UL << 27)
#define CREATE_TABLESPACE_ACL (1UL << 28)
+#define DELETE_HISTORY_ACL (1UL << 29)
/*
don't forget to update
1. static struct show_privileges_st sys_privileges[]
@@ -62,12 +63,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_HISTORY_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_HISTORY_ACL)
#define COL_ACLS \
(SELECT_ACL | INSERT_ACL | UPDATE_ACL | REFERENCES_ACL)
@@ -85,7 +87,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_HISTORY_ACL)
#define DEFAULT_CREATE_PROC_ACLS \
(ALTER_PROC_ACL | EXECUTE_ACL)
@@ -117,31 +119,37 @@
CREATE_PROC_ACL | ALTER_PROC_ACL )
#define DB_CHUNK4 (EXECUTE_ACL)
#define DB_CHUNK5 (EVENT_ACL | TRIGGER_ACL)
+#define DB_CHUNK6 (DELETE_HISTORY_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_HISTORY_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) | \
@@ -175,6 +183,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_alter.h b/sql/sql_alter.h
index 25e377be8de..5478ce74c10 100644
--- a/sql/sql_alter.h
+++ b/sql/sql_alter.h
@@ -95,11 +95,35 @@ public:
// Set for ADD [COLUMN] FIRST | AFTER
ALTER_COLUMN_ORDER = 1L << 25,
ALTER_ADD_CHECK_CONSTRAINT = 1L << 27,
- ALTER_DROP_CHECK_CONSTRAINT = 1L << 28
+ ALTER_DROP_CHECK_CONSTRAINT = 1L << 28,
+ ALTER_COLUMN_UNVERSIONED = 1L << 29,
+ ALTER_ADD_SYSTEM_VERSIONING = 1L << 30,
+ ALTER_DROP_SYSTEM_VERSIONING= 1L << 31,
};
enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE };
+ bool data_modifying() const
+ {
+ return flags & (
+ ALTER_ADD_COLUMN |
+ ALTER_DROP_COLUMN |
+ ALTER_CHANGE_COLUMN |
+ ALTER_COLUMN_ORDER);
+ }
+
+ bool partition_modifying() const
+ {
+ return flags & (
+ ALTER_DROP_PARTITION |
+ ALTER_COALESCE_PARTITION |
+ ALTER_REORGANIZE_PARTITION |
+ ALTER_REMOVE_PARTITIONING |
+ ALTER_TABLE_REORG |
+ ALTER_EXCHANGE_PARTITION |
+ ALTER_TRUNCATE_PARTITION);
+ }
+
/**
The different values of the ALGORITHM clause.
Describes which algorithm to use when altering the table.
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index a441b0ef6a6..69b867da0cb 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -5653,7 +5653,7 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
if (field_ptr && *field_ptr)
{
- if ((*field_ptr)->field_visibility == COMPLETELY_INVISIBLE &&
+ if ((*field_ptr)->invisible == INVISIBLE_FULL &&
DBUG_EVALUATE_IF("test_completely_invisible", 0, 1))
DBUG_RETURN((Field*)0);
@@ -5867,6 +5867,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
@@ -6544,6 +6545,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->str, using_fields);
@@ -7238,7 +7243,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.
@@ -7612,6 +7617,35 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table,
}
+#ifdef VERS_EXPERIMENTAL
+inline
+bool Field::vers_sys_invisible(THD *thd) const
+{
+ DBUG_ASSERT(vers_sys_field());
+ DBUG_ASSERT(table);
+ DBUG_ASSERT(table->versioned());
+ DBUG_ASSERT(table->pos_in_table_list);
+
+ if (thd->lex->sql_command != SQLCOM_SELECT)
+ return invisible;
+
+ switch (thd->variables.vers_show)
+ {
+ case VERS_SHOW_RANGE:
+ {
+ vers_system_time_t vers_type= table->pos_in_table_list->vers_conditions.type;
+ return vers_type > SYSTEM_TIME_AS_OF ? false : invisible;
+ }
+ case VERS_SHOW_ALWAYS:
+ return false;
+ default:
+ break;
+ };
+ return invisible;
+}
+#endif
+
+
/*
Drops in all fields instead of current '*' field
@@ -7741,9 +7775,14 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
Field_iterator_natural_join).
But view fields can never be invisible.
*/
- if ((field= field_iterator.field()) &&
- field->field_visibility != NOT_INVISIBLE)
+ if ((field= field_iterator.field()) && (
+#ifdef VERS_EXPERIMENTAL
+ field->vers_sys_field() && field->table->versioned() ?
+ field->vers_sys_invisible(thd) :
+#endif
+ field->invisible != VISIBLE))
continue;
+
Item *item;
if (!(item= field_iterator.create_item(thd)))
@@ -8093,6 +8132,7 @@ fill_record(THD *thd, TABLE *table_arg, List<Item> &fields, List<Item> &values,
List_iterator_fast<Item> f(fields),v(values);
Item *value, *fld;
Item_field *field;
+ bool only_unvers_fields= update && table_arg->versioned();
bool save_abort_on_warning= thd->abort_on_warning;
bool save_no_errors= thd->no_errors;
DBUG_ENTER("fill_record");
@@ -8127,22 +8167,29 @@ fill_record(THD *thd, TABLE *table_arg, List<Item> &fields, List<Item> &values,
goto err;
}
value=v++;
+ DBUG_ASSERT(value);
Field *rfield= field->field;
TABLE* table= rfield->table;
if (table->next_number_field &&
rfield->field_index == table->next_number_field->field_index)
table->auto_increment_field_not_null= TRUE;
Item::Type type= value->type();
- if (rfield->vcol_info &&
+ bool vers_sys_field= table->versioned() && rfield->vers_sys_field();
+ if ((rfield->vcol_info || vers_sys_field) &&
type != Item::DEFAULT_VALUE_ITEM &&
type != Item::NULL_ITEM &&
table->s->table_category != TABLE_CATEGORY_TEMPORARY)
{
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_WARNING_NON_DEFAULT_VALUE_FOR_VIRTUAL_COLUMN,
- ER_THD(thd, ER_WARNING_NON_DEFAULT_VALUE_FOR_VIRTUAL_COLUMN),
+ ER_WARNING_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN,
+ ER_THD(thd, ER_WARNING_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN),
rfield->field_name.str, table->s->table_name.str);
+ if (vers_sys_field)
+ continue;
}
+ if (only_unvers_fields && !rfield->vers_update_unversioned())
+ only_unvers_fields= false;
+
if (rfield->stored_in_db() &&
(value->save_in_field(rfield, 0)) < 0 && !ignore_errors)
{
@@ -8159,6 +8206,8 @@ fill_record(THD *thd, TABLE *table_arg, List<Item> &fields, List<Item> &values,
if (table_arg->vfield &&
table_arg->update_virtual_fields(table_arg->file, VCOL_UPDATE_FOR_WRITE))
goto err;
+ if (table_arg->versioned() && !only_unvers_fields)
+ table_arg->vers_update_fields();
thd->abort_on_warning= save_abort_on_warning;
thd->no_errors= save_no_errors;
DBUG_RETURN(thd->is_error());
@@ -8211,7 +8260,7 @@ void switch_defaults_to_nullable_trigger_fields(TABLE *table)
Field **trigger_field= table->field_to_fill();
/* True if we have NOT NULL fields and BEFORE triggers */
- if (trigger_field != table->field)
+ if (*trigger_field != *table->field)
{
for (Field **field_ptr= table->default_field; *field_ptr ; field_ptr++)
{
@@ -8372,13 +8421,18 @@ fill_record(THD *thd, TABLE *table, Field **ptr, List<Item> &values,
/* Ensure that all fields are from the same table */
DBUG_ASSERT(field->table == table);
- if (field->field_visibility != NOT_INVISIBLE)
+ if (field->invisible)
+ {
continue;
+ }
else
value=v++;
+
+ bool vers_sys_field= table->versioned() && field->vers_sys_field();
+
if (field->field_index == autoinc_index)
table->auto_increment_field_not_null= TRUE;
- if (field->vcol_info)
+ if (field->vcol_info || (vers_sys_field && !ignore_errors))
{
Item::Type type= value->type();
if (type != Item::DEFAULT_VALUE_ITEM &&
@@ -8386,9 +8440,11 @@ fill_record(THD *thd, TABLE *table, Field **ptr, List<Item> &values,
table->s->table_category != TABLE_CATEGORY_TEMPORARY)
{
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_WARNING_NON_DEFAULT_VALUE_FOR_VIRTUAL_COLUMN,
- ER_THD(thd, ER_WARNING_NON_DEFAULT_VALUE_FOR_VIRTUAL_COLUMN),
+ ER_WARNING_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN,
+ ER_THD(thd, ER_WARNING_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN),
field->field_name.str, table->s->table_name.str);
+ if (vers_sys_field)
+ continue;
}
}
@@ -8407,6 +8463,8 @@ fill_record(THD *thd, TABLE *table, Field **ptr, List<Item> &values,
if (table->vfield &&
table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_WRITE))
goto err;
+ if (table->versioned())
+ table->vers_update_fields();
thd->abort_on_warning= abort_on_warning_saved;
DBUG_RETURN(thd->is_error());
@@ -8565,7 +8623,6 @@ int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order)
{
List_iterator<Item_func_match> li(*(select_lex->ftfunc_list));
Item_func_match *ifm;
- DBUG_PRINT("info",("Performing FULLTEXT search"));
while ((ifm=li++))
if (ifm->init_search(thd, no_order))
@@ -8755,10 +8812,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->s->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->s->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/sql_class.cc b/sql/sql_class.cc
index 9d83e467c82..84fdaf8b1b6 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -705,7 +705,6 @@ extern "C" void thd_kill_timeout(THD* thd)
thd->awake(KILL_TIMEOUT);
}
-
THD::THD(my_thread_id id, bool is_wsrep_applier, bool skip_global_sys_var_lock)
:Statement(&main_lex, &main_mem_root, STMT_CONVENTIONAL_EXECUTION,
/* statement id */ 0),
@@ -3713,6 +3712,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;
}
@@ -4790,7 +4790,7 @@ extern "C" int thd_slave_thread(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;
}
@@ -7061,6 +7061,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.
@@ -7680,3 +7689,16 @@ void Database_qualified_name::copy(MEM_ROOT *mem_root,
#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 8747d658aea..c15bbe54a1b 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -706,6 +706,14 @@ typedef struct system_variables
uint column_compression_threshold;
uint column_compression_zlib_level;
uint in_subquery_conversion_threshold;
+
+ vers_asof_timestamp_t vers_asof_timestamp;
+#ifdef VERS_EXPERIMENTAL
+ my_bool vers_force;
+ ulong vers_show;
+#endif
+ my_bool vers_innodb_algorithm_simple;
+ ulong vers_alter_history;
} SV;
/**
@@ -948,6 +956,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
{
@@ -955,7 +968,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
@@ -975,6 +989,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)
@@ -1019,6 +1035,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;
/**
@@ -1768,8 +1800,9 @@ private:
class Locked_tables_list
{
-private:
+public:
MEM_ROOT m_locked_tables_root;
+private:
TABLE_LIST *m_locked_tables;
TABLE_LIST **m_locked_tables_last;
/** An auxiliary array used only in reopen_tables(). */
@@ -2051,12 +2084,43 @@ struct wait_for_commit
Structure to store the start time for a query
*/
-typedef struct
+struct QUERY_START_TIME_INFO
{
my_time_t start_time;
- ulong start_time_sec_part;
+ ulong start_time_sec_part;
ulonglong start_utime, utime_after_lock;
-} QUERY_START_TIME_INFO;
+};
+
+class Backup_query_start_time : public QUERY_START_TIME_INFO
+{
+ QUERY_START_TIME_INFO *m_origin;
+
+public:
+ Backup_query_start_time() : m_origin(NULL)
+ {}
+ Backup_query_start_time(QUERY_START_TIME_INFO &origin)
+ {
+ backup(origin);
+ }
+ ~Backup_query_start_time()
+ {
+ restore();
+ }
+ void backup(QUERY_START_TIME_INFO &origin)
+ {
+ m_origin= &origin;
+ QUERY_START_TIME_INFO *backup_= this;
+ *backup_= origin;
+ }
+ void restore()
+ {
+ if (m_origin)
+ {
+ *m_origin= *this;
+ m_origin= NULL;
+ }
+ }
+};
extern "C" void my_message_sql(uint error, const char *str, myf MyFlags);
@@ -2068,7 +2132,8 @@ extern "C" void my_message_sql(uint error, const char *str, myf MyFlags);
class THD :public Statement,
public MDL_context_owner,
- public Open_tables_state
+ public Open_tables_state,
+ public QUERY_START_TIME_INFO
{
private:
inline bool is_stmt_prepare() const
@@ -2293,12 +2358,12 @@ public:
uint32 file_id; // for LOAD DATA INFILE
/* remote (peer) port */
uint16 peer_port;
- my_time_t start_time; // start_time and its sec_part
- ulong start_time_sec_part; // are almost always used separately
my_hrtime_t user_time;
// track down slow pthread_create
ulonglong prior_thr_create_utime, thr_create_utime;
- ulonglong start_utime, utime_after_lock, utime_after_query;
+ ulonglong utime_after_query;
+ my_time_t system_time;
+ ulong system_time_sec_part;
// Process indicator
struct {
@@ -3315,27 +3380,50 @@ 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; }
- inline void set_current_time()
+ MYSQL_TIME query_start_TIME();
+
+private:
+ bool system_time_ge(my_time_t secs, ulong usecs)
+ {
+ return (system_time == secs && system_time_sec_part >= usecs) ||
+ system_time > secs;
+ }
+
+ void set_system_time()
{
my_hrtime_t hrtime= my_hrtime();
- start_time= hrtime_to_my_time(hrtime);
- start_time_sec_part= hrtime_sec_part(hrtime);
-#ifdef HAVE_PSI_THREAD_INTERFACE
- PSI_THREAD_CALL(set_thread_start_time)(start_time);
-#endif
+ my_time_t secs= hrtime_to_my_time(hrtime);
+ ulong usecs= hrtime_sec_part(hrtime);
+ if (system_time_ge(secs, usecs))
+ {
+ if (++system_time_sec_part == HRTIME_RESOLUTION)
+ {
+ ++system_time;
+ system_time_sec_part= 0;
+ }
+ }
+ else
+ {
+ system_time= secs;
+ system_time_sec_part= usecs;
+ }
}
+
+public:
inline void set_start_time()
{
+ set_system_time();
if (user_time.val)
{
start_time= hrtime_to_my_time(user_time);
start_time_sec_part= hrtime_sec_part(user_time);
-#ifdef HAVE_PSI_THREAD_INTERFACE
- PSI_THREAD_CALL(set_thread_start_time)(start_time);
-#endif
}
else
- set_current_time();
+ {
+ start_time= system_time;
+ start_time_sec_part= system_time_sec_part;
+ }
+ PSI_CALL_set_thread_start_time(start_time);
}
inline void set_time()
{
@@ -3358,20 +3446,6 @@ public:
MYSQL_SET_STATEMENT_LOCK_TIME(m_statement_psi,
(utime_after_lock - start_utime));
}
- void get_time(QUERY_START_TIME_INFO *time_info)
- {
- time_info->start_time= start_time;
- time_info->start_time_sec_part= start_time_sec_part;
- time_info->start_utime= start_utime;
- time_info->utime_after_lock= utime_after_lock;
- }
- void set_time(QUERY_START_TIME_INFO *time_info)
- {
- start_time= time_info->start_time;
- start_time_sec_part= time_info->start_time_sec_part;
- start_utime= time_info->start_utime;
- utime_after_lock= time_info->utime_after_lock;
- }
ulonglong current_utime() { return microsecond_interval_timer(); }
/* Tell SHOW PROCESSLIST to show time from this point */
@@ -3979,10 +4053,8 @@ public:
db_length= db ? new_db_len : 0;
bool result= new_db && !db;
mysql_mutex_unlock(&LOCK_thd_data);
-#ifdef HAVE_PSI_THREAD_INTERFACE
if (result)
- PSI_THREAD_CALL(set_thread_db)(new_db, (int) new_db_len);
-#endif
+ PSI_CALL_set_thread_db(new_db, (int) new_db_len);
return result;
}
@@ -4005,9 +4077,7 @@ public:
db= new_db;
db_length= new_db_len;
mysql_mutex_unlock(&LOCK_thd_data);
-#ifdef HAVE_PSI_THREAD_INTERFACE
- PSI_THREAD_CALL(set_thread_db)(new_db, (int) new_db_len);
-#endif
+ PSI_CALL_set_thread_db(new_db, (int) new_db_len);
}
}
/*
@@ -4111,7 +4181,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 */
@@ -4221,9 +4296,7 @@ public:
set_query_inner(string_arg);
mysql_mutex_unlock(&LOCK_thd_data);
-#ifdef HAVE_PSI_THREAD_INTERFACE
- PSI_THREAD_CALL(set_thread_info)(query(), query_length());
-#endif
+ PSI_CALL_set_thread_info(query(), query_length());
}
void reset_query() /* Mutex protected */
{ set_query(CSET_STRING()); }
@@ -4530,6 +4603,7 @@ public:
/* Handling of timeouts for commands */
thr_timer_t query_timer;
+
public:
void set_query_timer()
{
@@ -5027,6 +5101,7 @@ class select_insert :public select_result_interceptor {
ulonglong autoinc_value_of_last_inserted_row; // autogenerated or not
COPY_INFO info;
bool insert_into_view;
+ bool versioned_write;
select_insert(THD *thd_arg, TABLE_LIST *table_list_par,
TABLE *table_par, List<Item> *fields_par,
List<Item> *update_fields, List<Item> *update_values,
@@ -5087,6 +5162,12 @@ public:
const THD *get_thd(void) { return thd; }
const HA_CREATE_INFO *get_create_info() { return create_info; };
int prepare2(void) { return 0; }
+
+private:
+ TABLE *create_table_from_items(THD *thd,
+ List<Item> *items,
+ MYSQL_LOCK **lock,
+ TABLEOP_HOOKS *hooks);
};
#include <myisam.h>
@@ -5748,6 +5829,12 @@ 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;
+
+ bool has_vers_fields;
+
public:
multi_update(THD *thd_arg, TABLE_LIST *ut, List<TABLE_LIST> *leaves_list,
List<Item> *fields, List<Item> *values,
@@ -6327,6 +6414,24 @@ public:
void dbug_serve_apcs(THD *thd, int n_calls);
#endif
-#endif /* MYSQL_SERVER */
+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 984a0799b54..a382fdb7c03 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -223,13 +223,21 @@ bool Update_plan::save_explain_data_intern(MEM_ROOT *mem_root,
static bool record_should_be_deleted(THD *thd, TABLE *table, SQL_SELECT *sel,
- Explain_delete *explain)
+ Explain_delete *explain, bool truncate_history)
{
+ bool check_delete= true;
+
+ if (table->versioned())
+ {
+ bool historical= !table->vers_end_field()->is_max();
+ check_delete= truncate_history ? historical : !historical;
+ }
+
explain->tracker.on_record_read();
thd->inc_examined_row_count(1);
if (table->vfield)
(void) table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_DELETE);
- if (!sel || sel->skip_record(thd) > 0)
+ if (check_delete && (!sel || sel->skip_record(thd) > 0))
{
explain->tracker.on_record_after_where();
return true;
@@ -238,6 +246,18 @@ static bool record_should_be_deleted(THD *thd, TABLE *table, SQL_SELECT *sel,
}
+inline
+int TABLE::delete_row()
+{
+ if (!versioned(VERS_TIMESTAMP) || !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.
@@ -284,6 +304,39 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
DBUG_RETURN(TRUE);
THD_STAGE_INFO(thd, stage_init_update);
+
+ bool truncate_history= table_list->vers_conditions;
+ if (truncate_history)
+ {
+ if (table_list->is_view_or_derived())
+ {
+ my_error(ER_VERS_TRUNCATE_VIEW, MYF(0));
+ DBUG_RETURN(true);
+ }
+
+ TABLE *table= table_list->table;
+ DBUG_ASSERT(table);
+
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ if (table->part_info)
+ {
+ my_error(ER_NOT_ALLOWED_COMMAND, MYF(0));
+ DBUG_RETURN(true);
+ }
+#endif
+
+ DBUG_ASSERT(!conds || thd->stmt_arena->is_stmt_execute());
+ if (select_lex->vers_setup_conds(thd, table_list, &conds))
+ DBUG_RETURN(TRUE);
+
+ // trx_sees() in InnoDB reads row_start
+ if (!table->versioned(VERS_TIMESTAMP))
+ {
+ DBUG_ASSERT(table_list->vers_conditions.type == SYSTEM_TIME_BEFORE);
+ bitmap_set_bit(table->read_set, table->vers_end_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))
@@ -378,7 +431,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
table->triggers->has_delete_triggers());
if (!with_select && !using_limit && const_cond_result &&
(!thd->is_current_stmt_binlog_format_row() &&
- !has_triggers))
+ !has_triggers)
+ && !table->versioned(VERS_TIMESTAMP))
{
/* Update the table->file->stats.records number */
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
@@ -650,7 +704,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
while (!(error=info.read_record()) && !thd->killed &&
! thd->is_error())
{
- if (record_should_be_deleted(thd, table, select, explain))
+ if (record_should_be_deleted(thd, table, select, explain, truncate_history))
{
table->file->position(table->record[0]);
if ((error= deltempfile->unique_add((char*) table->file->ref)))
@@ -677,10 +731,11 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
! thd->is_error())
{
if (delete_while_scanning)
- delete_record= record_should_be_deleted(thd, table, select, explain);
+ delete_record= record_should_be_deleted(thd, table, select, explain,
+ truncate_history);
if (delete_record)
{
- if (table->triggers &&
+ if (!truncate_history && table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
TRG_ACTION_BEFORE, FALSE))
{
@@ -694,10 +749,11 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
break;
}
- if (!(error= table->file->ha_delete_row(table->record[0])))
+ error= table->delete_row();
+ if (!error)
{
deleted++;
- if (table->triggers &&
+ if (!truncate_history && table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
TRG_ACTION_AFTER, FALSE))
{
@@ -784,6 +840,8 @@ cleanup:
else
errcode= query_error_code(thd, killed_status == NOT_KILLED);
+ ScopedStatementReplication scoped_stmt_rpl(
+ table->versioned(VERS_TRX_ID) ? thd : NULL);
/*
[binlog]: If 'handler::delete_all_rows()' was called and the
storage engine does not inject the rows itself, we replicate
@@ -884,6 +942,16 @@ l
select_lex->leaf_tables, FALSE,
DELETE_ACL, SELECT_ACL, TRUE))
DBUG_RETURN(TRUE);
+ if (table_list->vers_conditions)
+ {
+ if (table_list->is_view())
+ {
+ my_error(ER_VERS_TRUNCATE_VIEW, MYF(0));
+ DBUG_RETURN(true);
+ }
+ if (select_lex->vers_setup_conds(thd, table_list, conds))
+ DBUG_RETURN(true);
+ }
if ((wild_num && setup_wild(thd, table_list, field_list, NULL, wild_num)) ||
setup_fields(thd, Ref_ptr_array(),
field_list, MARK_COLUMNS_READ, NULL, NULL, 0) ||
@@ -1169,6 +1237,11 @@ int multi_delete::send_data(List<Item> &values)
if (table->status & (STATUS_NULL_ROW | STATUS_DELETED))
continue;
+ if (table->versioned() && !table->vers_end_field()->is_max())
+ {
+ continue;
+ }
+
table->file->position(table->record[0]);
found++;
@@ -1181,7 +1254,9 @@ int multi_delete::send_data(List<Item> &values)
TRG_ACTION_BEFORE, FALSE))
DBUG_RETURN(1);
table->status|= STATUS_DELETED;
- if (!(error=table->file->ha_delete_row(table->record[0])))
+
+ error= table->delete_row();
+ if (!error)
{
deleted++;
if (!table->file->has_transactions())
@@ -1360,8 +1435,8 @@ 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]);
+
+ local_error= table->delete_row();
if (local_error && !ignore)
{
table->file->print_error(local_error, MYF(0));
diff --git a/sql/sql_error.h b/sql/sql_error.h
index f8b8adc805a..b89af72cc44 100644
--- a/sql/sql_error.h
+++ b/sql/sql_error.h
@@ -1174,7 +1174,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_insert.cc b/sql/sql_insert.cc
index 0cf121fdd59..203838dac10 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -676,6 +676,12 @@ static void save_insert_query_plan(THD* thd, TABLE_LIST *table_list)
}
+Field **TABLE::field_to_fill()
+{
+ return triggers && triggers->nullable_fields() ? triggers->nullable_fields() : field;
+}
+
+
/**
INSERT statement implementation
@@ -1139,8 +1145,10 @@ values_loop_end:
}
else
errcode= query_error_code(thd, thd->killed == NOT_KILLED);
-
- /* bug#22725:
+
+ ScopedStatementReplication scoped_stmt_rpl(
+ table->versioned(VERS_TRX_ID) ? thd : NULL);
+ /* bug#22725:
A query which per-row-loop can not be interrupted with
KILLED, like INSERT, and that does not invoke stored
@@ -1560,6 +1568,13 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
if (!table)
table= table_list->table;
+ if (table->versioned(VERS_TIMESTAMP) && 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;
@@ -1611,6 +1626,25 @@ 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)
+{
+ DBUG_ASSERT(table->versioned(VERS_TIMESTAMP));
+ restore_record(table,record[1]);
+
+ // Set Sys_end to now()
+ if (table->vers_end_field()->set_time())
+ DBUG_ASSERT(0);
+
+ return table->file->ha_write_row(table->record[0]);
+}
+
+/*
Write a record to table with optional deleting of conflicting records,
invoke proper triggers if needed.
@@ -1814,7 +1848,26 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
}
if (error != HA_ERR_RECORD_IS_THE_SAME)
+ {
info->updated++;
+ if (table->versioned())
+ {
+ if (table->versioned(VERS_TIMESTAMP))
+ {
+ store_record(table, record[2]);
+ if ((error= vers_insert_history_row(table)))
+ {
+ info->last_errno= error;
+ table->file->print_error(error, MYF(0));
+ trg_error= 1;
+ restore_record(table, record[2]);
+ goto ok_or_after_trg_err;
+ }
+ restore_record(table, record[2]);
+ }
+ info->copied++;
+ }
+ }
else
error= 0;
/*
@@ -1866,17 +1919,35 @@ 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() &&
+ 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()))
{
+ if (table->versioned(VERS_TRX_ID))
+ {
+ bitmap_set_bit(table->write_set, table->vers_start_field()->field_index);
+ table->vers_start_field()->set_notnull();
+ table->vers_start_field()->store(0, false);
+ }
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)
+ {
info->deleted++;
+ if (table->versioned(VERS_TIMESTAMP))
+ {
+ store_record(table, record[2]);
+ error= vers_insert_history_row(table);
+ restore_record(table, record[2]);
+ if (error)
+ goto err;
+ }
+ }
else
error= 0;
thd->record_first_successful_insert_id_in_cur_stmt(table->file->insert_id_for_cur_row);
@@ -1892,9 +1963,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(VERS_TIMESTAMP))
+ 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(VERS_TIMESTAMP))
+ info->deleted++;
+ else
+ info->updated++;
if (!table->file->has_transactions())
thd->transaction.stmt.modified_non_trans_table= TRUE;
if (table->triggers &&
@@ -1982,7 +2073,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))
+ !(*field)->vers_sys_field() &&
+ has_no_default_value(thd, *field, table_list) &&
+ ((*field)->real_type() != MYSQL_TYPE_ENUM))
err=1;
}
return thd->abort_on_warning ? err : 0;
@@ -2845,7 +2938,7 @@ pthread_handler_t handle_delayed_insert(void *arg)
pthread_detach_this_thread();
/* Add thread to THD list so that's it's visible in 'show processlist' */
- thd->set_current_time();
+ thd->set_start_time();
add_to_active_threads(thd);
if (abort_loop)
thd->set_killed(KILL_CONNECTION);
@@ -3499,7 +3592,8 @@ select_insert::select_insert(THD *thd_arg, TABLE_LIST *table_list_par,
select_result_interceptor(thd_arg),
table_list(table_list_par), table(table_par), fields(fields_par),
autoinc_value_of_last_inserted_row(0),
- insert_into_view(table_list_par && table_list_par->view != 0)
+ insert_into_view(table_list_par && table_list_par->view != 0),
+ versioned_write(false)
{
bzero((char*) &info,sizeof(info));
info.handle_duplicates= duplic;
@@ -3534,6 +3628,8 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
check_insert_fields(thd, table_list, *fields, values,
!insert_into_view, 1, &map));
+ versioned_write= table_list->table->versioned();
+
if (!res && fields->elements)
{
bool saved_abort_on_warning= thd->abort_on_warning;
@@ -3746,6 +3842,7 @@ int select_insert::send_data(List<Item> &values)
table->auto_increment_field_not_null= FALSE;
DBUG_RETURN(1);
}
+ table->vers_write= versioned_write;
if (table_list) // Not CREATE ... SELECT
{
switch (table_list->view_check_option(thd, info.ignore)) {
@@ -3757,6 +3854,7 @@ int select_insert::send_data(List<Item> &values)
}
error= write_record(thd, table, &info);
+ table->vers_write= table->versioned();
table->auto_increment_field_not_null= FALSE;
if (!error)
@@ -3795,12 +3893,16 @@ int select_insert::send_data(List<Item> &values)
void select_insert::store_values(List<Item> &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()
@@ -4026,10 +4128,7 @@ Field *Item::create_field_for_create_select(TABLE *table)
@retval 0 Error
*/
-static TABLE *create_table_from_items(THD *thd,
- Table_specification_st *create_info,
- TABLE_LIST *create_table,
- Alter_info *alter_info,
+TABLE *select_create::create_table_from_items(THD *thd,
List<Item> *items,
MYSQL_LOCK **lock,
TABLEOP_HOOKS *hooks)
@@ -4090,6 +4189,12 @@ static TABLE *create_table_from_items(THD *thd,
alter_info->create_list.push_back(cr_field, thd->mem_root);
}
+ if (create_info->vers_fix_system_fields(thd, alter_info, *create_table,
+ select_tables, items, &versioned_write))
+ {
+ DBUG_RETURN(NULL);
+ }
+
DEBUG_SYNC(thd,"create_table_select_before_create");
/* Check if LOCK TABLES + CREATE OR REPLACE of existing normal table*/
@@ -4213,8 +4318,9 @@ static TABLE *create_table_from_items(THD *thd,
int
-select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
+select_create::prepare(List<Item> &_values, SELECT_LEX_UNIT *u)
{
+ List<Item> values(_values, thd->mem_root);
MYSQL_LOCK *extra_lock= NULL;
DBUG_ENTER("select_create::prepare");
@@ -4296,10 +4402,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
DEBUG_SYNC(thd,"create_table_select_before_check_if_exists");
- if (!(table= create_table_from_items(thd, create_info,
- create_table,
- alter_info, &values,
- &extra_lock, hook_ptr)))
+ if (!(table= create_table_from_items(thd, &values, &extra_lock, hook_ptr)))
/* abort() deletes table */
DBUG_RETURN(-1);
diff --git a/sql/sql_insert.h b/sql/sql_insert.h
index aea0dac6b0d..6efd680d188 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);
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 c86bdb94bd9..197fe86957c 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);
}
@@ -773,6 +773,8 @@ void LEX::start(THD *thd_arg)
frame_bottom_bound= NULL;
win_spec= NULL;
+ vers_conditions.empty();
+
is_lex_started= TRUE;
DBUG_VOID_RETURN;
}
@@ -1342,6 +1344,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'
@@ -1352,6 +1356,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;
case VALUES:
if (thd->lex->current_select->parsing_place == IN_UPDATE_ON_DUP_KEY ||
thd->lex->current_select->parsing_place == IN_PART_FUNC)
@@ -2247,6 +2272,7 @@ void st_select_lex::init_query()
window_funcs.empty();
tvc= 0;
in_tvc= false;
+ versioned_tables= 0;
}
void st_select_lex::init_select()
@@ -2288,6 +2314,7 @@ void st_select_lex::init_select()
in_funcs.empty();
curr_tvc_name= 0;
in_tvc= false;
+ versioned_tables= 0;
}
/*
@@ -3022,8 +3049,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),
default_used(0), is_lex_started(0), limit_rows_examined_cnt(ULONGLONG_MAX)
{
@@ -3753,6 +3779,7 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds,
DBUG_ENTER("st_select_lex::fix_prepare_information");
if (!thd->stmt_arena->is_conventional() && first_execution)
{
+ Query_arena_stmt on_stmt_arena(thd);
first_execution= 0;
if (group_list.first)
{
@@ -7306,6 +7333,20 @@ 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);
+ thd->lex->sql_command= backup.sql_command;
+}
+
+
+Query_tables_backup::~Query_tables_backup()
+{
+ thd->lex->restore_backup_query_tables_list(&backup);
+}
+
+
bool LEX::sp_add_cfetch(THD *thd, const LEX_CSTRING *name)
{
uint offset;
@@ -7437,3 +7478,26 @@ Item *LEX::make_item_func_replace(THD *thd,
new (thd->mem_root) Item_func_replace_oracle(thd, org, find, replace) :
new (thd->mem_root) Item_func_replace(thd, org, find, replace);
}
+
+
+bool SELECT_LEX::vers_push_field(THD *thd, TABLE_LIST *table, const LEX_CSTRING field_name)
+{
+ DBUG_ASSERT(field_name.str);
+ 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.str, field_name.length))
+ 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 fac06233592..1465465a56c 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -582,6 +582,10 @@ public:
*/
uint8 uncacheable;
enum sub_select_type linkage;
+ bool is_linkage_set() const
+ {
+ return linkage == UNION_TYPE || linkage == INTERSECT_TYPE || linkage == EXCEPT_TYPE;
+ }
bool no_table_names_allowed; /* used for global order by */
static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
@@ -1040,6 +1044,13 @@ public:
table_value_constr *tvc;
bool in_tvc;
+ /** System Versioning */
+public:
+ uint versioned_tables;
+ int vers_setup_conds(THD *thd, TABLE_LIST *tables, COND **where_expr);
+ /* push new Item_field into item_list */
+ bool vers_push_field(THD *thd, TABLE_LIST *table, const LEX_CSTRING field_name);
+
void init_query();
void init_select();
st_select_lex_unit* master_unit() { return (st_select_lex_unit*) master; }
@@ -1974,6 +1985,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.
@@ -2710,7 +2733,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);
@@ -2724,6 +2746,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);
@@ -2982,6 +3005,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());
@@ -3686,6 +3712,11 @@ public:
bool add_grant_command(THD *thd, enum_sql_command sql_command_arg,
stored_procedure_type type_arg);
+
+ Vers_parse_info &vers_get_info()
+ {
+ return create_info.vers_info;
+ }
};
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 137a260adb4..b058af531c6 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -111,6 +111,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,
@@ -3161,6 +3162,11 @@ bool Sql_cmd_call::execute(THD *thd)
if (do_execute_sp(thd, sp))
return true;
+ if (sp->sp_cache_version() == 0)
+ {
+ sp_cache_flush(thd->sp_proc_cache, sp);
+ }
+
/*
Disable slow log for the above call(), if calls are disabled.
Instead we will log the executed statements to the slow log.
@@ -4019,7 +4025,6 @@ mysql_execute_command(THD *thd)
copy.
*/
Alter_info alter_info(lex->alter_info, thd->mem_root);
-
if (thd->is_fatal_error)
{
/* If out of memory when creating a copy of alter_info. */
@@ -4047,6 +4052,7 @@ mysql_execute_command(THD *thd)
*/
if (!(create_info.used_fields & HA_CREATE_USED_ENGINE))
create_info.use_default_db_type(thd);
+
/*
If we are using SET CHARSET without DEFAULT, add an implicit
DEFAULT to not confuse old users. (This may change).
@@ -4233,6 +4239,10 @@ mysql_execute_command(THD *thd)
}
else
{
+ if (create_info.vers_fix_system_fields(thd, &alter_info, *create_table))
+ {
+ 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
@@ -6429,6 +6439,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)
@@ -9389,10 +9414,18 @@ bool update_precheck(THD *thd, TABLE_LIST *tables)
bool delete_precheck(THD *thd, TABLE_LIST *tables)
{
DBUG_ENTER("delete_precheck");
- if (check_one_table_access(thd, DELETE_ACL, tables))
- DBUG_RETURN(TRUE);
- /* Set privilege for the WHERE clause */
- tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
+ if (tables->vers_conditions)
+ {
+ if (check_one_table_access(thd, DELETE_HISTORY_ACL, tables))
+ DBUG_RETURN(TRUE);
+ }
+ else
+ {
+ if (check_one_table_access(thd, DELETE_ACL, tables))
+ DBUG_RETURN(TRUE);
+ /* Set privilege for the WHERE clause */
+ tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
+ }
DBUG_RETURN(FALSE);
}
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 1080f9d9de2..d1da9823aa4 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 <algorithm>
using std::max;
@@ -87,6 +88,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 *);
@@ -1295,6 +1297,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)
@@ -1335,6 +1355,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)
@@ -1607,6 +1631,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.
@@ -1639,6 +1664,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_expression(thd))
+ goto end;
List_iterator<const char> it(part_info->part_field_list);
if (unlikely(handle_list_of_fields(thd, it, table, part_info, FALSE)))
goto end;
@@ -1662,6 +1690,12 @@ 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= "SYSTEM_TIME";
+ if (unlikely(part_info->check_range_constants(thd)))
+ goto end;
+ }
else
{
DBUG_ASSERT(0);
@@ -2182,6 +2216,20 @@ static int add_partition_values(String *str, partition_info *part_info,
} while (++i < num_items);
err+= str->append(')');
}
+ else if (part_info->part_type == VERSIONING_PARTITION)
+ {
+ switch (p_elem->type())
+ {
+ case partition_element::CURRENT:
+ err+= str->append(STRING_WITH_LEN(" CURRENT"));
+ break;
+ case partition_element::HISTORY:
+ err+= str->append(STRING_WITH_LEN(" HISTORY"));
+ break;
+ default:
+ DBUG_ASSERT(0 && "wrong p_elem->type");
+ }
+ }
end:
return err;
}
@@ -2275,13 +2323,32 @@ char *generate_partition_syntax(THD *thd, partition_info *part_info,
else
err+= str.append(STRING_WITH_LEN("HASH "));
break;
+ case VERSIONING_PARTITION:
+ err+= str.append(STRING_WITH_LEN("SYSTEM_TIME "));
+ 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+= str.append(STRING_WITH_LEN("INTERVAL "));
+ err+= str.append_ulonglong(vers_info->interval);
+ err+= str.append(STRING_WITH_LEN(" SECOND "));
+ }
+ if (vers_info->limit)
+ {
+ err+= str.append(STRING_WITH_LEN("LIMIT "));
+ err+= str.append_ulonglong(vers_info->limit);
+ }
+ }
+ else if (part_info->part_expr)
{
err+= str.append('(');
part_info->part_expr->print_for_table_def(&str);
@@ -3088,6 +3155,74 @@ 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");
+ DBUG_ASSERT(part_info);
+ Field *row_end= part_info->part_field_array[STAT_TRX_END];
+ DBUG_ASSERT(row_end);
+ TABLE *table= part_info->table;
+ DBUG_ASSERT(table);
+ Vers_part_info *vers_info= part_info->vers_info;
+ DBUG_ASSERT(vers_info);
+ DBUG_ASSERT(vers_info->initialized());
+ DBUG_ASSERT(row_end->table == table);
+ DBUG_ASSERT(table->versioned());
+ DBUG_ASSERT(table->vers_end_field() == row_end);
+
+ // new rows have NULL in row_end
+ if (row_end->is_max() || row_end->is_null())
+ {
+ *part_id= vers_info->now_part->id;
+ }
+ else // row is historical
+ {
+ THD *thd= current_thd;
+
+ 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);
+ // transaction is not yet pushed to VTQ, so we use now-time
+ ulong sec_part;
+ my_time_t end_ts= row_end->table->versioned(VERS_TRX_ID) ?
+ my_time_t(0) : row_end->get_timestamp(&sec_part);
+ if (part_info->vers_limit_exceed() || part_info->vers_interval_exceed(end_ts))
+ {
+ 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);
+ 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)
@@ -4438,6 +4573,8 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
/* ALTER_ADMIN_PARTITION is handled in mysql_admin_table */
DBUG_ASSERT(!(alter_info->flags & Alter_info::ALTER_ADMIN_PARTITION));
+ partition_info *saved_part_info= NULL;
+
if (alter_info->flags &
(Alter_info::ALTER_ADD_PARTITION |
Alter_info::ALTER_DROP_PARTITION |
@@ -4602,6 +4739,10 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
"LIST", "IN");
}
+ else if (thd->work_part_info->part_type == VERSIONING_PARTITION)
+ {
+ my_error(ER_PARTITION_WRONG_TYPE, MYF(0), "SYSTEM_TIME");
+ }
else
{
DBUG_ASSERT(tab_part_info->part_type == RANGE_PARTITION ||
@@ -4634,6 +4775,16 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
}
if (alter_info->flags & Alter_info::ALTER_ADD_PARTITION)
{
+ if (*fast_alter_table && thd->locked_tables_mode)
+ {
+ MEM_ROOT *old_root= thd->mem_root;
+ thd->mem_root= &thd->locked_tables_list.m_locked_tables_root;
+ saved_part_info= tab_part_info->get_clone(thd);
+ thd->mem_root= old_root;
+ saved_part_info->read_partitions= tab_part_info->read_partitions;
+ saved_part_info->lock_partitions= tab_part_info->lock_partitions;
+ saved_part_info->bitmaps_are_initialized= tab_part_info->bitmaps_are_initialized;
+ }
/*
We start by moving the new partitions to the list of temporary
partitions. We will then check that the new partitions fit in the
@@ -4649,7 +4800,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;
@@ -4854,6 +5006,21 @@ that are reorganised.
partition configuration is made.
*/
{
+ partition_element *now_part= NULL;
+ if (tab_part_info->part_type == VERSIONING_PARTITION)
+ {
+ List_iterator<partition_element> it(tab_part_info->partitions);
+ partition_element *el;
+ while ((el= it++))
+ {
+ if (el->type() == partition_element::CURRENT)
+ {
+ DBUG_ASSERT(tab_part_info->vers_info && el == tab_part_info->vers_info->now_part);
+ it.remove();
+ now_part= el;
+ }
+ }
+ }
List_iterator<partition_element> alt_it(alt_part_info->partitions);
uint part_count= 0;
do
@@ -4868,6 +5035,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.
@@ -4901,16 +5077,28 @@ that are reorganised.
List_iterator<partition_element> 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)
+ {
+ 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;
+ }
}
- 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
{
@@ -4918,6 +5106,13 @@ that are reorganised.
if (is_name_in_list(part_elem->partition_name,
alter_info->partition_names))
{
+ if (tab_part_info->part_type == VERSIONING_PARTITION &&
+ part_elem->type() == partition_element::CURRENT)
+ {
+ 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;
+ }
/*
Set state to indicate that the partition is to be dropped.
*/
@@ -5240,6 +5435,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_expression(thd, alt_part_info->partitions.elements))
+ goto err;
+
if (tab_part_info->check_partition_info(thd, (handlerton**)NULL,
table->file, 0, TRUE))
{
@@ -5278,7 +5479,7 @@ the generated partition syntax in a correct manner.
goto err;
}
}
- }
+ } // ADD, DROP, COALESCE, REORGANIZE, TABLE_REORG, REBUILD
else
{
/*
@@ -5444,6 +5645,8 @@ the generated partition syntax in a correct manner.
DBUG_RETURN(FALSE);
err:
*fast_alter_table= false;
+ if (saved_part_info)
+ table->part_info= saved_part_info;
DBUG_RETURN(TRUE);
}
@@ -6908,6 +7111,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.
@@ -6946,6 +7182,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()
@@ -7092,6 +7383,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)
@@ -7392,7 +7684,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;
@@ -7438,7 +7730,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 */
{
@@ -8141,4 +8433,5 @@ uint get_partition_field_store_length(Field *field)
store_length+= HA_KEY_BLOB_LENGTH;
return store_length;
}
+
#endif
diff --git a/sql/sql_partition.h b/sql/sql_partition.h
index 992229afb05..626ceee3f13 100644
--- a/sql/sql_partition.h
+++ b/sql/sql_partition.h
@@ -41,6 +41,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
@@ -128,6 +129,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,4 +300,30 @@ int __attribute__((warn_unused_result))
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);
+
#endif /* SQL_PARTITION_INCLUDED */
+
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index 61e312646da..31cc6bcdd31 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);
@@ -299,12 +300,23 @@ do_rename(THD *thd, TABLE_LIST *ren_table, const char *new_db,
LEX_CSTRING new_db_name= { 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_alter_history == VERS_ALTER_HISTORY_SURVIVE)
{
+ 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_alter_history == VERS_ALTER_HISTORY_SURVIVE)
+ 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_select.cc b/sql/sql_select.cc
index da09c483668..135e27a3a38 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -54,12 +54,16 @@
#include "sql_statistics.h"
#include "sql_cte.h"
#include "sql_window.h"
+#include "tztime.h"
#include "debug_sync.h" // DEBUG_SYNC
#include <m_ctype.h>
#include <my_bit.h>
#include <hash.h>
#include <ft_global.h>
+#include "sys_vars_shared.h"
+#include "sp_head.h"
+#include "sp_rcontext.h"
/*
A key part number that means we're using a fulltext scan.
@@ -666,6 +670,401 @@ setup_without_group(THD *thd, Ref_ptr_array ref_pointer_array,
DBUG_RETURN(res);
}
+bool vers_select_conds_t::init_from_sysvar(THD *thd)
+{
+ vers_asof_timestamp_t &in= thd->variables.vers_asof_timestamp;
+ type= (vers_system_time_t) in.type;
+ unit_start= VERS_TIMESTAMP;
+ from_query= false;
+ if (type != SYSTEM_TIME_UNSPECIFIED && type != SYSTEM_TIME_ALL)
+ {
+ DBUG_ASSERT(type == SYSTEM_TIME_AS_OF);
+ start= new (thd->mem_root)
+ Item_datetime_literal(thd, &in.ltime, TIME_SECOND_PART_DIGITS);
+ if (!start)
+ return true;
+ }
+ else
+ start= NULL;
+ end= NULL;
+ return false;
+}
+
+inline
+void JOIN::vers_check_items()
+{
+ Item_transformer transformer= &Item::vers_transformer;
+
+ if (conds)
+ {
+ Item *tmp = conds->transform(thd, transformer, NULL);
+ if (conds != tmp)
+ conds= tmp;
+ }
+
+ for (ORDER *ord= order; ord; ord= ord->next)
+ {
+ Item *tmp= (*ord->item)->transform(thd, transformer, NULL);
+ if (*ord->item != tmp)
+ {
+ ord->item_ptr= tmp;
+ *ord->item= ord->item_ptr;
+ }
+ }
+
+ for (ORDER *ord= group_list; ord; ord= ord->next)
+ {
+ Item *tmp= (*ord->item)->transform(thd, transformer, NULL);
+ if (*ord->item != tmp)
+ {
+ ord->item_ptr= tmp;
+ *ord->item= ord->item_ptr;
+ }
+ }
+
+ if (having)
+ {
+ Item *tmp= having->transform(thd, transformer, NULL);
+ if (having != tmp)
+ having= tmp;
+ }
+}
+
+int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables, COND **where_expr)
+{
+ DBUG_ENTER("SELECT_LEX::vers_setup_cond");
+#define newx new (thd->mem_root)
+
+ TABLE_LIST *table;
+
+ 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);
+ }
+
+ if (!versioned_tables)
+ {
+ for (table= tables; table; table= table->next_local)
+ {
+ if (table->table && table->table->versioned())
+ versioned_tables++;
+ else if (table->vers_conditions.user_defined() &&
+ (table->is_non_derived() || !table->vers_conditions.used))
+ {
+ my_error(ER_VERS_NOT_VERSIONED, MYF(0), table->alias);
+ DBUG_RETURN(-1);
+ }
+ }
+ }
+
+ 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. */
+ Query_arena_stmt on_stmt_arena(thd);
+
+ // find outer system_time
+ SELECT_LEX *outer_slex= outer_select();
+ TABLE_LIST* outer_table= NULL;
+
+ if (outer_slex)
+ {
+ TABLE_LIST* derived= master_unit()->derived;
+ // inner SELECT may not be a derived table (derived == NULL)
+ while (derived && outer_slex && !derived->vers_conditions)
+ {
+ derived= outer_slex->master_unit()->derived;
+ outer_slex= outer_slex->outer_select();
+ }
+ if (derived && outer_slex)
+ {
+ DBUG_ASSERT(derived->vers_conditions);
+ outer_table= derived;
+ }
+ }
+
+ COND** dst_cond= where_expr;
+ COND* vers_cond= NULL;
+
+ for (table= tables; table; table= table->next_local)
+ {
+ if (!table->table || !table->table->versioned())
+ continue;
+
+ vers_select_conds_t &vers_conditions= table->vers_conditions;
+
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ /*
+ if the history is stored in partitions, then partitions
+ themselves are not versioned
+ */
+ if (table->partition_names && table->table->part_info->vers_info)
+ {
+ if (vers_conditions)
+ {
+#define PART_VERS_ERR_MSG "%s PARTITION (%s)"
+ char buf[NAME_LEN*2 + sizeof(PART_VERS_ERR_MSG)];
+ my_snprintf(buf, sizeof(buf), PART_VERS_ERR_MSG, table->alias,
+ table->partition_names->head()->c_ptr());
+ my_error(ER_VERS_NOT_VERSIONED, MYF(0), buf);
+ DBUG_RETURN(-1);
+ }
+ else
+ vers_conditions.init(SYSTEM_TIME_ALL);
+ }
+#endif
+
+ if (outer_table && !vers_conditions)
+ {
+ // propagate system_time from nearest outer SELECT_LEX
+ vers_conditions= outer_table->vers_conditions;
+ outer_table->vers_conditions.used= true;
+ }
+
+ // propagate system_time from sysvar
+ if (!vers_conditions)
+ {
+ if (vers_conditions.init_from_sysvar(thd))
+ DBUG_RETURN(-1);
+ }
+
+ if (vers_conditions)
+ {
+ if (vers_conditions == SYSTEM_TIME_ALL)
+ continue;
+
+ lock_type= TL_READ; // ignore TL_WRITE, history is immutable anyway
+ }
+
+ if (table->on_expr)
+ {
+ dst_cond= &table->on_expr;
+ }
+
+ if (TABLE_LIST *t= table->embedding)
+ {
+ if (t->on_expr)
+ dst_cond= &t->on_expr;
+ }
+
+ const LEX_CSTRING *fstart= &table->table->vers_start_field()->field_name;
+ const LEX_CSTRING *fend= &table->table->vers_end_field()->field_name;
+
+ Item *row_start=
+ newx Item_field(thd, &this->context, table->db, table->alias, fstart);
+ Item *row_end=
+ newx Item_field(thd, &this->context, table->db, table->alias, fend);
+
+ bool tmp_from_ib=
+ table->table->s->table_category == TABLE_CATEGORY_TEMPORARY &&
+ table->table->vers_start_field()->type() == MYSQL_TYPE_LONGLONG;
+ bool timestamps_only= table->table->versioned(VERS_TIMESTAMP) && !tmp_from_ib;
+
+ if (vers_conditions)
+ {
+ /* TODO: do resolve fix_length_and_dec(), fix_fields(). This requires
+ storing vers_conditions as Item and make some magic related to
+ vers_system_time_t/VERS_TRX_ID at stage of fix_fields()
+ (this is large refactoring). */
+ vers_conditions.resolve_units(timestamps_only);
+ if (timestamps_only && (vers_conditions.unit_start == VERS_TRX_ID ||
+ vers_conditions.unit_end == VERS_TRX_ID))
+ {
+ my_error(ER_VERS_ENGINE_UNSUPPORTED, MYF(0), table->table_name);
+ DBUG_RETURN(-1);
+ }
+ }
+
+ Item *cond1= 0, *cond2= 0, *curr= 0;
+ // 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 (tmp_from_ib || t->versioned(VERS_TIMESTAMP) ||
+ thd->variables.vers_innodb_algorithm_simple)
+ {
+ if (vers_conditions)
+ {
+ if (vers_conditions.start)
+ {
+ if (!vers_conditions.unit_start)
+ vers_conditions.unit_start= t->s->versioned;
+ switch (vers_conditions.unit_start)
+ {
+ case VERS_TIMESTAMP:
+ {
+ vers_conditions.start= newx Item_datetime_from_unixtime_typecast(
+ thd, vers_conditions.start, 6);
+ break;
+ }
+ case VERS_TRX_ID:
+ {
+ vers_conditions.start= newx Item_longlong_typecast(
+ thd, vers_conditions.start);
+ break;
+ }
+ default:
+ DBUG_ASSERT(0);
+ break;
+ }
+ }
+
+ if (vers_conditions.end)
+ {
+ if (!vers_conditions.unit_end)
+ vers_conditions.unit_end= t->s->versioned;
+ switch (vers_conditions.unit_end)
+ {
+ case VERS_TIMESTAMP:
+ {
+ vers_conditions.end= newx Item_datetime_from_unixtime_typecast(
+ thd, vers_conditions.end, 6);
+ break;
+ }
+ case VERS_TRX_ID:
+ {
+ vers_conditions.end= newx Item_longlong_typecast(
+ thd, vers_conditions.end);
+ break;
+ }
+ default:
+ DBUG_ASSERT(0);
+ break;
+ }
+ }
+ }
+ switch (vers_conditions.type)
+ {
+ case SYSTEM_TIME_UNSPECIFIED:
+ 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);
+ 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
+ {
+ curr= newx Item_int(thd, ULONGLONG_MAX);
+ cond1= newx Item_func_eq(thd, row_end, curr);
+ }
+ break;
+ case SYSTEM_TIME_AS_OF:
+ cond1= newx Item_func_le(thd, row_start,
+ vers_conditions.start);
+ cond2= newx Item_func_gt(thd, row_end,
+ vers_conditions.start);
+ break;
+ case SYSTEM_TIME_FROM_TO:
+ cond1= newx Item_func_lt(thd, row_start,
+ vers_conditions.end);
+ cond2= newx Item_func_ge(thd, row_end,
+ vers_conditions.start);
+ break;
+ case SYSTEM_TIME_BETWEEN:
+ cond1= newx Item_func_le(thd, row_start,
+ vers_conditions.end);
+ cond2= newx Item_func_ge(thd, row_end,
+ vers_conditions.start);
+ break;
+ case SYSTEM_TIME_BEFORE:
+ cond1= newx Item_func_lt(thd, row_end,
+ vers_conditions.start);
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+ }
+ else
+ {
+ DBUG_ASSERT(table->table->s && table->table->s->db_plugin);
+
+ Item *trx_id0, *trx_id1;
+
+ switch (vers_conditions.type)
+ {
+ case SYSTEM_TIME_UNSPECIFIED:
+ curr= newx Item_int(thd, ULONGLONG_MAX);
+ cond1= newx Item_func_eq(thd, row_end, curr);
+ break;
+ case SYSTEM_TIME_AS_OF:
+ trx_id0= vers_conditions.unit_start == VERS_TIMESTAMP ?
+ newx Item_func_vtq_id(thd, vers_conditions.start, TR_table::FLD_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 SYSTEM_TIME_FROM_TO:
+ case SYSTEM_TIME_BETWEEN:
+ trx_id0= vers_conditions.unit_start == VERS_TIMESTAMP ?
+ newx Item_func_vtq_id(thd, vers_conditions.start, TR_table::FLD_TRX_ID, true) :
+ vers_conditions.start;
+ trx_id1= vers_conditions.unit_end == VERS_TIMESTAMP ?
+ newx Item_func_vtq_id(thd, vers_conditions.end, TR_table::FLD_TRX_ID, false) :
+ vers_conditions.end;
+ cond1= vers_conditions.type == 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;
+ case SYSTEM_TIME_BEFORE:
+ trx_id0= vers_conditions.unit_start == VERS_TIMESTAMP ?
+ newx Item_func_vtq_id(thd, vers_conditions.start, TR_table::FLD_TRX_ID) :
+ vers_conditions.start;
+ cond1= newx Item_func_lt(thd, row_end, trx_id0);
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+ }
+
+ if (cond1)
+ {
+ vers_cond= and_items(thd,
+ vers_cond,
+ and_items(thd,
+ cond2,
+ cond1));
+ if (table->is_view_or_derived())
+ vers_cond= or_items(thd, vers_cond, newx Item_func_isnull(thd, row_end));
+ }
+ } // for (table= tables; ...)
+
+ if (vers_cond)
+ {
+ COND *all_cond= and_items(thd, *dst_cond, vers_cond);
+ bool from_where= dst_cond == where_expr;
+ if (on_stmt_arena.arena_replaced())
+ *dst_cond= all_cond;
+ else
+ thd->change_item_tree(dst_cond, all_cond);
+
+ if (from_where)
+ {
+ this->where= *dst_cond;
+ this->where->top_level_item();
+ }
+
+ if (outer_table)
+ outer_table->vers_conditions.type= SYSTEM_TIME_ALL;
+
+ // Invalidate current SP [#52, #422]
+ if (thd->spcont)
+ {
+ DBUG_ASSERT(thd->spcont->m_sp);
+ thd->spcont->m_sp->set_sp_cache_version(0);
+ }
+ }
+
+ DBUG_RETURN(0);
+#undef newx
+}
+
/*****************************************************************************
Check fields, find best join, do the select and output fields.
mysql_select assumes that all tables are already opened
@@ -741,7 +1140,11 @@ JOIN::prepare(TABLE_LIST *tables_init,
{
remove_redundant_subquery_clauses(select_lex);
}
-
+
+ /* System Versioning: handle FOR SYSTEM_TIME clause. */
+ if (select_lex->vers_setup_conds(thd, tables_list, &conds) < 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
@@ -1041,6 +1444,11 @@ 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() && select_lex->versioned_tables > 0)
+ {
+ vers_check_items();
+ }
+
unit= unit_arg;
if (prepare_stage2())
goto err;
@@ -3633,6 +4041,18 @@ void JOIN::exec_inner()
result->send_result_set_metadata(
procedure ? procedure_fields_list : *fields,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
+
+ {
+ List_iterator<Item> it(*columns_list);
+ while (Item *item= it++)
+ {
+ Item_transformer transformer= &Item::vers_transformer;
+ Item *new_item= item->transform(thd, transformer, NULL);
+ if (new_item) // Item_default_value::transform() may return NULL
+ it.replace(new_item);
+ }
+ }
+
error= do_select(this, procedure);
/* Accumulate the counts from all join iterations of all join parts. */
thd->inc_examined_row_count(join_examined_rows);
@@ -14262,6 +14682,8 @@ static COND* substitute_for_best_equal_field(THD *thd, JOIN_TAB *context_tab,
Item_equal *item_equal;
COND *org_cond= cond; // Return this in case of fatal error
+ Query_arena_stmt on_stmt_arena(thd);
+
if (cond->type() == Item::COND_ITEM)
{
List<Item> *cond_list= ((Item_cond*) cond)->argument_list();
@@ -15383,6 +15805,8 @@ optimize_cond(JOIN *join, COND *conds,
THD *thd= join->thd;
DBUG_ENTER("optimize_cond");
+ Query_arena_stmt on_stmt_arena(thd);
+
if (!conds)
{
*cond_value= Item::COND_TRUE;
@@ -16199,7 +16623,11 @@ 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 |
+ VERS_SYS_START_FLAG |
+ VERS_SYS_END_FLAG |
+ VERS_UPDATE_UNVERSIONED_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 ||
@@ -16459,6 +16887,10 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
modify_item ? field :
NULL);
}
+
+ if (field->field->vers_sys_field())
+ result->invisible= field->field->invisible;
+
if (orig_type == Item::REF_ITEM && orig_modify)
((Item_ref*)orig_item)->set_result_field(result);
/*
@@ -18121,6 +18553,12 @@ free_tmp_table(THD *thd, TABLE *entry)
plugin_unlock(0, entry->s->db_plugin);
entry->alias.free();
+ if (entry->pos_in_table_list && entry->pos_in_table_list->table)
+ {
+ DBUG_ASSERT(entry->pos_in_table_list->table == entry);
+ entry->pos_in_table_list->table= NULL;
+ }
+
free_root(&own_root, MYF(0)); /* the table is allocated in its own root */
thd_proc_info(thd, save_proc_info);
@@ -25549,6 +25987,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];
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 0f9b38eb7c8..fbadca2255d 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -1768,6 +1768,7 @@ private:
bool add_having_as_table_cond(JOIN_TAB *tab);
bool make_aggr_tables_info();
+ void vers_check_items();
};
enum enum_with_bush_roots { WITH_BUSH_ROOTS, WITHOUT_BUSH_ROOTS};
@@ -2269,6 +2270,10 @@ inline Item * and_items(THD *thd, Item* cond, Item *item)
{
return (cond ? (new (thd->mem_root) Item_cond_and(thd, cond, item)) : item);
}
+inline Item * or_items(THD *thd, Item* cond, Item *item)
+{
+ return (cond ? (new (thd->mem_root) Item_cond_or(thd, cond, item)) : item);
+}
bool choose_plan(JOIN *join, table_map join_tables);
void optimize_wo_join_buffering(JOIN *join, uint first_tab, uint last_tab,
table_map last_remaining_tables,
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 850383d697c..41cf8556e87 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
{
@@ -591,6 +593,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"},
@@ -1365,6 +1368,15 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
*/
MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
+ TABLE_LIST archive;
+ bool versioned= table_list->vers_conditions;
+ if (versioned)
+ {
+ DBUG_ASSERT(table_list->vers_conditions == SYSTEM_TIME_AS_OF);
+ VTMD_table vtmd(*table_list);
+ if (vtmd.setup_select(thd))
+ goto exit;
+ }
if (mysqld_show_create_get_fields(thd, table_list, &field_list, &buffer))
goto exit;
@@ -1407,6 +1419,13 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
my_eof(thd);
exit:
+ if (versioned)
+ {
+ /* 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);
@@ -1769,6 +1788,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->vers_sys_field() &&
field->unireg_check != Field::NEXT_NUMBER));
def_value->length(0);
@@ -2088,6 +2108,10 @@ 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;
+#ifdef VERS_EXPERIMENTAL
+ ulong vers_show= thd->variables.vers_show;
+#endif
+ bool explicit_fields= false;
bool foreign_db_mode= sql_mode & (MODE_POSTGRESQL | MODE_ORACLE |
MODE_MSSQL | MODE_DB2 |
MODE_MAXDB | MODE_ANSI);
@@ -2127,7 +2151,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
{
@@ -2168,7 +2192,11 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
uint flags = field->flags;
- if (field->field_visibility > USER_DEFINED_INVISIBLE)
+ if (field->invisible > INVISIBLE_USER
+#ifdef VERS_EXPERIMENTAL
+ && !(field->vers_sys_field() && vers_show == VERS_SHOW_ALWAYS)
+#endif
+ )
continue;
if (not_the_first_field)
packet->append(STRING_WITH_LEN(",\n"));
@@ -2215,7 +2243,15 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
}
else
{
- if (flags & NOT_NULL_FLAG)
+ 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"));
+ }
+ else if (flags & NOT_NULL_FLAG)
packet->append(STRING_WITH_LEN(" NOT NULL"));
else if (field->type() == MYSQL_TYPE_TIMESTAMP)
{
@@ -2226,7 +2262,7 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
packet->append(STRING_WITH_LEN(" NULL"));
}
- if (field->field_visibility == USER_DEFINED_INVISIBLE)
+ if (field->invisible == INVISIBLE_USER)
{
packet->append(STRING_WITH_LEN(" INVISIBLE"));
}
@@ -2237,6 +2273,11 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
packet->append(def_value.ptr(), def_value.length(), system_charset_info);
}
+ if (field->vers_update_unversioned())
+ {
+ packet->append(STRING_WITH_LEN(" WITHOUT SYSTEM VERSIONING"));
+ }
+
if (!limited_mysql_mode &&
print_on_update_clause(field, &def_value, false))
{
@@ -2302,6 +2343,14 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
for (uint j=0 ; j < key_info->user_defined_key_parts ; j++,key_part++)
{
+ Field *field= key_part->field;
+ if (field->invisible > INVISIBLE_USER
+#ifdef VERS_EXPERIMENTAL
+ && !(field->vers_sys_field() && vers_show == VERS_SHOW_ALWAYS)
+#endif
+ )
+ continue;
+
if (j)
packet->append(',');
@@ -2330,6 +2379,33 @@ 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();
+ DBUG_ASSERT(fs);
+ DBUG_ASSERT(fe);
+ explicit_fields= fs->invisible < INVISIBLE_SYSTEM;
+ DBUG_ASSERT(!explicit_fields || fe->invisible < INVISIBLE_SYSTEM);
+ if (explicit_fields
+#ifdef VERS_EXPERIMENTAL
+ || vers_show == VERS_SHOW_ALWAYS
+#endif
+ )
+ {
+ packet->append(STRING_WITH_LEN(",\n PERIOD FOR SYSTEM_TIME ("));
+ append_identifier(thd,packet,fs->field_name.str, fs->field_name.length);
+ packet->append(STRING_WITH_LEN(", "));
+ append_identifier(thd,packet,fe->field_name.str, fe->field_name.length);
+ packet->append(STRING_WITH_LEN(")"));
+ }
+ else
+ {
+ DBUG_ASSERT(fs->invisible == INVISIBLE_SYSTEM);
+ DBUG_ASSERT(fe->invisible == INVISIBLE_SYSTEM);
+ }
+ }
+
/*
Get possible foreign key definitions stored in InnoDB and append them
to the CREATE TABLE statement
@@ -2368,6 +2444,13 @@ 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()
+#ifdef VERS_EXPERIMENTAL
+ && (!thd->variables.vers_force || explicit_fields)
+#endif
+ )
+ packet->append(STRING_WITH_LEN(" WITH SYSTEM VERSIONING"));
+
#ifdef WITH_PARTITION_STORAGE_ENGINE
{
if (table->part_info &&
@@ -4299,7 +4382,7 @@ int schema_tables_add(THD *thd, Dynamic_array<LEX_CSTRING*> *files,
@retval 2 Not fatal error; Safe to ignore this file list
*/
-static int
+int
make_table_name_list(THD *thd, Dynamic_array<LEX_CSTRING*> *table_names,
LEX *lex, LOOKUP_FIELD_VALUES *lookup_field_vals,
LEX_CSTRING *db_name)
@@ -4951,6 +5034,64 @@ public:
}
};
+static bool get_all_archive_tables(THD *thd,
+ Dynamic_array<String> &all_archive_tables)
+{
+#ifdef VERS_EXPERIMENTAL
+ if (thd->variables.vers_show == VERS_SHOW_ALWAYS)
+ return false;
+#endif
+
+ if (thd->variables.vers_alter_history != VERS_ALTER_HISTORY_SURVIVE)
+ return false;
+
+ Dynamic_array<LEX_CSTRING *> all_db;
+ LOOKUP_FIELD_VALUES lookup_field_values= {
+ {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_CSTRING 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_CSTRING db_name= *all_db.at(i);
+ Dynamic_array<String> 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<String> &all_archive_tables,
+ const LEX_CSTRING 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
@@ -4993,6 +5134,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<String> all_archive_tables;
MEM_ROOT tmp_mem_root;
DBUG_ENTER("get_all_tables");
@@ -5059,6 +5201,9 @@ 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;
+
/* Use tmp_mem_root to allocate data for opened tables */
init_alloc_root(&tmp_mem_root, SHOW_ALLOC_BLOCK_SIZE, SHOW_ALLOC_BLOCK_SIZE,
MY_THREAD_SPECIFIC);
@@ -5088,6 +5233,9 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
LEX_CSTRING *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))
{
@@ -5311,7 +5459,10 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
else
{
DBUG_ASSERT(share->tmp_table == NO_TMP_TABLE);
- table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs);
+ if (share->versioned)
+ table->field[3]->store(STRING_WITH_LEN("SYSTEM VERSIONED"), cs);
+ else
+ table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs);
}
for (int i= 4; i < 20; i++)
@@ -5722,7 +5873,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
for (; (field= *ptr) ; ptr++)
{
- if(field->field_visibility > USER_DEFINED_INVISIBLE)
+ if(field->invisible > INVISIBLE_USER)
continue;
uchar *pos;
char tmp[MAX_FIELD_WIDTH];
@@ -5800,10 +5951,19 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
else
buf.set(STRING_WITH_LEN("VIRTUAL GENERATED"), cs);
}
+ else if (field->flags & VERS_SYSTEM_FIELD)
+ {
+ if (field->flags & VERS_SYS_START_FLAG)
+ table->field[21]->store(STRING_WITH_LEN("ROW START"), cs);
+ else
+ table->field[21]->store(STRING_WITH_LEN("ROW END"), cs);
+ table->field[21]->set_notnull();
+ table->field[20]->store(STRING_WITH_LEN("ALWAYS"), cs);
+ }
else
table->field[20]->store(STRING_WITH_LEN("NEVER"), cs);
/*Invisible can coexist with auto_increment and virtual */
- if (field->field_visibility == USER_DEFINED_INVISIBLE)
+ if (field->invisible == INVISIBLE_USER)
{
if (buf.length())
buf.append(STRING_WITH_LEN(", "));
@@ -7164,6 +7324,10 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables,
tmp_res.append(STRING_WITH_LEN("HASH"));
table->field[7]->store(tmp_res.ptr(), tmp_res.length(), cs);
break;
+ case VERSIONING_PARTITION:
+ tmp_res.length(0);
+ tmp_res.append(STRING_WITH_LEN("SYSTEM_TIME"));
+ break;
default:
DBUG_ASSERT(0);
my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
@@ -7869,7 +8033,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,
field_name_length,
- fields_info->field_type)))
+ fields_info->field_type,
+ fields_info->field_length)))
DBUG_RETURN(0);
item->decimals= fields_info->field_length;
break;
diff --git a/sql/sql_show.h b/sql/sql_show.h
index dc2fe9738fe..ac13099ca48 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<LEX_CSTRING *> *table_names,
+ LEX *lex, LOOKUP_FIELD_VALUES *lookup_field_vals,
+ LEX_CSTRING *db_name);
/*
INFORMATION_SCHEMA: Execution plan for get_all_tables() call
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index f7a988bb398..58e29ad9b18 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -55,6 +55,9 @@
#include "transaction.h"
#include "sql_audit.h"
#include "sql_sequence.h"
+#include "tztime.h"
+#include "vtmd.h" // System Versioning
+
#ifdef __WIN__
#include <io.h>
@@ -2309,6 +2312,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
const 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: %p s: %p",
table->db, table->table_name, table->table,
@@ -2469,6 +2473,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
@@ -2507,30 +2512,51 @@ 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 (!error)
+ 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)
+ {
+ 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
{
- 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)
+ drop_table:
+ error= ha_delete_table(thd, table_type, path, db, table->table_name,
+ !dont_log_query);
+ if (!error)
{
- /*
- 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;
+ /* 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);
+ }
}
- else
- frm_delete_error= mysql_file_delete(key_file_frm, path,
- MYF(MY_WME));
- if (frm_delete_error)
- frm_delete_error= my_errno;
- else
+ }
+
+ if (!error)
+ {
+ int trigger_drop_error= 0;
+
+ if (!frm_delete_error)
{
non_tmp_table_deleted= TRUE;
trigger_drop_error=
@@ -2543,8 +2569,21 @@ 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)
+ {
+ 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);
+ }
+
if (error)
{
if (wrong_tables.length())
@@ -3038,10 +3077,12 @@ void promote_first_timestamp_column(List<Create_field> *column_definitions)
if (column_definition->is_timestamp_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 & (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 "
@@ -3275,22 +3316,22 @@ bool Column_definition::prepare_stage1_check_typelib_default()
field_list list of all table fields
field_name name/prefix of invisible field
( Prefix in the case when it is
- *COMPLETELY_INVISIBLE*
+ *INVISIBLE_FULL*
and given name is duplicate)
type_handler field data type
- field_visibility
+ invisible
default value
RETURN VALUE
Create_field pointer
*/
int mysql_add_invisible_field(THD *thd, List<Create_field> * field_list,
const char *field_name, Type_handler *type_handler,
- field_visible_type field_visibility, Item* default_value)
+ field_visibility_t invisible, Item* default_value)
{
Create_field *fld= new(thd->mem_root)Create_field();
const char *new_name= NULL;
- /* Get unique field name if field_visibility == COMPLETELY_INVISIBLE */
- if (field_visibility == COMPLETELY_INVISIBLE)
+ /* Get unique field name if invisible == INVISIBLE_FULL */
+ if (invisible == INVISIBLE_FULL)
{
if ((new_name= make_unique_invisible_field_name(thd, field_name,
field_list)))
@@ -3307,7 +3348,7 @@ int mysql_add_invisible_field(THD *thd, List<Create_field> * field_list,
fld->field_name.length= strlen(field_name);
}
fld->set_handler(type_handler);
- fld->field_visibility= field_visibility;
+ fld->invisible= invisible;
if (default_value)
{
Virtual_column_info *v= new (thd->mem_root) Virtual_column_info();
@@ -3380,12 +3421,12 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
DBUG_EXECUTE_IF("test_pseudo_invisible",{
mysql_add_invisible_field(thd, &alter_info->create_list,
- "invisible", &type_handler_long, SYSTEM_INVISIBLE,
+ "invisible", &type_handler_long, INVISIBLE_SYSTEM,
new (thd->mem_root)Item_int(thd, 9));
});
DBUG_EXECUTE_IF("test_completely_invisible",{
mysql_add_invisible_field(thd, &alter_info->create_list,
- "invisible", &type_handler_long, COMPLETELY_INVISIBLE,
+ "invisible", &type_handler_long, INVISIBLE_FULL,
new (thd->mem_root)Item_int(thd, 9));
});
DBUG_EXECUTE_IF("test_invisible_index",{
@@ -3431,6 +3472,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
}
select_field_pos= alter_info->create_list.elements - select_field_count;
+
for (field_no=0; (sql_field=it++) ; field_no++)
{
/*
@@ -3542,7 +3584,9 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
*/
if (sql_field->stored_in_db())
record_offset+= sql_field->pack_length;
- if (sql_field->field_visibility == USER_DEFINED_INVISIBLE &&
+ if (sql_field->flags & VERS_SYSTEM_FIELD)
+ continue;
+ if (sql_field->invisible == INVISIBLE_USER &&
sql_field->flags & NOT_NULL_FLAG &&
sql_field->flags & NO_DEFAULT_VALUE_FLAG)
{
@@ -3562,7 +3606,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
sql_field->offset= record_offset;
record_offset+= sql_field->pack_length;
}
- if (sql_field->field_visibility == NOT_INVISIBLE)
+ if (sql_field->invisible == VISIBLE)
is_all_invisible= false;
}
if (is_all_invisible)
@@ -3820,15 +3864,15 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
&sql_field->field_name))
field++;
/*
- Either field is not present or field visibility is >
- USER_DEFINED_INVISIBLE
+ Either field is not present or field visibility is > INVISIBLE_USER
*/
if (!sql_field)
{
my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.str);
DBUG_RETURN(TRUE);
}
- if (sql_field->field_visibility > USER_DEFINED_INVISIBLE &&
+ if (sql_field->invisible > INVISIBLE_USER &&
+ !(sql_field->flags & VERS_SYSTEM_FIELD) &&
!key->invisible && DBUG_EVALUATE_IF("test_invisible_index", 0, 1))
{
my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.str);
@@ -4402,6 +4446,51 @@ bool Column_definition::sp_prepare_create_field(THD *thd, MEM_ROOT *mem_root)
}
+static bool
+vers_prepare_keys(THD *thd,
+ HA_CREATE_INFO *create_info,
+ Alter_info *alter_info,
+ KEY **key_info,
+ uint key_count)
+{
+ DBUG_ASSERT(create_info->versioned());
+
+ 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.as_row.end;
+ DBUG_ASSERT(row_end_field);
+
+ List_iterator<Key> 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<Key_part_spec> 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
+
+ Key_part_spec *key_part_sys_end_col=
+ new (thd->mem_root) Key_part_spec(&create_info->vers_info.as_row.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,
@@ -4557,7 +4646,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)
{
/*
@@ -4638,6 +4730,13 @@ handler *mysql_create_frm_image(THD *thd,
}
#endif
+ if (create_info->versioned())
+ {
+ if(vers_prepare_keys(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))
@@ -5097,6 +5196,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
{
@@ -5105,6 +5205,20 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
}
}
+ if (create_info->versioned() &&
+ thd->variables.vers_alter_history == VERS_ALTER_HISTORY_SURVIVE)
+ {
+ 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;
+ }
+ }
+
err:
/* In RBR we don't need to log CREATE TEMPORARY TABLE */
if (thd->is_current_stmt_binlog_format_row() && create_info->tmp_table())
@@ -5230,11 +5344,11 @@ static void make_unique_constraint_name(THD *thd, LEX_CSTRING *name,
}
/**
- COMPLETELY_INVISIBLE are internally created. They are completely invisible
+ INVISIBLE_FULL are internally created. They are completely invisible
to Alter command (Opposite of SYSTEM_INVISIBLE which throws an
error when same name column is added by Alter). So in the case of when
- user added a same column name as of COMPLETELY_INVISIBLE , we change
- COMPLETELY_INVISIBLE column name.
+ user added a same column name as of INVISIBLE_FULL , we change
+ INVISIBLE_FULL column name.
*/
static const
char * make_unique_invisible_field_name(THD *thd, const char *field_name,
@@ -5261,6 +5375,66 @@ char * make_unique_invisible_field_name(THD *thd, const char *field_name,
** Alter a table definition
****************************************************************************/
+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 row_end=MAX for rows with row_end=now(6)
+static bool vers_reset_alter_copy(THD *thd, TABLE *table)
+{
+ const MYSQL_TIME query_start= thd->query_start_TIME();
+
+ READ_RECORD info;
+ int error= 0;
+ bool will_batch= false;
+ ha_rows 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()))
+ {
+ MYSQL_TIME current;
+ if (table->vers_end_field()->get_date(&current, 0))
+ goto err_read_record;
+ if (current != query_start)
+ {
+ 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.
@@ -5495,7 +5669,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
local_create_info.max_rows= 0;
/* 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;
/*
@@ -5504,6 +5678,13 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
*/
local_create_info.data_file_name= local_create_info.index_file_name= NULL;
+ if (src_table->table->versioned() &&
+ local_create_info.vers_info.fix_create_like(local_alter_info, local_create_info,
+ *src_table, *table))
+ {
+ goto err;
+ }
+
/* The following is needed only in case of lock tables */
if ((local_create_info.table= thd->lex->query_tables->table))
pos_in_locked_tables= local_create_info.table->pos_in_locked_tables;
@@ -6380,6 +6561,14 @@ 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 (alter_info->flags & Alter_info::ALTER_COLUMN_UNVERSIONED)
+ ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_COLUMN_UNVERSIONED;
+ if (alter_info->flags & Alter_info::ALTER_ADD_SYSTEM_VERSIONING)
+ ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_ADD_SYSTEM_VERSIONING;
+ if (alter_info->flags & Alter_info::ALTER_DROP_SYSTEM_VERSIONING)
+ ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_DROP_SYSTEM_VERSIONING;
/*
If we altering table with old VARCHAR fields we will be automatically
@@ -7412,11 +7601,34 @@ static bool mysql_inplace_alter_table(THD *thd,
DEBUG_SYNC(thd, "alter_table_inplace_before_commit");
THD_STAGE_INFO(thd, stage_alter_inplace_commit);
- if (table->file->ha_commit_inplace_alter_table(altered_table,
- ha_alter_info,
- true))
{
- goto rollback;
+ TR_table trt(thd, true);
+ if (trt != *table_list && table->file->ht->prepare_commit_versioned)
+ {
+ ulonglong trx_start_id= 0;
+ ulonglong trx_end_id= table->file->ht->prepare_commit_versioned(thd, &trx_start_id);
+ if (trx_end_id)
+ {
+ if (!use_transaction_registry)
+ {
+ my_error(ER_VERS_TRT_IS_DISABLED, MYF(0));
+ goto rollback;
+ }
+ if (trt.update(trx_start_id, trx_end_id))
+ {
+ goto rollback;
+ }
+ }
+ }
+
+ if (table->file->ha_commit_inplace_alter_table(altered_table,
+ ha_alter_info,
+ true))
+ {
+ goto rollback;
+ }
+
+ thd->drop_temporary_table(altered_table, NULL, false);
}
close_all_tables_for_name(thd, table->s,
@@ -7426,8 +7638,6 @@ static bool mysql_inplace_alter_table(THD *thd,
NULL);
table_list->table= table= NULL;
- thd->drop_temporary_table(altered_table, NULL, false);
-
/*
Replace the old .FRM with the new .FRM, but keep the old name for now.
Rename to the new name (if needed) will be handled separately below.
@@ -7684,7 +7894,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
bitmap_clear_all(&table->tmp_set);
for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
{
- if (field->field_visibility == COMPLETELY_INVISIBLE)
+ if (field->invisible == INVISIBLE_FULL)
continue;
Alter_drop *drop;
if (field->type() == MYSQL_TYPE_VARCHAR)
@@ -7697,7 +7907,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
!my_strcasecmp(system_charset_info,field->field_name.str, drop->name))
break;
}
- if (drop && field->field_visibility < SYSTEM_INVISIBLE)
+ if (drop && (field->invisible < INVISIBLE_SYSTEM || field->vers_sys_field()))
{
/* Reset auto_increment value if it was dropped */
if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER &&
@@ -7722,7 +7932,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
&def->change))
break;
}
- if (def && field->field_visibility < SYSTEM_INVISIBLE)
+ if (def && (field->invisible < INVISIBLE_SYSTEM || field->vers_sys_field()))
{ // Field is changed
def->field=field;
/*
@@ -8155,6 +8365,13 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
}
}
+ if (table->versioned() && !(alter_info->flags & Alter_info::ALTER_DROP_SYSTEM_VERSIONING) &&
+ new_create_list.elements == VERSIONING_FIELDS)
+ {
+ my_error(ER_VERS_TABLE_MUST_HAVE_COLUMNS, MYF(0), table->s->table_name.str);
+ goto err;
+ }
+
if (!create_info->comment.str)
{
create_info->comment.str= table->s->comment.str;
@@ -8648,18 +8865,30 @@ 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_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,
+ alter_ctx->table_name,
+ alter_ctx->new_db,
+ alter_ctx->new_alias))
+ {
+ 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,
+ alter_ctx->new_db, alter_ctx->new_alias,
+ alter_ctx->db, alter_ctx->table_name,
+ NO_FK_CHECKS);
+ error= -1;
+ }
}
}
@@ -8791,6 +9020,56 @@ bool mysql_alter_table(THD *thd, const char *new_db, const char *new_name,
&alter_prelocking_strategy);
thd->open_options&= ~HA_OPEN_FOR_ALTER;
+ TABLE *table= table_list->table;
+ bool versioned= table && table->versioned();
+ bool vers_survival_mod= false;
+
+ if (versioned)
+ {
+ if (handlerton *hton1= create_info->db_type)
+ {
+ handlerton *hton2= table->file->partition_ht();
+ if (hton1 != hton2 &&
+ (ha_check_storage_engine_flag(hton1, HTON_NATIVE_SYS_VERSIONING) ||
+ ha_check_storage_engine_flag(hton2, HTON_NATIVE_SYS_VERSIONING)))
+ {
+ my_error(ER_VERS_ALTER_ENGINE_PROHIBITED, MYF(0), table_list->db,
+ table_list->table_name);
+ DBUG_RETURN(true);
+ }
+ }
+ bool vers_data_mod= alter_info->data_modifying();
+ if (thd->variables.vers_alter_history == VERS_ALTER_HISTORY_SURVIVE)
+ {
+ vers_survival_mod= alter_info->data_modifying() || alter_info->partition_modifying();
+ }
+ else if (vers_data_mod && thd->variables.vers_alter_history == VERS_ALTER_HISTORY_ERROR)
+ {
+ my_error(ER_VERS_ALTER_NOT_ALLOWED, MYF(0), table_list->db, table_list->table_name);
+ DBUG_RETURN(true);
+ }
+ }
+
+ if (vers_survival_mod)
+ {
+ 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(VERS_TRX_ID) &&
+ 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");
#ifdef WITH_WSREP
@@ -8807,7 +9086,6 @@ bool mysql_alter_table(THD *thd, const char *new_db, const char *new_name,
if (error)
DBUG_RETURN(true);
- TABLE *table= table_list->table;
table->use_all_columns();
MDL_ticket *mdl_ticket= table->mdl_ticket;
@@ -8918,6 +9196,11 @@ bool mysql_alter_table(THD *thd, const char *new_db, const 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.fix_alter_info(thd, alter_info, create_info, table))
+ {
+ DBUG_RETURN(true);
+ }
+
if ((create_info->db_type != table->s->db_type() ||
alter_info->flags & Alter_info::ALTER_PARTITION) &&
!table->file->can_switch_engines())
@@ -9096,9 +9379,11 @@ bool mysql_alter_table(THD *thd, const char *new_db, const 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 ((!vers_survival_mod &&
+ 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);
}
@@ -9160,6 +9445,7 @@ bool mysql_alter_table(THD *thd, const char *new_db, const 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;
/*
@@ -9499,6 +9785,8 @@ bool mysql_alter_table(THD *thd, const char *new_db, const char *new_name,
}
if (!new_table)
goto err_new_table_cleanup;
+ new_table->s->orig_table_name= table->s->table_name.str;
+ 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.
@@ -9525,7 +9813,14 @@ bool mysql_alter_table(THD *thd, const char *new_db, const char *new_name,
order_num, order, &copied, &deleted,
alter_info->keys_onoff,
&alter_ctx))
+ {
+ if (vers_survival_mod && new_versioned && table->versioned(VERS_TIMESTAMP))
+ {
+ // Failure of this function may result in corruption of an original table.
+ vers_reset_alter_copy(thd, table);
+ }
goto err_new_table_cleanup;
+ }
}
else
{
@@ -9620,9 +9915,14 @@ bool mysql_alter_table(THD *thd, const char *new_db, const 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, (long) thd->thread_id);
+ char backup_name[FN_LEN];
+ if (vers_survival_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",
+ 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,
@@ -9650,6 +9950,17 @@ bool mysql_alter_table(THD *thd, const char *new_db, const char *new_name,
goto err_with_mdl;
}
+ if (vers_survival_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())
{
@@ -9660,6 +9971,7 @@ bool mysql_alter_table(THD *thd, const char *new_db, const 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);
@@ -9674,7 +9986,8 @@ bool mysql_alter_table(THD *thd, const char *new_db, const 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 (!(vers_survival_mod && new_versioned) &&
+ 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
@@ -9861,6 +10174,11 @@ 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();
+ bool keep_versioned= from->versioned() && to->versioned();
+ Field *to_row_start= NULL, *to_row_end= NULL, *from_row_end= NULL;
+ MYSQL_TIME query_start;
DBUG_ENTER("copy_data_between_tables");
/* Two or 3 stages; Sorting, copying data and update indexes */
@@ -9961,6 +10279,29 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
thd_progress_next_stage(thd);
}
+ if (make_versioned)
+ {
+ query_start= thd->query_start_TIME();
+ to_row_start= to->vers_start_field();
+ to_row_end= to->vers_end_field();
+ }
+ else if (make_unversioned)
+ {
+ from_row_end= from->vers_end_field();
+ }
+ else if (keep_versioned)
+ {
+ if (thd->variables.vers_alter_history == VERS_ALTER_HISTORY_SURVIVE)
+ {
+ query_start= thd->query_start_TIME();
+ from_row_end= from->vers_end_field();
+ to_row_start= to->vers_start_field();
+ } else if (thd->variables.vers_alter_history == VERS_ALTER_HISTORY_DROP)
+ {
+ from_row_end= from->vers_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();
@@ -10014,6 +10355,36 @@ 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_row_end && !from_row_end->is_max())
+ {
+ continue;
+ }
+
+ if (make_versioned)
+ {
+ to_row_start->set_notnull();
+ to_row_start->store_time(&query_start);
+ to_row_end->set_max();
+ }
+ else if (make_unversioned)
+ {
+ if (!from_row_end->is_max())
+ continue; // Drop history rows.
+ }
+ else if (keep_versioned &&
+ thd->variables.vers_alter_history == VERS_ALTER_HISTORY_SURVIVE)
+ {
+ if (!from_row_end->is_max())
+ continue; // Do not copy history rows.
+
+ store_record(from, record[1]);
+ from->vers_end_field()->store_time(&query_start);
+ from->file->ha_update_row(from->record[1], from->record[0]);
+ to_row_start->store_time(&query_start);
+ }
+
prev_insert_id= to->file->next_insert_id;
if (to->default_field)
to->update_default_fields(0, ignore);
@@ -10028,7 +10399,12 @@ 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(VERS_TRX_ID) &&
+ thd->variables.vers_alter_history != VERS_ALTER_HISTORY_SURVIVE)
+ {
+ to->vers_write= false;
+ }
+ error= to->file->ha_write_row(to->record[0]);
to->auto_increment_field_not_null= FALSE;
if (error)
{
diff --git a/sql/sql_time.cc b/sql/sql_time.cc
index 309ede45ecc..276540e9dba 100644
--- a/sql/sql_time.cc
+++ b/sql/sql_time.cc
@@ -475,6 +475,7 @@ void localtime_to_TIME(MYSQL_TIME *to, struct tm *from)
to->second= (int) from->tm_sec;
}
+
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 1832e4501ed..28a2e2f50d2 100644
--- a/sql/sql_time.h
+++ b/sql/sql_time.h
@@ -170,6 +170,7 @@ 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 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/sql_trigger.cc b/sql/sql_trigger.cc
index be85fb892b0..8a1cc1ada7a 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -1251,7 +1251,9 @@ bool Table_triggers_list::prepare_record_accessors(TABLE *table)
bzero(extra_null_bitmap, null_bytes);
}
else
+ {
record0_field= table->field;
+ }
if (has_triggers(TRG_EVENT_UPDATE,TRG_ACTION_BEFORE) ||
has_triggers(TRG_EVENT_UPDATE,TRG_ACTION_AFTER) ||
diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h
index 8847680c7b2..6c02afdb89c 100644
--- a/sql/sql_trigger.h
+++ b/sql/sql_trigger.h
@@ -307,13 +307,6 @@ private:
}
};
-inline Field **TABLE::field_to_fill()
-{
- return triggers && triggers->nullable_fields() ? triggers->nullable_fields()
- : field;
-}
-
-
bool add_table_for_trigger(THD *thd,
const sp_name *trg_name,
bool continue_if_not_exist,
diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc
index 1d6edbc5fc9..bd3f1fdc111 100644
--- a/sql/sql_truncate.cc
+++ b/sql/sql_truncate.cc
@@ -27,7 +27,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.
@@ -481,7 +482,6 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref)
DBUG_RETURN(error);
}
-
/**
Execute a TRUNCATE statement at runtime.
@@ -493,13 +493,13 @@ 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");
- 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_tvc.cc b/sql/sql_tvc.cc
index 79e894f5a7f..56a6ae58a77 100644
--- a/sql/sql_tvc.cc
+++ b/sql/sql_tvc.cc
@@ -241,7 +241,7 @@ bool table_value_constr::prepare(THD *thd, SELECT_LEX *sl,
/* Error's in 'new' will be detected after loop */
Item_type_holder *new_holder= new (thd->mem_root)
Item_type_holder(thd,
- &item->name,
+ item,
holders[pos].type_handler(),
&holders[pos]/*Type_all_attributes*/,
holders[pos].get_maybe_null());
diff --git a/sql/sql_type.cc b/sql/sql_type.cc
index e84bdb1455d..e1fb9cb51a0 100644
--- a/sql/sql_type.cc
+++ b/sql/sql_type.cc
@@ -32,6 +32,7 @@ Type_handler_long type_handler_long;
Type_handler_int24 type_handler_int24;
Type_handler_longlong type_handler_longlong;
Type_handler_longlong type_handler_ulonglong; // Only used for CAST() for now
+Type_handler_vers_trx_id type_handler_vers_trx_id;
Type_handler_float type_handler_float;
Type_handler_double type_handler_double;
Type_handler_bit type_handler_bit;
@@ -658,7 +659,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;
@@ -2063,6 +2066,19 @@ Field *Type_handler_longlong::make_table_field(const LEX_CSTRING *name,
}
+Field *Type_handler_vers_trx_id::make_table_field(const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE *table) const
+{
+ return new (table->in_use->mem_root)
+ Field_vers_trx_id(addr.ptr, attr.max_char_length(),
+ addr.null_ptr, addr.null_bit,
+ Field::NONE, name,
+ 0/*zerofill*/, attr.unsigned_flag);
+}
+
+
Field *Type_handler_float::make_table_field(const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
@@ -4431,6 +4447,14 @@ bool Type_handler::
}
+bool Type_handler::
+ Item_longlong_typecast_fix_length_and_dec(Item_longlong_typecast *item) const
+{
+ item->fix_length_and_dec_generic();
+ return false;
+}
+
+
#ifdef HAVE_SPATIAL
bool Type_handler_geometry::
diff --git a/sql/sql_type.h b/sql/sql_type.h
index 427d59718f6..ac95c5a9c88 100644
--- a/sql/sql_type.h
+++ b/sql/sql_type.h
@@ -55,6 +55,7 @@ class Item_char_typecast;
class Item_time_typecast;
class Item_date_typecast;
class Item_datetime_typecast;
+class Item_longlong_typecast;
class Item_func_plus;
class Item_func_minus;
class Item_func_mul;
@@ -983,6 +984,8 @@ public:
Item_date_typecast_fix_length_and_dec(Item_date_typecast *item) const;
virtual bool
Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *item) const;
+ virtual bool
+ Item_longlong_typecast_fix_length_and_dec(Item_longlong_typecast *item) const;
virtual bool
Item_func_plus_fix_length_and_dec(Item_func_plus *func) const= 0;
@@ -1891,6 +1894,17 @@ public:
};
+class Type_handler_vers_trx_id: public Type_handler_longlong
+{
+public:
+ virtual ~Type_handler_vers_trx_id() {}
+ Field *make_table_field(const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE *table) const;
+};
+
+
class Type_handler_int24: public Type_handler_general_purpose_int
{
static const Name m_name_mediumint;
@@ -2844,14 +2858,16 @@ public:
class Type_handler_hybrid_field_type
{
const Type_handler *m_type_handler;
+ bool m_vers_trx_id;
bool aggregate_for_min_max(const Type_handler *other);
+
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(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)
{ }
void swap(Type_handler_hybrid_field_type &other)
{
@@ -2940,6 +2956,7 @@ extern MYSQL_PLUGIN_IMPORT Type_handler_int24 type_handler_int24;
extern MYSQL_PLUGIN_IMPORT Type_handler_long type_handler_long;
extern MYSQL_PLUGIN_IMPORT Type_handler_longlong type_handler_longlong;
extern MYSQL_PLUGIN_IMPORT Type_handler_longlong type_handler_ulonglong;
+extern MYSQL_PLUGIN_IMPORT Type_handler_vers_trx_id type_handler_vers_trx_id;
extern MYSQL_PLUGIN_IMPORT Type_handler_newdecimal type_handler_newdecimal;
extern MYSQL_PLUGIN_IMPORT Type_handler_olddecimal type_handler_olddecimal;
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 3a96e958f56..82745b61929 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -803,7 +803,7 @@ bool st_select_lex_unit::join_union_item_types(THD *thd_arg,
/* Error's in 'new' will be detected after loop */
types.push_back(new (thd_arg->mem_root)
Item_type_holder(thd_arg,
- &item_tmp->name,
+ item_tmp,
holders[pos].type_handler(),
&holders[pos]/*Type_all_attributes*/,
holders[pos].get_maybe_null()));
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 0b6564d8e49..7b4938fc8c4 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*).
@@ -152,6 +155,23 @@ static bool check_fields(THD *thd, List<Item> &items)
return FALSE;
}
+static bool check_has_vers_fields(TABLE *table, List<Item> &items)
+{
+ List_iterator<Item> it(items);
+ if (!table->versioned())
+ return false;
+
+ while (Item *item= it++)
+ {
+ if (Item_field *item_field= item->field_for_view_update())
+ {
+ Field *field= item_field->field;
+ if (field->table == table && !field->vers_update_unversioned())
+ return true;
+ }
+ }
+ return false;
+}
/**
Re-read record if more columns are needed for error message.
@@ -283,6 +303,10 @@ int mysql_update(THD *thd,
TABLE_LIST *update_source_table;
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);
@@ -353,12 +377,16 @@ int mysql_update(THD *thd,
{
DBUG_RETURN(1);
}
+ bool has_vers_fields= check_has_vers_fields(table, fields);
if (check_key_in_view(thd, table_list))
{
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "UPDATE");
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=
@@ -808,6 +836,11 @@ update_begin:
THD_STAGE_INFO(thd, stage_updating);
while (!(error=info.read_record()) && !thd->killed)
{
+ if (table->versioned() && !table->vers_end_field()->is_max())
+ {
+ continue;
+ }
+
explain->tracker.on_record_read();
thd->inc_examined_row_count(1);
if (!select || select->skip_record(thd) > 0)
@@ -817,6 +850,7 @@ update_begin:
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 */
@@ -880,19 +914,35 @@ update_begin:
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 (has_vers_fields && table->versioned())
+ {
+ if (table->versioned(VERS_TIMESTAMP))
+ {
+ 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 ||
table->file->is_fatal_error(error, HA_CHECK_ALL))
- {
+ {
/*
If (ignore && error is ignorable) we don't have to
do anything; otherwise...
@@ -1065,6 +1115,9 @@ update_end:
else
errcode= query_error_code(thd, killed_status == NOT_KILLED);
+ ScopedStatementReplication scoped_stmt_rpl(
+ table->versioned(VERS_TRX_ID) ? thd : NULL);
+
if (thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query(), thd->query_length(),
transactional_table, FALSE, FALSE, errcode))
@@ -1089,9 +1142,15 @@ update_end:
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(VERS_TIMESTAMP))
+ 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));
@@ -1700,8 +1759,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)
+{
+}
/*
@@ -1952,7 +2013,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;
@@ -2005,6 +2066,7 @@ multi_update::initialize_tables(JOIN *join)
if (safe_update_on_fly(thd, join->join_tab, table_ref, all_tables))
{
table_to_update= table; // Update table on the fly
+ has_vers_fields= check_has_vers_fields(table, *fields);
continue;
}
}
@@ -2177,6 +2239,11 @@ int multi_update::send_data(List<Item> &not_used_values)
if (table->status & (STATUS_NULL_ROW | STATUS_UPDATED))
continue;
+ if (table->versioned() && !table->vers_end_field()->is_max())
+ {
+ continue;
+ }
+
if (table == table_to_update)
{
/*
@@ -2189,6 +2256,7 @@ int multi_update::send_data(List<Item> &not_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,
@@ -2254,6 +2322,21 @@ int multi_update::send_data(List<Item> &not_used_values)
error= 0;
updated--;
}
+ else if (has_vers_fields && table->versioned())
+ {
+ if (table->versioned(VERS_TIMESTAMP))
+ {
+ 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 */
if (table->file->has_transactions())
@@ -2280,6 +2363,7 @@ int multi_update::send_data(List<Item> &not_used_values)
*/
uint field_num= 0;
List_iterator_fast<TABLE> tbl_it(unupdated_check_opt_tables);
+ /* Set first tbl = table and then tbl to tables from tbl_it */
TABLE *tbl= table;
do
{
@@ -2342,10 +2426,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();
}
}
@@ -2437,6 +2517,8 @@ int multi_update::do_updates()
if (table->vfield)
empty_record(table);
+ has_vers_fields= check_has_vers_fields(table, *fields);
+
check_opt_it.rewind();
while(TABLE *tbl= check_opt_it++)
{
@@ -2547,19 +2629,40 @@ int multi_update::do_updates()
goto err2;
}
}
- if ((local_error=table->file->ha_update_row(table->record[1],
- table->record[0])) &&
+ if (has_vers_fields && table->versioned())
+ table->vers_update_fields();
+
+ 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 (has_vers_fields && table->versioned())
+ {
+ if (table->versioned(VERS_TIMESTAMP))
+ {
+ 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
local_error= 0;
}
@@ -2675,9 +2778,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(VERS_TRX_ID))
+ {
+ 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
}
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index b2be437965e..c36c1fa2a93 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -607,14 +607,22 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
view->table_name, item->name.str) &
VIEW_ANY_ACL);
- if (fld && !fld->field->table->s->tmp_table)
+ if (!fld)
+ continue;
+ TABLE_SHARE *s= fld->field->table->s;
+ const LString_i field_name= fld->field->field_name;
+ if (s->tmp_table ||
+ (s->versioned &&
+ (field_name == s->vers_start_field()->field_name ||
+ 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;
}
}
@@ -2017,7 +2025,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<Item> *list, TABLE_LIST *view)
@@ -2034,7 +2042,15 @@ bool insert_view_fields(THD *thd, List<Item> *list, TABLE_LIST *view)
{
Item_field *fld;
if ((fld= entry->item->field_for_view_update()))
+ {
+ TABLE_SHARE *s= fld->context->table_list->table->s;
+ LString_i field_name= fld->field_name;
+ if (s->versioned &&
+ (field_name == s->vers_start_field()->field_name ||
+ field_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");
@@ -2045,7 +2061,7 @@ bool insert_view_fields(THD *thd, List<Item> *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 63194e9d097..5dd5493203e 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -68,6 +68,7 @@
#include "sql_lex.h"
#include "sql_sequence.h"
#include "sql_tvc.h"
+#include "vers_utils.h"
/* this is to get the bison compilation windows warnings out */
#ifdef _MSC_VER
@@ -738,6 +739,28 @@ bool LEX::set_bincmp(CHARSET_INFO *cs, bool bin)
MYSQL_YYABORT; \
} while(0)
+
+void vers_select_conds_t::init(vers_system_time_t t, vers_sys_type_t u_start,
+ Item *s, vers_sys_type_t u_end, Item *e)
+{
+ type= t;
+ unit_start= u_start;
+ unit_end= u_end;
+ start= fix_dec(s);
+ end= fix_dec(e);
+ used= from_query= false;
+}
+
+Item *vers_select_conds_t::fix_dec(Item *item)
+{
+ if (item && item->decimals == 0 && item->type() == Item::FUNC_ITEM &&
+ ((Item_func*)item)->functype() == Item_func::NOW_FUNC)
+ item->decimals= 6;
+
+ return item;
+}
+
+
Virtual_column_info *add_virtual_expression(THD *thd, Item *expr)
{
Virtual_column_info *v= new (thd->mem_root) Virtual_column_info();
@@ -857,6 +880,8 @@ 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_sys_type_t vers_range_unit;
+ enum Column_definition::enum_column_versioning vers_column_versioning;
}
%{
@@ -867,15 +892,16 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%parse-param { THD *thd }
%lex-param { THD *thd }
/*
- Currently there are 104 shift/reduce conflicts.
+ Currently there are 123 shift/reduce conflicts.
We should not introduce new conflicts any more.
*/
-%expect 104
+%expect 123
/*
Comments for TOKENS.
For each token, please include in the same line a comment that contains
the following tags:
+ SQL-2011-R : Reserved keyword as per SQL-2011
SQL-2011-N : Non Reserved keyword as per SQL-2011
SQL-2003-R : Reserved keyword as per SQL-2003
SQL-2003-N : Non Reserved keyword as per SQL-2003
@@ -1100,6 +1126,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
@@ -1129,7 +1156,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token HEX_NUM
%token HEX_STRING
%token HIGH_PRIORITY
-%token INVISIBLE_SYM
+%token HISTORY_SYM /* MYSQL */
%token HOST_SYM
%token HOSTS_SYM
%token HOUR_MICROSECOND_SYM
@@ -1170,6 +1197,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token ISOPEN_SYM /* Oracle-N */
%token ISSUER_SYM
%token ITERATE_SYM
+%token INVISIBLE_SYM
%token JOIN_SYM /* SQL-2003-R */
%token JSON_SYM
%token KEYS
@@ -1334,6 +1362,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token PERCENT_RANK_SYM
%token PERCENTILE_CONT_SYM
%token PERCENTILE_DISC_SYM
+%token PERIOD_SYM /* SQL-2011-R */
%token PERSISTENT_SYM
%token PHASE_SYM
%token PLUGINS_SYM
@@ -1500,6 +1529,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token SWAPS_SYM
%token SWITCHES_SYM
%token SYSDATE
+%token SYSTEM /* SQL-2011-R */
+%token SYSTEM_TIME_SYM /* SQL-2011-R */
%token TABLES
%token TABLESPACE
%token TABLE_REF_PRIORITY
@@ -1570,6 +1601,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 /* SQL-2011-R */
%token VIA_SYM
%token VIEW_SYM /* SQL-2003-N */
%token VIRTUAL_SYM
@@ -1583,8 +1615,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token WHILE_SYM
%token WITH /* SQL-2003-R */
%token WITHIN
+%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 */
@@ -1690,7 +1724,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
optional_flush_tables_arguments
opt_time_precision kill_type kill_option int_num
opt_default_time_precision
- case_stmt_body opt_bin_mod
+ case_stmt_body opt_bin_mod opt_for_system_time_clause
opt_if_exists_table_element opt_if_not_exists_table_element
opt_recursive opt_format_xid
@@ -1920,6 +1954,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
@@ -1928,6 +1963,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
explainable_command
opt_lock_wait_timeout
opt_delete_gtid_domain
+ asrow_attribute
END_OF_INPUT
%type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt
@@ -1948,6 +1984,7 @@ END_OF_INPUT
%type <num> sp_decl_idents sp_decl_idents_init_vars
%type <num> sp_handler_type sp_hcond_list
+%type <num> start_or_end
%type <spcondvalue> sp_cond sp_hcond sqlstate signal_value opt_signal_value
%type <spblock> sp_decls sp_decl sp_decl_body sp_decl_variable_list
%type <spname> sp_name
@@ -1985,7 +2022,6 @@ END_OF_INPUT
%type <frame_exclusion> opt_window_frame_exclusion;
%type <window_frame_bound> window_frame_start window_frame_bound;
-
%type <NONE>
'-' '+' '*' '/' '%' '(' ')'
',' '!' '{' '}' '&' '|' AND_SYM OR_SYM OR_OR_SYM BETWEEN_SYM CASE_SYM
@@ -1998,6 +2034,8 @@ END_OF_INPUT
%type <lex_str_list> opt_with_column_list
+%type <vers_range_unit> opt_trans_or_timestamp
+%type <vers_column_versioning> with_or_without_system
%%
@@ -4997,7 +5035,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:
@@ -5144,6 +5182,10 @@ part_type_def:
}
| 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:
@@ -5351,6 +5393,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;
@@ -5383,6 +5426,9 @@ opt_part_values:
{
if (part_info->error_if_requires_values())
MYSQL_YYABORT;
+ if (part_info->part_type == VERSIONING_PARTITION)
+ my_yyabort_error((ER_VERS_WRONG_PARTS, MYF(0),
+ lex->create_last_non_select_table->table_name));
}
else
part_info->part_type= HASH_PARTITION;
@@ -5415,6 +5461,60 @@ opt_part_values:
part_info->part_type= LIST_PARTITION;
}
part_values_in {}
+ | CURRENT_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)
+ my_yyabort_error((ER_PARTITION_WRONG_TYPE, MYF(0), "SYSTEM_TIME"));
+ }
+ 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_PARTS, MYF(0),
+ Lex->create_last_non_select_table->table_name));
+ }
+ elem->type(partition_element::CURRENT);
+ DBUG_ASSERT(part_info->vers_info);
+ part_info->vers_info->now_part= elem;
+ if (part_info->init_column_part(thd))
+ {
+ MYSQL_YYABORT;
+ }
+ }
+ | HISTORY_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)
+ my_yyabort_error((ER_PARTITION_WRONG_TYPE, MYF(0), "SYSTEM_TIME"));
+ }
+ else
+ {
+ part_info->vers_init_info(thd);
+ elem->id= UINT32_MAX;
+ }
+ DBUG_ASSERT(part_info->vers_info);
+ if (part_info->vers_info->now_part)
+ {
+ 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::HISTORY);
+ if (part_info->init_column_part(thd))
+ {
+ MYSQL_YYABORT;
+ }
+ }
| DEFAULT
{
LEX *lex= Lex;
@@ -5660,6 +5760,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;
@@ -5716,6 +5817,38 @@ 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) ||
+ part_info->vers_set_interval(interval))
+ {
+ my_error(ER_PART_WRONG_VALUE, MYF(0),
+ Lex->create_last_non_select_table->table_name, "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))
+ {
+ my_error(ER_PART_WRONG_VALUE, MYF(0),
+ Lex->create_last_non_select_table->table_name, "LIMIT");
+ MYSQL_YYABORT;
+ }
+ }
+ ;
+
/*
End of partition parser part
*/
@@ -6082,6 +6215,33 @@ create_table_option:
{
Lex->create_info.used_fields|= HA_CREATE_USED_SEQUENCE;
Lex->create_info.sequence= ($3 == HA_CHOICE_YES);
+ }
+ | versioning_option
+ ;
+
+opt_versioning_option:
+ /* empty */
+ | versioning_option
+ ;
+
+versioning_option:
+ WITH_SYSTEM_SYM VERSIONING_SYM
+ {
+ if (Lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)
+ {
+#ifdef VERS_EXPERIMENTAL
+ if (!thd->variables.vers_force)
+#endif
+ {
+ my_error(ER_VERS_TEMPORARY, MYF(0));
+ MYSQL_YYABORT;
+ }
+ }
+ else
+ {
+ Lex->alter_info.flags|= Alter_info::ALTER_ADD_SYSTEM_VERSIONING;
+ Lex->create_info.options|= HA_VERSIONED_TABLE;
+ }
}
;
@@ -6182,6 +6342,7 @@ field_list_item:
column_def { }
| key_def
| constraint_def
+ | period_for_system_time
;
column_def:
@@ -6281,6 +6442,15 @@ 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 '(' ident ',' ident ')'
+ {
+ Vers_parse_info &info= Lex->vers_get_info();
+ info.set_system_time($4, $6);
+ }
+ ;
+
opt_check_constraint:
/* empty */ { $$= (Virtual_column_info*) 0; }
| check_constraint { $$= $1;}
@@ -6366,6 +6536,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
@@ -6375,6 +6554,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 opt_asrow_attribute
+ {
+ LEX *lex= Lex;
+ Vers_parse_info &info= lex->vers_get_info();
+ const LEX_CSTRING &field_name= lex->last_field->field_name;
+
+ LString_i *p;
+ switch ($4)
+ {
+ case 1:
+ p= &info.as_row.start;
+ if (*p)
+ {
+ my_yyabort_error((ER_VERS_DUPLICATE_ROW_START_END, MYF(0),
+ "START", field_name.str));
+ }
+ lex->last_field->flags|= VERS_SYS_START_FLAG;
+ break;
+ case 0:
+ p= &info.as_row.end;
+ if (*p)
+ {
+ my_yyabort_error((ER_VERS_DUPLICATE_ROW_START_END, MYF(0),
+ "END", field_name.str));
+ }
+ lex->last_field->flags|= VERS_SYS_END_FLAG;
+ break;
+ default:
+ /* Not Reachable */
+ MYSQL_YYABORT;
+ break;
+ }
+ DBUG_ASSERT(p);
+ *p= field_name;
+ }
+ ;
+
+start_or_end:
+ START_SYM { $$ = 1; }
+ | END { $$ = 0; }
;
opt_generated_always:
@@ -6427,7 +6646,7 @@ vcol_attribute:
| COMMENT_SYM TEXT_STRING_sys { Lex->last_field->comment= $2; }
| INVISIBLE_SYM
{
- Lex->last_field->field_visibility= USER_DEFINED_INVISIBLE;
+ Lex->last_field->invisible= INVISIBLE_USER;
}
;
@@ -6838,8 +7057,11 @@ opt_compression_method:
| equal ident { $$= $2.str; }
;
-serial_attribute:
- not NULL_SYM { Lex->last_field->flags|= NOT_NULL_FLAG; }
+asrow_attribute:
+ not NULL_SYM
+ {
+ Lex->last_field->flags|= NOT_NULL_FLAG;
+ }
| opt_primary KEY_SYM
{
LEX *lex=Lex;
@@ -6847,6 +7069,10 @@ serial_attribute:
lex->alter_info.flags|= Alter_info::ALTER_ADD_INDEX;
}
| vcol_attribute
+ ;
+
+serial_attribute:
+ asrow_attribute
| IDENT_sys equal TEXT_STRING_sys
{
if ($3.length > ENGINE_OPTION_MAX_LENGTH)
@@ -6874,6 +7100,26 @@ serial_attribute:
new (thd->mem_root)
engine_option_value($1, &Lex->last_field->option_list, &Lex->option_list_last);
}
+ | with_or_without_system VERSIONING_SYM
+ {
+ Lex->last_field->versioning= $1;
+ Lex->create_info.options|= HA_VERSIONED_TABLE;
+ }
+ ;
+
+with_or_without_system:
+ WITH_SYSTEM_SYM
+ {
+ Lex->alter_info.flags|= Alter_info::ALTER_COLUMN_UNVERSIONED;
+ Lex->create_info.vers_info.versioned_fields= true;
+ $$= Column_definition::WITH_VERSIONING;
+ }
+ | WITHOUT SYSTEM
+ {
+ Lex->alter_info.flags|= Alter_info::ALTER_COLUMN_UNVERSIONED;
+ Lex->create_info.vers_info.unversioned_fields= true;
+ $$= Column_definition::WITHOUT_VERSIONING;
+ }
;
@@ -7832,6 +8078,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 |
@@ -7996,6 +8245,15 @@ alter_list_item:
}
| alter_algorithm_option
| alter_lock_option
+ | ADD SYSTEM VERSIONING_SYM
+ {
+ Lex->alter_info.flags|= Alter_info::ALTER_ADD_SYSTEM_VERSIONING;
+ Lex->create_info.options|= HA_VERSIONED_TABLE;
+ }
+ | DROP SYSTEM VERSIONING_SYM
+ {
+ Lex->alter_info.flags|= Alter_info::ALTER_DROP_SYSTEM_VERSIONING;
+ }
;
opt_index_lock_algorithm:
@@ -8908,6 +9166,53 @@ select_options:
}
;
+opt_trans_or_timestamp:
+ /* empty */
+ {
+ $$ = VERS_UNDEFINED;
+ }
+ | TRANSACTION_SYM
+ {
+ $$ = VERS_TRX_ID;
+ }
+ | TIMESTAMP
+ {
+ $$ = VERS_TIMESTAMP;
+ }
+ ;
+
+opt_for_system_time_clause:
+ /* empty */
+ {
+ $$= false;
+ }
+ | FOR_SYSTEM_TIME_SYM system_time_expr
+ {
+ $$= true;
+ }
+ ;
+
+system_time_expr:
+ AS OF_SYM opt_trans_or_timestamp simple_expr
+ {
+ Lex->vers_conditions.init(SYSTEM_TIME_AS_OF, $3, $4);
+ }
+ | ALL
+ {
+ Lex->vers_conditions.init(SYSTEM_TIME_ALL);
+ }
+ | FROM opt_trans_or_timestamp simple_expr
+ TO_SYM opt_trans_or_timestamp simple_expr
+ {
+ Lex->vers_conditions.init(SYSTEM_TIME_FROM_TO, $2, $3, $5, $6);
+ }
+ | BETWEEN_SYM opt_trans_or_timestamp simple_expr
+ AND_SYM opt_trans_or_timestamp simple_expr
+ {
+ Lex->vers_conditions.init(SYSTEM_TIME_BETWEEN, $2, $3, $5, $6);
+ }
+ ;
+
select_option_list:
select_option_list select_option
| select_option
@@ -11428,12 +11733,13 @@ 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_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,
@@ -11441,6 +11747,8 @@ table_primary_ident:
$3)))
MYSQL_YYABORT;
Select->add_joined_table($$);
+ if ($4)
+ $$->vers_conditions= Lex->vers_conditions;
}
;
@@ -11463,11 +11771,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,
@@ -11490,7 +11798,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;
@@ -11498,7 +11806,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
@@ -11522,11 +11830,16 @@ table_primary_derived:
if ($$ && $$->derived &&
!$$->derived->first_select()->next_select())
$$->select_lex->add_where_field($$->derived->first_select());
+ if ($5)
+ {
+ MYSQL_YYABORT_UNLESS(!$3);
+ $$->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;
@@ -11537,10 +11850,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;
}
;
@@ -13087,10 +13402,29 @@ delete:
lex->ignore= 0;
lex->select_lex.init_order();
}
- opt_delete_options single_multi
+ delete_part2
+ ;
+
+opt_delete_system_time:
+ /* empty */
+ {
+ Lex->vers_conditions.init(SYSTEM_TIME_ALL);
+ }
+ | BEFORE_SYM SYSTEM_TIME_SYM opt_trans_or_timestamp simple_expr
+ {
+ Lex->vers_conditions.init(SYSTEM_TIME_BEFORE, $3, $4);
+ }
+ ;
+
+delete_part2:
+ opt_delete_options single_multi {}
+ | HISTORY_SYM delete_single_table opt_delete_system_time
+ {
+ Lex->last_table()->vers_conditions= Lex->vers_conditions;
+ }
;
-single_multi:
+delete_single_table:
FROM table_ident opt_use_partition
{
if (!Select->add_table_to_list(thd, $2, NULL, TL_OPTION_UPDATING,
@@ -13102,8 +13436,13 @@ single_multi:
YYPS->m_lock_type= TL_READ_DEFAULT;
YYPS->m_mdl_type= MDL_SHARED_READ;
}
- opt_where_clause opt_order_clause
- delete_limit_clause {}
+ ;
+
+single_multi:
+ delete_single_table
+ opt_where_clause
+ opt_order_clause
+ delete_limit_clause
opt_select_expressions {}
| table_wild_list
{
@@ -13185,7 +13524,7 @@ opt_delete_option:
;
truncate:
- TRUNCATE_SYM opt_table_sym
+ TRUNCATE_SYM
{
LEX* lex= Lex;
lex->sql_command= SQLCOM_TRUNCATE;
@@ -13196,7 +13535,7 @@ truncate:
YYPS->m_lock_type= TL_WRITE;
YYPS->m_mdl_type= MDL_EXCLUSIVE;
}
- table_name opt_lock_wait_timeout
+ opt_table_sym table_name opt_lock_wait_timeout
{
LEX* lex= thd->lex;
DBUG_ASSERT(!lex->m_sql_cmd);
@@ -13491,13 +13830,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 != SYSTEM_TIME_UNSPECIFIED &&
+ lex->vers_conditions.type != SYSTEM_TIME_AS_OF)
+ {
+ my_yyabort_error((ER_VERS_RANGE_PROHIBITED, MYF(0)));
+ }
+ if ($4)
+ Lex->last_table()->vers_conditions= Lex->vers_conditions;
}
| CREATE VIEW_SYM table_ident
{
@@ -14963,6 +15310,7 @@ keyword_alias:
| OTHERS_SYM {}
| OWNER_SYM {}
| PARSER_SYM {}
+ | PERIOD_SYM {}
| PORT_SYM {}
| PRECEDES_SYM {}
| PRECEDING_SYM {}
@@ -15168,7 +15516,7 @@ keyword_sp_not_data_type:
| GOTO_SYM {}
| HASH_SYM {}
| HARD_SYM {}
- | INVISIBLE_SYM {}
+ | HISTORY_SYM {}
| HOSTS_SYM {}
| HOUR_SYM {}
| ID_SYM {}
@@ -15186,6 +15534,7 @@ keyword_sp_not_data_type:
| ISOPEN_SYM {}
| ISSUER_SYM {}
| INSERT_METHOD {}
+ | INVISIBLE_SYM {}
| KEY_BLOCK_SIZE {}
| LAST_VALUE {}
| LAST_SYM {}
@@ -15346,6 +15695,8 @@ keyword_sp_not_data_type:
| SUSPEND_SYM {}
| SWAPS_SYM {}
| SWITCHES_SYM {}
+ | SYSTEM {}
+ | SYSTEM_TIME_SYM {}
| TABLE_NAME_SYM {}
| TABLES {}
| TABLE_CHECKSUM_SYM {}
@@ -15371,6 +15722,7 @@ keyword_sp_not_data_type:
| USER_SYM {}
| USE_FRM {}
| VARIABLES {}
+ | VERSIONING_SYM {}
| VIEW_SYM {}
| VIRTUAL_SYM {}
| VALUE_SYM {}
@@ -15378,6 +15730,7 @@ keyword_sp_not_data_type:
| WAIT_SYM {}
| WEEK_SYM {}
| WEIGHT_STRING_SYM {}
+ | WITHOUT {}
| WORK_SYM {}
| X509_SYM {}
| XML_SYM {}
@@ -15807,6 +16160,18 @@ set_expr_or_default:
if ($$ == NULL)
MYSQL_YYABORT;
}
+ | DROP
+ {
+ $$=new (thd->mem_root) Item_string_sys(thd, "DROP", 4);
+ if ($$ == NULL)
+ MYSQL_YYABORT;
+ }
+ | RANGE_SYM
+ {
+ $$=new (thd->mem_root) Item_string_sys(thd, C_STRING_WITH_LEN("RANGE"));
+ if ($$ == NULL)
+ MYSQL_YYABORT;
+ }
;
/* Lock function */
@@ -16189,6 +16554,7 @@ object_privilege:
| EVENT_SYM { Lex->grant |= EVENT_ACL;}
| TRIGGER_SYM { Lex->grant |= TRIGGER_ACL; }
| CREATE TABLESPACE { Lex->grant |= CREATE_TABLESPACE_ACL; }
+ | DELETE_SYM HISTORY_SYM { Lex->grant |= DELETE_HISTORY_ACL; }
;
opt_and:
@@ -16968,9 +17334,14 @@ trigger_tail:
}
table_ident /* $10 */
FOR_SYM
- remember_name /* $12 */
- { /* $13 */
- Lex->raw_trg_on_table_name_end= YYLIP->get_tok_start();
+ remember_name /* $13 */
+ { /* $14 */
+ /*
+ 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/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy
index 2dcfa018dce..e96e8bdcb9a 100644
--- a/sql/sql_yacc_ora.yy
+++ b/sql/sql_yacc_ora.yy
@@ -284,6 +284,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
Comments for TOKENS.
For each token, please include in the same line a comment that contains
the following tags:
+ SQL-2011-R : Reserved keyword as per SQL-2011
SQL-2011-N : Non Reserved keyword as per SQL-2011
SQL-2003-R : Reserved keyword as per SQL-2003
SQL-2003-N : Non Reserved keyword as per SQL-2003
@@ -508,6 +509,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
@@ -537,7 +539,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token HEX_NUM
%token HEX_STRING
%token HIGH_PRIORITY
-%token INVISIBLE_SYM
+%token HISTORY_SYM /* MYSQL */
%token HOST_SYM
%token HOSTS_SYM
%token HOUR_MICROSECOND_SYM
@@ -578,6 +580,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token ISOPEN_SYM /* Oracle-N */
%token ISSUER_SYM
%token ITERATE_SYM
+%token INVISIBLE_SYM
%token JOIN_SYM /* SQL-2003-R */
%token JSON_SYM
%token KEYS
@@ -742,6 +745,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token PERCENT_RANK_SYM
%token PERCENTILE_CONT_SYM
%token PERCENTILE_DISC_SYM
+%token PERIOD_SYM /* SQL-2011-R */
%token PERSISTENT_SYM
%token PHASE_SYM
%token PLUGINS_SYM
@@ -908,6 +912,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token SWAPS_SYM
%token SWITCHES_SYM
%token SYSDATE
+%token SYSTEM /* SQL-2011-R */
+%token SYSTEM_TIME_SYM /* SQL-2011-R */
%token TABLES
%token TABLESPACE
%token TABLE_REF_PRIORITY
@@ -978,6 +984,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 /* SQL-2011-R */
%token VIA_SYM
%token VIEW_SYM /* SQL-2003-N */
%token VIRTUAL_SYM
@@ -991,8 +998,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token WHILE_SYM
%token WITH /* SQL-2003-R */
%token WITHIN
+%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 */
@@ -6128,7 +6137,7 @@ vcol_attribute:
| COMMENT_SYM TEXT_STRING_sys { Lex->last_field->comment= $2; }
| INVISIBLE_SYM
{
- Lex->last_field->field_visibility= USER_DEFINED_INVISIBLE;
+ Lex->last_field->invisible= INVISIBLE_USER;
}
;
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 0e5192d72ad..3b37fac5c39 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -390,6 +390,61 @@ static Sys_var_charptr Sys_my_bind_addr(
READ_ONLY GLOBAL_VAR(my_bind_addr_str), CMD_LINE(REQUIRED_ARG),
IN_FS_CHARSET, DEFAULT(0));
+const char *Sys_var_vers_asof::asof_keywords[]= {"DEFAULT", NULL};
+static Sys_var_vers_asof Sys_vers_asof_timestamp(
+ "system_versioning_asof", "Default value for the FOR SYSTEM_TIME AS OF clause",
+ SESSION_VAR(vers_asof_timestamp.type), NO_CMD_LINE,
+ Sys_var_vers_asof::asof_keywords, DEFAULT(SYSTEM_TIME_UNSPECIFIED));
+
+#ifdef VERS_EXPERIMENTAL
+static Sys_var_mybool Sys_vers_force(
+ "debug_system_versioning_force", "Force system versioning for all created tables",
+ SESSION_VAR(vers_force), CMD_LINE(OPT_ARG), DEFAULT(FALSE));
+
+static const char *vers_show_keywords[]= {"OFF", "RANGE", "ALWAYS", NULL};
+static Sys_var_enum Sys_vers_show(
+ "debug_system_versioning_show", "Show system fields special rules. "
+ "OFF: don't use special show rules; "
+ "RANGE: show implicit system fields only in range versioned queries; "
+ "ALWAYS: show system fields in all queries",
+ SESSION_VAR(vers_show), CMD_LINE(REQUIRED_ARG),
+ vers_show_keywords, DEFAULT(VERS_SHOW_OFF));
+#endif
+
+static Sys_var_mybool Sys_vers_innodb_algorithm_simple(
+ "system_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));
+
+static const char *vers_alter_history_keywords[]= {"ERROR", "KEEP",/* "SURVIVE", "DROP",*/ NULL};
+static Sys_var_enum Sys_vers_alter_history(
+ "system_versioning_alter_history", "Versioning ALTER TABLE mode. "
+ "ERROR: Fail ALTER with error; " /* TODO: fail only when history non-empty */
+ "KEEP: Keep historical system rows and subject them to ALTER; "
+ /*"SURVIVE: Keep historical system rows intact; "
+ "DROP: Drop historical system rows while processing ALTER"*/,
+ SESSION_VAR(vers_alter_history), CMD_LINE(REQUIRED_ARG),
+ vers_alter_history_keywords, DEFAULT(VERS_ALTER_HISTORY_ERROR));
+
+static bool update_transaction_registry(sys_var *self, THD *thd, enum_var_type type)
+{
+ use_transaction_registry= opt_transaction_registry;
+ if (use_transaction_registry)
+ {
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, WARN_VERS_TRT_EXPERIMENTAL,
+ ER_THD(thd, WARN_VERS_TRT_EXPERIMENTAL));
+ }
+ return false;
+}
+
+static Sys_var_mybool Sys_vers_transaction_registry(
+ "system_versioning_transaction_registry",
+ "Enable or disable update of `mysql`.`transaction_registry`",
+ GLOBAL_VAR(opt_transaction_registry), CMD_LINE(OPT_ARG),
+ DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ 0, ON_UPDATE(update_transaction_registry));
+
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/sql/sys_vars.ic b/sql/sys_vars.ic
index 706240727c5..e012cd48ecb 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.
@@ -2597,3 +2602,96 @@ public:
bool global_update(THD *thd, set_var *var);
uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base);
};
+
+
+class Sys_var_vers_asof: public Sys_var_enum
+{
+public:
+ static const char *asof_keywords[];
+
+public:
+ Sys_var_vers_asof(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt, const char *values[],
+ uint def_val)
+ : Sys_var_enum(name_arg, comment, flag_args, off, size,
+ getopt, values, def_val)
+ {
+ // setval() accepts string rather enum
+ option.var_type= GET_STR;
+ }
+ virtual bool do_check(THD *thd, set_var *var)
+ {
+ if (!Sys_var_enum::do_check(thd, var))
+ return false;
+ MYSQL_TIME ltime;
+ bool res= var->value->get_date(&ltime, 0);
+ if (!res)
+ {
+ var->save_result.ulonglong_value= SYSTEM_TIME_AS_OF;
+ }
+ return res;
+ }
+
+private:
+ bool update(set_var *var, vers_asof_timestamp_t &out)
+ {
+ bool res= false;
+ out.type= static_cast<enum_var_type>(var->save_result.ulonglong_value);
+ if (out.type == SYSTEM_TIME_AS_OF)
+ {
+ if (var->value)
+ {
+ res= var->value->get_date(&out.ltime, 0);
+ }
+ else // set DEFAULT from global var
+ {
+ out= global_var(vers_asof_timestamp_t);
+ res= false;
+ }
+ }
+ return res;
+ }
+
+public:
+ virtual bool global_update(THD *thd, set_var *var)
+ {
+ return update(var, global_var(vers_asof_timestamp_t));
+ }
+ virtual bool session_update(THD *thd, set_var *var)
+ {
+ return update(var, session_var(thd, vers_asof_timestamp_t));
+ }
+
+private:
+ uchar *value_ptr(THD *thd, vers_asof_timestamp_t &val)
+ {
+ switch (val.type)
+ {
+ case SYSTEM_TIME_UNSPECIFIED:
+ case SYSTEM_TIME_ALL:
+ return (uchar*) thd->strdup(asof_keywords[val.type]);
+ case SYSTEM_TIME_AS_OF:
+ {
+ uchar *buf= (uchar*) thd->alloc(MAX_DATE_STRING_REP_LENGTH);
+ if (buf &&!my_datetime_to_str(&val.ltime, (char*) buf, 6))
+ {
+ // TODO: figure out variable name
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "system_versioning_asof_timestamp", "NULL (wrong datetime)");
+ return (uchar*) thd->strdup("Error: wrong datetime");
+ }
+ return buf;
+ }
+ default:
+ break;
+ }
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "system_versioning_asof_timestamp", "NULL (wrong range type)");
+ return (uchar*) thd->strdup("Error: wrong range type");
+ }
+
+public:
+ virtual uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base)
+ { return value_ptr(thd, session_var(thd, vers_asof_timestamp_t)); }
+ virtual uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base)
+ { return value_ptr(thd, global_var(vers_asof_timestamp_t)); }
+};
diff --git a/sql/table.cc b/sql/table.cc
index e6878c42ea2..d7e7e3f0a89 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -68,6 +68,8 @@ LEX_CSTRING GENERAL_LOG_NAME= {STRING_WITH_LEN("general_log")};
/* SLOW_LOG name */
LEX_CSTRING SLOW_LOG_NAME= {STRING_WITH_LEN("slow_log")};
+LEX_CSTRING TRANSACTION_REG_NAME= {STRING_WITH_LEN("transaction_registry")};
+
/*
Keyword added as a prefix when parsing the defining expression for a
virtual column read from the column definition saved in the frm file
@@ -260,6 +262,9 @@ TABLE_CATEGORY get_table_category(const LEX_CSTRING *db,
if (lex_string_eq(&SLOW_LOG_NAME, name) == 0)
return TABLE_CATEGORY_LOG;
+
+ if (lex_string_eq(&TRANSACTION_REG_NAME, name) == 0)
+ return TABLE_CATEGORY_LOG;
}
return TABLE_CATEGORY_USER;
@@ -416,6 +421,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;
@@ -1162,14 +1170,12 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
uint db_create_options, keys, key_parts, n_length;
uint com_length, null_bit_pos, UNINIT_VAR(mysql57_vcol_null_bit_pos), bitmap_count;
uint i;
- uint field_additional_property_length= 0;
bool use_hash, mysql57_null_bits= 0;
char *keynames, *names, *comment_pos;
const uchar *forminfo, *extra2;
const uchar *frm_image_end = frm_image + frm_length;
uchar *record, *null_flags, *null_pos, *mysql57_vcol_null_pos= 0;
const uchar *disk_buff, *strpos;
- const uchar *field_properties= NULL;
ulong pos, record_offset;
ulong rec_buff_length;
handler *handler_file= 0;
@@ -1189,6 +1195,13 @@ 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;
+ bool vtmd_used= false;
+ share->vtmd= false;
+ bool vers_can_native= false;
+ 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;
DBUG_ENTER("TABLE_SHARE::init_from_binary_frm_image");
@@ -1282,9 +1295,27 @@ 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;
+ case EXTRA2_VTMD:
+ if (vtmd_used)
+ goto err;
+ share->vtmd= *extra2;
+ if (share->vtmd)
+ {
+ share->table_category= TABLE_CATEGORY_LOG;
+ share->no_replicate= true;
+ }
+ vtmd_used= true;
+ break;
case EXTRA2_FIELD_FLAGS:
- field_properties = extra2;
- field_additional_property_length= length;
+ 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 */
@@ -1603,7 +1634,7 @@ 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 (field_properties && field_additional_property_length != share->fields)
+ 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);
@@ -1737,6 +1768,28 @@ 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= VERS_UNDEFINED;
+ 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= VERS_TIMESTAMP;
+ vers_can_native= plugin_hton(se_plugin)->flags & HTON_NATIVE_SYS_VERSIONING;
+ 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;
@@ -1751,6 +1804,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
uint gis_length, gis_decimals, srid= 0;
Field::utype unireg_check;
const Type_handler *handler;
+ uint32 flags= 0;
if (new_frm_ver >= 3)
{
@@ -1960,6 +2014,35 @@ 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;
+
+ if (flags & VERS_SYSTEM_FIELD)
+ {
+ switch (field_type)
+ {
+ case MYSQL_TYPE_TIMESTAMP2:
+ case MYSQL_TYPE_DATETIME2:
+ break;
+ case MYSQL_TYPE_LONGLONG:
+ if (vers_can_native)
+ {
+ versioned= VERS_TRX_ID;
+ break;
+ }
+ default:
+ my_error(ER_VERS_FIELD_WRONG_TYPE, MYF(0), fieldnames.type_names[i],
+ versioned == VERS_TIMESTAMP ? "TIMESTAMP(6)" : "BIGINT(20) UNSIGNED",
+ table_name.str);
+ goto err;
+ }
+ }
+ }
+
/* Convert pre-10.2.2 timestamps to use Field::default_value */
unireg_check= (Field::utype) MTYP_TYPENR(unireg_type);
name.str= fieldnames.type_names[i];
@@ -1971,7 +2054,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
null_pos, null_bit_pos, pack_flag, handler, charset,
geom_type, srid, unireg_check,
(interval_nr ? share->intervals+interval_nr-1 : NULL),
- &name);
+ &name, flags);
if (!reg_field) // Not supported field type
goto err;
@@ -1987,14 +2070,18 @@ 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(field_properties!=NULL)
+ reg_field->flags|= flags;
+ if (extra2_field_flags)
{
- uint temp= *field_properties++;
- reg_field->field_visibility= f_visibility(temp);
+ uchar flags= *extra2_field_flags++;
+ if (flags & VERS_OPTIMIZED_UPDATE)
+ reg_field->flags|= VERS_UPDATE_UNVERSIONED_FLAG;
+
+ reg_field->invisible= f_visibility(flags);
}
- if (reg_field->field_visibility == USER_DEFINED_INVISIBLE)
+ if (reg_field->invisible == INVISIBLE_USER)
status_var_increment(thd->status_var.feature_invisible_columns);
- if (reg_field->field_visibility == NOT_INVISIBLE)
+ if (!reg_field->invisible)
share->visible_fields++;
if (field_type == MYSQL_TYPE_BIT && !f_bit_as_char(pack_flag))
{
@@ -2245,7 +2332,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
field= key_part->field= share->field[key_part->fieldnr-1];
key_part->type= field->key_type();
- if (field->field_visibility > USER_DEFINED_INVISIBLE)
+ if (field->invisible > INVISIBLE_USER && !field->vers_sys_field())
keyinfo->flags |= HA_INVISIBLE_KEY;
if (field->null_ptr)
{
@@ -2566,19 +2653,21 @@ 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;
+ 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;
@@ -3094,25 +3183,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,
@@ -3137,6 +3231,8 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
}
(*field_ptr)= 0; // End marker
+ outparam->vers_write= share->versioned;
+
if (share->found_next_number_field)
outparam->found_next_number_field=
outparam->field[(uint) (share->found_next_number_field - share->field)];
@@ -3228,6 +3324,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)
{
/*
@@ -3248,7 +3345,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,
@@ -3408,6 +3504,38 @@ partititon_err:
if (share->no_replicate || !binlog_filter->db_ok(share->db.str))
share->can_do_row_logging= 0; // No row based replication
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ if (outparam->part_info &&
+ outparam->part_info->part_type == VERSIONING_PARTITION)
+ {
+ 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_stats(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)
+ {
+ outparam->file->ha_close();
+ 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++;
@@ -4658,16 +4786,20 @@ bool TABLE_LIST::create_field_translation(THD *thd)
*/
if (is_view() && get_unit()->prepared && !field_translation_updated)
{
+ field_translation_updated= TRUE;
+ if (static_cast<uint>(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 */
@@ -6303,6 +6435,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);
+ }
}
@@ -6379,6 +6520,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();
@@ -7624,6 +7774,52 @@ int TABLE::update_default_fields(bool update_command, bool ignore_errors)
DBUG_RETURN(res);
}
+
+void TABLE::vers_update_fields()
+{
+ bitmap_set_bit(write_set, vers_start_field()->field_index);
+ bitmap_set_bit(write_set, vers_end_field()->field_index);
+
+ if (versioned(VERS_TIMESTAMP))
+ {
+ if (!vers_write)
+ return;
+ vers_start_field()->set_notnull();
+ if (vers_start_field()->store_timestamp(in_use->system_time,
+ in_use->system_time_sec_part))
+ DBUG_ASSERT(0);
+ }
+ else
+ {
+ vers_start_field()->set_notnull();
+ if (!vers_write)
+ return;
+ }
+
+ vers_end_field()->set_max();
+}
+
+
+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
*/
@@ -8369,6 +8565,354 @@ LEX_CSTRING *fk_option_name(enum_fk_option opt)
return names + opt;
}
+void TABLE_SHARE::vers_destroy()
+{
+ mysql_mutex_destroy(&LOCK_rotation);
+ mysql_cond_destroy(&COND_rotation);
+ mysql_rwlock_destroy(&LOCK_stat_serial);
+ if (stat_trx)
+ {
+ for (Vers_min_max_stats** p= stat_trx; *p; ++p)
+ {
+ delete *p;
+ }
+ }
+}
+
+TR_table::TR_table(THD* _thd, bool rw) :
+ thd(_thd), open_tables_backup(NULL)
+{
+ init_one_table(LEX_STRING_WITH_LEN(MYSQL_SCHEMA_NAME),
+ LEX_STRING_WITH_LEN(TRANSACTION_REG_NAME),
+ TRANSACTION_REG_NAME.str, rw ? TL_WRITE : TL_READ);
+}
+
+bool TR_table::open()
+{
+ DBUG_ASSERT(!table);
+ open_tables_backup= new Open_tables_backup;
+ if (!open_tables_backup)
+ {
+ my_error(ER_OUT_OF_RESOURCES, MYF(0));
+ return true;
+ }
+
+ All_tmp_tables_list *temporary_tables= thd->temporary_tables;
+ bool error= !open_log_table(thd, this, open_tables_backup);
+ thd->temporary_tables= temporary_tables;
+
+ return error;
+}
+
+TR_table::~TR_table()
+{
+ if (table)
+ {
+ thd->temporary_tables= NULL;
+ close_log_table(thd, open_tables_backup);
+ }
+ delete open_tables_backup;
+}
+
+void TR_table::store(uint field_id, ulonglong val)
+{
+ table->field[field_id]->store(val, true);
+ table->field[field_id]->set_notnull();
+}
+
+void TR_table::store(uint field_id, timeval ts)
+{
+ table->field[field_id]->store_timestamp(ts.tv_sec, ts.tv_usec);
+ table->field[field_id]->set_notnull();
+}
+
+enum_tx_isolation TR_table::iso_level() const
+{
+ enum_tx_isolation res= (enum_tx_isolation) ((*this)[FLD_ISO_LEVEL]->val_int() - 1);
+ DBUG_ASSERT(res <= ISO_SERIALIZABLE);
+ return res;
+}
+
+bool TR_table::update(ulonglong start_id, ulonglong end_id)
+{
+ if (!table && open())
+ return true;
+
+ timeval start_time= {thd->system_time, long(thd->system_time_sec_part)};
+ thd->set_start_time();
+ timeval end_time= {thd->system_time, long(thd->system_time_sec_part)};
+ store(FLD_TRX_ID, start_id);
+ store(FLD_COMMIT_ID, end_id);
+ store(FLD_BEGIN_TS, start_time);
+ store(FLD_COMMIT_TS, end_time);
+ store_iso_level(thd->tx_isolation);
+
+ int error= table->file->ha_write_row(table->record[0]);
+ if (error)
+ table->file->print_error(error, MYF(0));
+ return error;
+}
+
+#define newx new (thd->mem_root)
+bool TR_table::query(ulonglong trx_id)
+{
+ if (!table && open())
+ return false;
+ SQL_SELECT_auto select;
+ READ_RECORD info;
+ int error;
+ List<TABLE_LIST> dummy;
+ SELECT_LEX &slex= thd->lex->select_lex;
+ Name_resolution_context_backup backup(slex.context, *this);
+ Item *field= newx Item_field(thd, &slex.context, (*this)[FLD_TRX_ID]);
+ Item *value= newx Item_int(thd, trx_id);
+ COND *conds= newx Item_func_eq(thd, field, value);
+ if ((error= setup_conds(thd, this, dummy, &conds)))
+ return false;
+ select= make_select(table, 0, 0, conds, NULL, 0, &error);
+ if (error || !select)
+ return false;
+ // FIXME: (performance) force index 'transaction_id'
+ error= init_read_record(&info, thd, table, select, NULL,
+ 1 /* use_record_cache */, true /* print_error */,
+ false /* disable_rr_cache */);
+ while (!(error= info.read_record()) && !thd->killed && !thd->is_error())
+ {
+ if (select->skip_record(thd) > 0)
+ return true;
+ }
+ return false;
+}
+
+bool TR_table::query(MYSQL_TIME &commit_time, bool backwards)
+{
+ if (!table && open())
+ return false;
+ SQL_SELECT_auto select;
+ READ_RECORD info;
+ int error;
+ List<TABLE_LIST> dummy;
+ SELECT_LEX &slex= thd->lex->select_lex;
+ Name_resolution_context_backup backup(slex.context, *this);
+ Item *field= newx Item_field(thd, &slex.context, (*this)[FLD_COMMIT_TS]);
+ Item *value= newx Item_datetime_literal(thd, &commit_time, 6);
+ COND *conds;
+ if (backwards)
+ conds= newx Item_func_ge(thd, field, value);
+ else
+ conds= newx Item_func_le(thd, field, value);
+ if ((error= setup_conds(thd, this, dummy, &conds)))
+ return false;
+ // FIXME: (performance) force index 'commit_timestamp'
+ select= make_select(table, 0, 0, conds, NULL, 0, &error);
+ if (error || !select)
+ return false;
+ error= init_read_record(&info, thd, table, select, NULL,
+ 1 /* use_record_cache */, true /* print_error */,
+ false /* disable_rr_cache */);
+
+ // With PK by transaction_id the records are ordered by PK
+ bool found= false;
+ while (!(error= info.read_record()) && !thd->killed && !thd->is_error())
+ {
+ if (select->skip_record(thd) > 0)
+ {
+ if (backwards)
+ return true;
+ found= true;
+ // TODO: (performance) make ORDER DESC and break after first found.
+ // Otherwise it is O(n) scan (+copy)!
+ store_record(table, record[1]);
+ }
+ else
+ {
+ if (found)
+ restore_record(table, record[1]);
+ if (!backwards)
+ break;
+ }
+ }
+ return found;
+}
+#undef newx
+
+bool TR_table::query_sees(bool &result, ulonglong trx_id1, ulonglong trx_id0,
+ ulonglong commit_id1, enum_tx_isolation iso_level1,
+ ulonglong commit_id0)
+{
+ if (trx_id1 == trx_id0)
+ {
+ return false;
+ }
+
+ if (trx_id1 == ULONGLONG_MAX || trx_id0 == 0)
+ {
+ result= true;
+ return false;
+ }
+
+ if (!commit_id1)
+ {
+ if (!query(trx_id1))
+ return true;
+
+ commit_id1= (*this)[FLD_COMMIT_ID]->val_int();
+ iso_level1= iso_level();
+ }
+
+ if (!commit_id0)
+ {
+ if (!query(trx_id0))
+ return true;
+
+ commit_id0= (*this)[FLD_COMMIT_ID]->val_int();
+ }
+
+ // 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 < ISO_REPEATABLE_READ))
+ {
+ result= true;
+ }
+ else // All other cases: TX1 does not see TX0
+ {
+ result= false;
+ }
+
+ return false;
+}
+
+void TR_table::warn_schema_incorrect(const char *reason)
+{
+ if (MYSQL_VERSION_ID == table->s->mysql_version)
+ {
+ sql_print_error("`%s.%s` schema is incorrect: %s.", db, table_name, reason);
+ }
+ else
+ {
+ sql_print_error("`%s.%s` schema is incorrect: %s. Created with MariaDB %d, "
+ "now running %d.", db, table_name, reason, MYSQL_VERSION_ID,
+ static_cast<int>(table->s->mysql_version));
+ }
+}
+
+bool TR_table::check()
+{
+ if (!ha_resolve_by_legacy_type(thd, DB_TYPE_INNODB))
+ {
+ sql_print_information("`%s.%s` requires InnoDB storage engine.", db, table_name);
+ return true;
+ }
+
+ if (open())
+ {
+ sql_print_warning("`%s.%s` does not exist (open failed).", db, table_name);
+ return true;
+ }
+
+ if (table->file->ht->db_type != DB_TYPE_INNODB)
+ {
+ warn_schema_incorrect("Wrong table engine (expected InnoDB)");
+ return true;
+ }
+
+#define WARN_SCHEMA(...) \
+ char reason[128]; \
+ snprintf(reason, 128, __VA_ARGS__); \
+ warn_schema_incorrect(reason);
+
+ if (table->s->fields != FIELD_COUNT)
+ {
+ WARN_SCHEMA("Wrong field count (expected %d)", FIELD_COUNT);
+ return true;
+ }
+
+ if (table->field[FLD_TRX_ID]->type() != MYSQL_TYPE_LONGLONG)
+ {
+ WARN_SCHEMA("Wrong field %d type (expected BIGINT UNSIGNED)", FLD_TRX_ID);
+ return true;
+ }
+
+ if (table->field[FLD_COMMIT_ID]->type() != MYSQL_TYPE_LONGLONG)
+ {
+ WARN_SCHEMA("Wrong field %d type (expected BIGINT UNSIGNED)", FLD_COMMIT_ID);
+ return true;
+ }
+
+ if (table->field[FLD_BEGIN_TS]->type() != MYSQL_TYPE_TIMESTAMP)
+ {
+ WARN_SCHEMA("Wrong field %d type (expected TIMESTAMP(6))", FLD_BEGIN_TS);
+ return true;
+ }
+
+ if (table->field[FLD_COMMIT_TS]->type() != MYSQL_TYPE_TIMESTAMP)
+ {
+ WARN_SCHEMA("Wrong field %d type (expected TIMESTAMP(6))", FLD_COMMIT_TS);
+ return true;
+ }
+
+ if (table->field[FLD_ISO_LEVEL]->type() != MYSQL_TYPE_STRING ||
+ !(table->field[FLD_ISO_LEVEL]->flags & ENUM_FLAG))
+ {
+ wrong_enum:
+ WARN_SCHEMA("Wrong field %d type (expected ENUM('READ-UNCOMMITTED', "
+ "'READ-COMMITTED', 'REPEATABLE-READ', 'SERIALIZABLE'))",
+ FLD_ISO_LEVEL);
+ return true;
+ }
+
+ Field_enum *iso_level= static_cast<Field_enum *>(table->field[FLD_ISO_LEVEL]);
+ st_typelib *typelib= iso_level->typelib;
+
+ if (typelib->count != 4)
+ goto wrong_enum;
+
+ if (strcmp(typelib->type_names[0], "READ-UNCOMMITTED") ||
+ strcmp(typelib->type_names[1], "READ-COMMITTED") ||
+ strcmp(typelib->type_names[2], "REPEATABLE-READ") ||
+ strcmp(typelib->type_names[3], "SERIALIZABLE"))
+ {
+ goto wrong_enum;
+ }
+
+ if (!table->key_info || !table->key_info->key_part)
+ goto wrong_pk;
+
+ if (strcmp(table->key_info->key_part->field->field_name.str, "transaction_id"))
+ {
+ wrong_pk:
+ WARN_SCHEMA("Wrong PRIMARY KEY (expected `transaction_id`)");
+ return true;
+ }
+
+ return false;
+}
+
+void vers_select_conds_t::resolve_units(bool timestamps_only)
+{
+ DBUG_ASSERT(type != SYSTEM_TIME_UNSPECIFIED);
+ DBUG_ASSERT(start);
+ if (unit_start == VERS_UNDEFINED)
+ {
+ if (start->type() == Item::FIELD_ITEM)
+ unit_start= VERS_TIMESTAMP;
+ else
+ unit_start= (!timestamps_only && (start->result_type() == INT_RESULT ||
+ start->result_type() == REAL_RESULT)) ?
+ VERS_TRX_ID : VERS_TIMESTAMP;
+ }
+ if (end && unit_end == VERS_UNDEFINED)
+ {
+ if (start->type() == Item::FIELD_ITEM)
+ unit_start= VERS_TIMESTAMP;
+ else
+ unit_end= (!timestamps_only && (end->result_type() == INT_RESULT ||
+ end->result_type() == REAL_RESULT)) ?
+ VERS_TRX_ID : VERS_TIMESTAMP;
+ }
+}
+
Field *TABLE::find_field_by_name(LEX_CSTRING *str) const
{
diff --git a/sql/table.h b/sql/table.h
index 8e39964eea9..6899b65eb57 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -337,15 +337,18 @@ enum enum_vcol_update_mode
/* Field visibility enums */
-enum field_visible_type{
- NOT_INVISIBLE= 0,
- USER_DEFINED_INVISIBLE,
- /* automatically added by the server. Can be queried explicitly
- in SELECT, otherwise invisible from anything" */
- SYSTEM_INVISIBLE,
- COMPLETELY_INVISIBLE
+enum field_visibility_t {
+ VISIBLE= 0,
+ INVISIBLE_USER,
+ /* automatically added by the server. Can be queried explicitly
+ in SELECT, otherwise invisible from anything" */
+ INVISIBLE_SYSTEM,
+ INVISIBLE_FULL
};
+#define INVISIBLE_MAX_BITS 3
+
+
/**
Category of table found in the table share.
*/
@@ -571,6 +574,18 @@ struct TABLE_STATISTICS_CB
bool histograms_are_read;
};
+class Vers_min_max_stats;
+
+enum vers_sys_type_t
+{
+ VERS_UNDEFINED= 0,
+ VERS_TIMESTAMP,
+ VERS_TRX_ID
+};
+
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
/**
This structure is shared between different table objects. There is one
@@ -633,6 +648,16 @@ struct TABLE_SHARE
LEX_CSTRING normalized_path; /* unpack_filename(path) */
LEX_CSTRING connect_string;
+ const char* orig_table_name; /* Original table name for this tmp table */
+ const char* error_table_name() const /* Get table name for error messages */
+ {
+ return tmp_table ? (
+ orig_table_name ?
+ orig_table_name :
+ "(temporary)") :
+ table_name.str;
+ }
+
/*
Set of keys in use, implemented as a Bitmap.
Excludes keys disabled by ALTER TABLE ... DISABLE KEYS.
@@ -748,6 +773,52 @@ struct TABLE_SHARE
#endif
/**
+ System versioning support.
+ */
+
+ vers_sys_type_t versioned;
+ bool vtmd;
+ uint16 row_start_field;
+ uint16 row_end_field;
+ uint32 hist_part_id;
+ Vers_min_max_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;
+ 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();
+
+ Field *vers_start_field()
+ {
+ return field[row_start_field];
+ }
+
+ Field *vers_end_field()
+ {
+ return field[row_end_field];
+ }
+
+ void vers_wait_rotation()
+ {
+ while (busy_rotation)
+ mysql_cond_wait(&COND_rotation, &LOCK_rotation);
+ }
+
+ /**
Cache the checked structure of this table.
The pointer data is used to describe the structure that
@@ -1059,7 +1130,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 */
@@ -1456,7 +1527,7 @@ public:
bool prepare_triggers_for_delete_stmt_or_event();
bool prepare_triggers_for_update_stmt_or_event();
- inline Field **field_to_fill();
+ Field **field_to_fill();
bool validate_default_values_of_unset_fields(THD *thd) const;
bool insert_all_rows_into_tmp_table(THD *thd,
@@ -1469,6 +1540,57 @@ public:
void set_spl_opt_info(SplM_opt_info *spl_info);
void deny_splitting();
void add_splitting_info_for_key_field(struct KEY_FIELD *key_field);
+
+ /**
+ System Versioning support
+ */
+ bool vers_write;
+
+ bool versioned() const
+ {
+ DBUG_ASSERT(s);
+ return s->versioned;
+ }
+
+ bool versioned(vers_sys_type_t type) const
+ {
+ DBUG_ASSERT(s);
+ DBUG_ASSERT(type);
+ return s->versioned == type;
+ }
+
+ bool versioned_write(vers_sys_type_t type= VERS_UNDEFINED) const
+ {
+ DBUG_ASSERT(versioned() || !vers_write);
+ return versioned(type) ? vers_write : false;
+ }
+
+ bool vers_vtmd() const
+ {
+ DBUG_ASSERT(s);
+ return s->versioned && s->vtmd;
+ }
+
+ Field *vers_start_field() const
+ {
+ DBUG_ASSERT(s && s->versioned);
+ return field[s->row_start_field];
+ }
+
+ Field *vers_end_field() const
+ {
+ DBUG_ASSERT(s && s->versioned);
+ return field[s->row_end_field];
+ }
+
+ ulonglong vers_start_id() const;
+ ulonglong vers_end_id() const;
+
+ int delete_row();
+ void vers_update_fields();
+
+/** Number of additional fields used in versioned tables */
+#define VERSIONING_FIELDS 2
};
@@ -1756,6 +1878,50 @@ class Item_in_subselect;
4) jtbm semi-join (jtbm_subselect != NULL)
*/
+/** last_leaf_for_name_resolutioning support. */
+struct vers_select_conds_t
+{
+ vers_system_time_t type;
+ vers_sys_type_t unit_start, unit_end;
+ bool from_query:1;
+ bool used:1;
+ Item *start, *end;
+
+ void empty()
+ {
+ type= SYSTEM_TIME_UNSPECIFIED;
+ unit_start= unit_end= VERS_UNDEFINED;
+ used= from_query= false;
+ start= end= NULL;
+ }
+
+ Item *fix_dec(Item *item);
+
+ void init(vers_system_time_t t, vers_sys_type_t u_start= VERS_UNDEFINED,
+ Item * s= NULL, vers_sys_type_t u_end= VERS_UNDEFINED,
+ Item * e= NULL);
+
+ bool init_from_sysvar(THD *thd);
+
+ bool operator== (vers_system_time_t b)
+ {
+ return type == b;
+ }
+ bool operator!= (vers_system_time_t b)
+ {
+ return type != b;
+ }
+ operator bool() const
+ {
+ return type != SYSTEM_TIME_UNSPECIFIED;
+ }
+ void resolve_units(bool timestamps_only);
+ bool user_defined() const
+ {
+ return !from_query && type != SYSTEM_TIME_UNSPECIFIED;
+ }
+};
+
struct LEX;
class Index_hint;
struct TABLE_LIST
@@ -1791,6 +1957,16 @@ struct TABLE_LIST
MDL_TRANSACTION);
}
+ TABLE_LIST(TABLE &_table, thr_lock_type lock_type)
+ {
+ DBUG_ASSERT(_table.s);
+ init_one_table(
+ LEX_STRING_WITH_LEN(_table.s->db),
+ LEX_STRING_WITH_LEN(_table.s->table_name),
+ _table.s->table_name.str, lock_type);
+ table= &_table;
+ }
+
inline void init_one_table_for_prelocking(const char *db_name_arg,
size_t db_length_arg,
const char *table_name_arg,
@@ -2220,6 +2396,12 @@ 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 */
+ vers_select_conds_t vers_conditions;
+ bool vers_vtmd_name(String &out) const;
+ bool vers_force_alias;
+
/**
@brief
Find the bottom in the chain of embedded table VIEWs.
@@ -2759,6 +2941,7 @@ extern LEX_CSTRING PERFORMANCE_SCHEMA_DB_NAME;
extern LEX_CSTRING GENERAL_LOG_NAME;
extern LEX_CSTRING SLOW_LOG_NAME;
+extern LEX_CSTRING TRANSACTION_REG_NAME;
/* information schema */
extern LEX_CSTRING INFORMATION_SCHEMA_NAME;
@@ -2787,6 +2970,147 @@ inline void mark_as_null_row(TABLE *table)
bool is_simple_order(ORDER *order);
+class Open_tables_backup;
+
+/** Transaction Registry Table (TRT)
+
+ This table 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,
+ TRT is used to get their actual timestamps. */
+class TR_table: public TABLE_LIST
+{
+ THD *thd;
+ Open_tables_backup *open_tables_backup;
+
+public:
+ enum field_id_t {
+ FLD_TRX_ID= 0,
+ FLD_COMMIT_ID,
+ FLD_BEGIN_TS,
+ FLD_COMMIT_TS,
+ FLD_ISO_LEVEL,
+ FIELD_COUNT
+ };
+ /**
+ @param[in,out] Thread handle
+ @param[in] Current transaction is read-write.
+ */
+ TR_table(THD *_thd, bool rw= false);
+ /**
+ Opens a transaction_registry table.
+
+ @retval true on error, false otherwise.
+ */
+ bool open();
+ ~TR_table();
+ /**
+ @retval current thd
+ */
+ THD *get_thd() const { return thd; }
+ /**
+ Stores value to internal transaction_registry TABLE object.
+
+ @param[in] field number in a TABLE
+ @param[in] value to store
+ */
+ void store(uint field_id, ulonglong val);
+ /**
+ Stores value to internal transaction_registry TABLE object.
+
+ @param[in] field number in a TABLE
+ @param[in] value to store
+ */
+ void store(uint field_id, timeval ts);
+ /**
+ Update the transaction_registry right before commit.
+ @param start_id transaction identifier at start
+ @param end_id transaction identifier at commit
+
+ @retval false on success
+ @retval true on error (the transaction must be rolled back)
+ */
+ bool update(ulonglong start_id, ulonglong end_id);
+ // return true if found; false if not found or error
+ bool query(ulonglong trx_id);
+ /**
+ Gets a row from transaction_registry with the closest commit_timestamp to
+ first argument. We can search for a value which a lesser or greater than
+ first argument. Also loads a row into an internal TABLE object.
+
+ @param[in] timestamp
+ @param[in] true if we search for a lesser timestamp, false if greater
+ @retval true if exists, false it not exists or an error occured
+ */
+ bool query(MYSQL_TIME &commit_time, bool backwards);
+ /**
+ Checks whether transaction1 sees transaction0.
+
+ @param[out] true if transaction1 sees transaction0, undefined on error and
+ when transaction1=transaction0 and false otherwise
+ @param[in] transaction_id of transaction1
+ @param[in] transaction_id of transaction0
+ @param[in] commit time of transaction1 or 0 if we want it to be queried
+ @param[in] isolation level (from handler.h) of transaction1
+ @param[in] commit time of transaction0 or 0 if we want it to be queried
+ @retval true on error, false otherwise
+ */
+ bool query_sees(bool &result, ulonglong trx_id1, ulonglong trx_id0,
+ ulonglong commit_id1= 0,
+ enum_tx_isolation iso_level1= ISO_READ_UNCOMMITTED,
+ ulonglong commit_id0= 0);
+
+ /**
+ @retval transaction isolation level of a row from internal TABLE object.
+ */
+ enum_tx_isolation iso_level() const;
+ /**
+ Stores transactioin isolation level to internal TABLE object.
+ */
+ void store_iso_level(enum_tx_isolation iso_level)
+ {
+ DBUG_ASSERT(iso_level <= ISO_SERIALIZABLE);
+ store(FLD_ISO_LEVEL, iso_level + 1);
+ }
+
+ /**
+ Writes a message to MariaDB log about incorrect transaction_registry schema.
+
+ @param[in] a message explained what's incorrect in schema
+ */
+ void warn_schema_incorrect(const char *reason);
+ /**
+ Checks whether transaction_registry table has a correct schema.
+
+ @retval true if schema is incorrect and false otherwise
+ */
+ bool check();
+
+ TABLE * operator-> () const
+ {
+ return table;
+ }
+ Field * operator[] (uint field_id) const
+ {
+ DBUG_ASSERT(field_id < FIELD_COUNT);
+ return table->field[field_id];
+ }
+ operator bool () const
+ {
+ return table;
+ }
+ bool operator== (const TABLE_LIST &subj) const
+ {
+ if (0 != strcmp(db, subj.db))
+ return false;
+ return (0 == strcmp(table_name, subj.table_name));
+ }
+ bool operator!= (const TABLE_LIST &subj) const
+ {
+ return !(*this == subj);
+ }
+};
+
#endif /* MYSQL_CLIENT */
#endif /* TABLE_INCLUDED */
diff --git a/sql/threadpool_common.cc b/sql/threadpool_common.cc
index fb9e61f9a05..e5ac4b49a2a 100644
--- a/sql/threadpool_common.cc
+++ b/sql/threadpool_common.cc
@@ -84,17 +84,13 @@ struct Worker_thread_context
void save()
{
-#ifdef HAVE_PSI_THREAD_INTERFACE
- psi_thread = PSI_THREAD_CALL(get_thread)();
-#endif
+ psi_thread = PSI_CALL_get_thread();
mysys_var= (st_my_thread_var *)pthread_getspecific(THR_KEY_mysys);
}
void restore()
{
-#ifdef HAVE_PSI_THREAD_INTERFACE
- PSI_THREAD_CALL(set_thread)(psi_thread);
-#endif
+ PSI_CALL_set_thread(psi_thread);
pthread_setspecific(THR_KEY_mysys,mysys_var);
pthread_setspecific(THR_THD, 0);
}
@@ -144,9 +140,7 @@ static void thread_attach(THD* thd)
pthread_setspecific(THR_KEY_mysys,thd->mysys_var);
thd->thread_stack=(char*)&thd;
thd->store_globals();
-#ifdef HAVE_PSI_THREAD_INTERFACE
- PSI_THREAD_CALL(set_thread)(thd->event_scheduler.m_psi);
-#endif
+ PSI_CALL_set_thread(thd->event_scheduler.m_psi);
mysql_socket_set_thread_owner(thd->net.vio->mysql_socket);
}
@@ -254,10 +248,8 @@ static THD* threadpool_add_connection(CONNECT *connect, void *scheduler_data)
thd->event_scheduler.data= scheduler_data;
/* Create new PSI thread for use with the THD. */
-#ifdef HAVE_PSI_THREAD_INTERFACE
thd->event_scheduler.m_psi=
- PSI_THREAD_CALL(new_thread)(key_thread_one_connection, thd, thd->thread_id);
-#endif
+ PSI_CALL_new_thread(key_thread_one_connection, thd, thd->thread_id);
/* Login. */
diff --git a/sql/tztime.h b/sql/tztime.h
index eb7d85c48b2..7ffc36011e1 100644
--- a/sql/tztime.h
+++ b/sql/tztime.h
@@ -89,6 +89,5 @@ extern my_time_t sec_since_epoch_TIME(MYSQL_TIME *t);
static const int MY_TZ_TABLES_COUNT= 4;
-
#endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */
#endif /* TZTIME_INCLUDED */
diff --git a/sql/unireg.cc b/sql/unireg.cc
index a0f42f68bf0..251d48f2d96 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -87,21 +87,68 @@ static uchar *extra2_write(uchar *pos, enum extra2_frm_value_type type,
return extra2_write(pos, type, reinterpret_cast<LEX_CSTRING *>(str));
}
-static uchar *extra2_write_additional_field_properties(uchar *pos,
- int number_of_fields,List_iterator<Create_field> * it)
+static uchar *extra2_write_field_properties(uchar *pos,
+ List<Create_field> &create_fields)
{
- *pos++=EXTRA2_FIELD_FLAGS;
+ List_iterator<Create_field> it(create_fields);
+ *pos++= EXTRA2_FIELD_FLAGS;
/*
always first 2 for field visibility
*/
- pos= extra2_write_len(pos, number_of_fields);
- Create_field *cf;
- while((cf=(*it)++))
- *pos++= cf->field_visibility;
- it->rewind();
+ pos= extra2_write_len(pos, create_fields.elements);
+ while (Create_field *cf= it++)
+ {
+ uchar flags= cf->invisible;
+ if (cf->flags & VERS_UPDATE_UNVERSIONED_FLAG)
+ flags|= VERS_OPTIMIZED_UPDATE;
+ *pos++= flags;
+ }
return pos;
}
+static const bool ROW_START = true;
+static const bool ROW_END = false;
+
+static inline
+uint16
+vers_get_field(HA_CREATE_INFO *create_info, List<Create_field> &create_fields, bool row_start)
+{
+ DBUG_ASSERT(create_info->versioned());
+
+ List_iterator<Create_field> it(create_fields);
+ Create_field *sql_field = NULL;
+
+ const LString_i 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)
+ {
+ if (row_field == sql_field->field_name)
+ {
+ DBUG_ASSERT(field_no <= uint16(~0U));
+ return uint16(field_no);
+ }
+ }
+
+ DBUG_ASSERT(0); /* Not Reachable */
+ return 0;
+}
+
+static inline
+bool has_extra2_field_flags(List<Create_field> &create_fields)
+{
+ List_iterator<Create_field> it(create_fields);
+ while (Create_field *f= it++)
+ {
+ if (f->invisible)
+ return true;
+ if (f->flags & VERS_UPDATE_UNVERSIONED_FLAG)
+ return true;
+ }
+ return false;
+}
+
/**
Create a frm (table definition) file
@@ -136,19 +183,6 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table,
StringBuffer<MAX_FIELD_WIDTH> vcols;
DBUG_ENTER("build_frm_image");
- List_iterator<Create_field> it(create_fields);
- Create_field *field;
- bool have_additional_field_properties= false;
- while ((field=it++))
- {
- if (field->field_visibility != NOT_INVISIBLE)
- {
- have_additional_field_properties= true;
- break;
- }
- }
- it.rewind();
-
/* If fixed row records, we need one bit to check for deleted rows */
if (!(create_info->table_options & HA_OPTION_PACK_RECORD))
create_info->null_bits++;
@@ -246,9 +280,23 @@ 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(have_additional_field_properties)
- extra2_size+=1 + (create_fields.elements > 255 ? 3 : 1) +
+
+ if (create_info->versioned())
+ {
+ 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_)
+ {
+ extra2_size+= 1 + (create_fields.elements > 255 ? 3 : 1) +
create_fields.elements;
+ }
key_buff_length= uint4korr(fileinfo+47);
@@ -304,8 +352,27 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table,
pos+= gis_field_options_image(pos, create_fields);
}
#endif /*HAVE_SPATIAL*/
- if (have_additional_field_properties)
- pos=extra2_write_additional_field_properties(pos,create_fields.elements,&it);
+
+ if (create_info->versioned())
+ {
+ *pos++= EXTRA2_PERIOD_FOR_SYSTEM_TIME;
+ *pos++= 2 * sizeof(uint16);
+ int2store(pos, vers_get_field(create_info, create_fields, ROW_START));
+ pos+= sizeof(uint16);
+ int2store(pos, vers_get_field(create_info, create_fields, ROW_END));
+ pos+= sizeof(uint16);
+ }
+
+ if (create_info->vtmd())
+ {
+ *pos++= EXTRA2_VTMD;
+ *pos++= 1;
+ *pos++= 1;
+ }
+
+ if (has_extra2_field_flags_)
+ pos= extra2_write_field_properties(pos, create_fields);
+
int4store(pos, filepos); // end of the extra2 segment
pos+= 4;
@@ -991,7 +1058,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;
diff --git a/sql/unireg.h b/sql/unireg.h
index 36f985ee1bb..6d49b1d5092 100644
--- a/sql/unireg.h
+++ b/sql/unireg.h
@@ -172,6 +172,8 @@ enum extra2_frm_value_type {
EXTRA2_TABLEDEF_VERSION=0,
EXTRA2_DEFAULT_PART_ENGINE=1,
EXTRA2_GIS=2,
+ EXTRA2_PERIOD_FOR_SYSTEM_TIME=4,
+ EXTRA2_VTMD=8,
#define EXTRA2_ENGINE_IMPORTANT 128
@@ -179,6 +181,11 @@ enum extra2_frm_value_type {
EXTRA2_FIELD_FLAGS=129
};
+enum extra2_field_flags {
+ VERS_OPTIMIZED_UPDATE= 1 << INVISIBLE_MAX_BITS,
+ VERS_HIDDEN= 1 << (INVISIBLE_MAX_BITS + 1),
+};
+
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/sql/vers_string.h b/sql/vers_string.h
new file mode 100644
index 00000000000..6d501e1b81c
--- /dev/null
+++ b/sql/vers_string.h
@@ -0,0 +1,133 @@
+#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 <CHARSET_INFO* &CS= system_charset_info>
+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<files_charset_info> Compare_fs;
+typedef Compare_my_strcasecmp<table_alias_charset> Compare_t;
+
+template <class Storage= LEX_CSTRING>
+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;
+ }
+ const LEX_STRING& lex_string() const
+ {
+ return *(LEX_STRING *)this;
+ }
+};
+
+template <class Compare= Compare_strncmp, class Storage= LEX_STRING_u<> >
+struct XString : public Storage
+{
+public:
+ XString() {}
+ XString(const char *_str, size_t _len) :
+ Storage(_str, _len, Compare::charset())
+ {
+ }
+ XString(const LEX_STRING src) :
+ Storage(src.str, src.length, Compare::charset())
+ {
+ }
+ XString(const LEX_CSTRING src) :
+ Storage(src.str, src.length, Compare::charset())
+ {
+ }
+ XString(const char *_str) :
+ Storage(_str, strlen(_str), Compare::charset())
+ {
+ }
+ 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<char *>(this->ptr());
+ res.length= this->length();
+ return res;
+ }
+ operator bool () const
+ {
+ return Storage::ptr() != NULL;
+ }
+};
+
+typedef XString<> LString;
+typedef XString<Compare_fs> LString_fs;
+typedef XString<Compare_my_strcasecmp<> > LString_i;
+
+typedef XString<Compare_strncmp, String> SString;
+typedef XString<Compare_fs, String> SString_fs;
+typedef XString<Compare_t, String> 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
new file mode 100644
index 00000000000..b9b93856ea6
--- /dev/null
+++ b/sql/vers_utils.h
@@ -0,0 +1,81 @@
+#ifndef VERS_UTILS_INCLUDED
+#define VERS_UTILS_INCLUDED
+
+#include "table.h"
+#include "sql_class.h"
+#include "vers_string.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);
+ MDL_request protection_request;
+ if (thd->global_read_lock.can_acquire_protection())
+ {
+ error= true;
+ return;
+ }
+ protection_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE,
+ MDL_EXPLICIT);
+ error= thd->mdl_context.acquire_lock(&protection_request, thd->variables.lock_wait_timeout);
+ if (error)
+ return;
+
+ 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);
+ thd->mdl_context.release_lock(protection_request.ticket);
+ }
+ ~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; }
+};
+
+
+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..566638bbc46
--- /dev/null
+++ b/sql/vtmd.cc
@@ -0,0 +1,695 @@
+#include "vtmd.h"
+#include "sql_base.h"
+#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"
+#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"));
+
+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->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 row_end, bool &found)
+{
+ int error;
+ key_buf_t key;
+ found= false;
+
+ DBUG_ASSERT(vtmd.table);
+
+ if (key.allocate(vtmd.table->s->max_unique_length))
+ return true;
+
+ DBUG_ASSERT(row_end);
+ vtmd.table->vers_end_field()->set_notnull();
+ vtmd.table->vers_end_field()->store(row_end, true);
+ key_copy(key, vtmd.table->record[0], vtmd.table->key_info + IDX_TRX_END, 0);
+
+ error= vtmd.table->file->ha_index_read_idx_map(vtmd.table->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.table->file->print_error(error, MYF(0));
+ return true;
+ }
+
+ 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)
+{
+ bool result= true;
+ bool found= false;
+ bool created;
+ int error;
+ size_t an_len= 0;
+ 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 (open(thd, local_da, &created))
+ goto open_error;
+
+ if (!vtmd.table->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.table->file->extra(HA_EXTRA_MARK_AS_LOG_TABLE)))
+ {
+ vtmd.table->file->print_error(error, MYF(0));
+ goto quit;
+ }
+
+ /* Honor next number columns if present */
+ vtmd.table->next_number_field= vtmd.table->found_next_number_field;
+
+ if (vtmd.table->s->fields != FIELD_COUNT)
+ {
+ my_printf_error(ER_VERS_VTMD_ERROR, "`%s.%s` unexpected fields count: %d", MYF(0),
+ 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.table->field[FLD_ARCHIVE_NAME]->store(archive_name, an_len, table_alias_charset);
+ vtmd.table->field[FLD_ARCHIVE_NAME]->set_notnull();
+ }
+ else
+ {
+ vtmd.table->field[FLD_ARCHIVE_NAME]->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.table->s->db.str, vtmd.table->s->table_name.str);
+ goto quit;
+ }
+ vtmd.table->mark_columns_needed_for_update(); // not needed?
+ if (archive_name)
+ {
+ vtmd.table->vers_write= false;
+ error= vtmd.table->file->ha_update_row(vtmd.table->record[1], vtmd.table->record[0]);
+ vtmd.table->vers_write= true;
+
+ if (!error)
+ {
+ if (thd->lex->sql_command == SQLCOM_DROP_TABLE)
+ {
+ error= vtmd.table->file->ha_delete_row(vtmd.table->record[0]);
+ }
+ else
+ {
+ DBUG_ASSERT(thd->lex->sql_command == SQLCOM_ALTER_TABLE);
+ ulonglong row_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;
+
+ DBUG_ASSERT(an_len);
+ while (true)
+ { // fill archive_name of last sequential renames
+ bool found;
+ if (find_record(row_end, found))
+ goto quit;
+ if (!found || !vtmd.table->field[FLD_ARCHIVE_NAME]->is_null())
+ break;
+
+ 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->vers_write= false;
+ error= vtmd.table->file->ha_update_row(vtmd.table->record[1], vtmd.table->record[0]);
+ vtmd.table->vers_write= true;
+ if (error)
+ goto err;
+ row_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.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.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.table->file->print_error(error, MYF(0));
+ }
+ else
+ result= local_da.is_error();
+ }
+
+quit:
+ if (!result && vtmd.table->file->ht->prepare_commit_versioned)
+ {
+ DBUG_ASSERT(use_transaction_registry); // FIXME: disable survival mode while TRT is disabled
+ TR_table trt(thd, true);
+ ulonglong trx_start_id= 0;
+ ulonglong trx_end_id= vtmd.table->file->ht->prepare_commit_versioned(thd, &trx_start_id);
+ result= trx_end_id && trt.update(trx_start_id, trx_end_id);
+ }
+
+ 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)
+{
+ vtmd.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;
+
+ TABLE *res= open_log_table(thd, &vtmd, &open_tables_backup);
+ if (!res)
+ return true;
+
+ if (key.allocate(vtmd.table->key_info[IDX_ARCHIVE_NAME].key_length))
+ {
+ close_log_table(thd, &open_tables_backup);
+ return true;
+ }
+
+ if ((error= vtmd.table->file->ha_start_keyread(IDX_ARCHIVE_NAME)))
+ goto err;
+ end_keyread= true;
+
+ if ((error= vtmd.table->file->ha_index_init(IDX_ARCHIVE_NAME, true)))
+ goto err;
+ index_end= true;
+
+ error= vtmd.table->file->ha_index_first(vtmd.table->record[0]);
+ while (!error)
+ {
+ if (!vtmd.table->field[FLD_ARCHIVE_NAME]->is_null())
+ {
+ vtmd.table->field[FLD_ARCHIVE_NAME]->val_str(&archive);
+ key_copy(key,
+ vtmd.table->record[0],
+ &vtmd.table->key_info[IDX_ARCHIVE_NAME],
+ vtmd.table->key_info[IDX_ARCHIVE_NAME].key_length,
+ false);
+ error= vtmd.table->file->ha_index_read_map(
+ vtmd.table->record[0],
+ key,
+ 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.table->file->ha_index_next(vtmd.table->record[0]);
+ }
+ }
+ else
+ {
+ archive.length(0);
+ error= vtmd.table->file->ha_index_next(vtmd.table->record[0]);
+ }
+ }
+
+ if (error && error != HA_ERR_END_OF_FILE)
+ {
+err:
+ vtmd.table->file->print_error(error, MYF(0));
+ rc= true;
+ }
+
+ if (index_end)
+ vtmd.table->file->ha_index_end();
+ if (end_keyread)
+ vtmd.table->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)) != LString_fs(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);
+ 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,
+ 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);
+}
+
+bool
+VTMD_table::find_archive_name(THD *thd, String &out)
+{
+ READ_RECORD info;
+ int error;
+ SQL_SELECT *select= NULL;
+ COND *conds= NULL;
+ List<TABLE_LIST> dummy;
+ SELECT_LEX &select_lex= thd->lex->select_lex;
+
+ 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 = 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= select_lex.vers_setup_conds(thd, &vtmd, &conds)) ||
+ (error= setup_conds(thd, &vtmd, dummy, &conds)))
+ goto err;
+
+ select= make_select(vtmd.table, 0, 0, conds, NULL, 0, &error);
+ if (error)
+ goto loc_err;
+
+ 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()) && !thd->killed && !thd->is_error())
+ {
+ if (!select || select->skip_record(thd) > 0)
+ {
+ vtmd.table->field[FLD_ARCHIVE_NAME]->val_str(&out);
+ break;
+ }
+ }
+
+ 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;
+ vtmd.table->map= map;
+ close_log_table(thd, &open_tables_backup);
+ DBUG_ASSERT(!error || local_da.is_error());
+ return error;
+}
+
+static
+bool
+get_vtmd_tables(THD *thd, const char *db,
+ size_t db_length, Dynamic_array<LEX_CSTRING *> &table_names)
+{
+ LOOKUP_FIELD_VALUES lookup_field_values= {
+ {db, db_length}, {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, const char *db, size_t db_length,
+ Dynamic_array<String> &result)
+{
+ Dynamic_array<LEX_CSTRING *> vtmd_tables;
+ 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_CSTRING table_name= *vtmd_tables.at(i);
+
+ Open_tables_backup open_tables_backup;
+ TABLE_LIST table_list;
+ 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 || !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;
+ SQL_SELECT *sql_select= make_select(table, 0, 0, NULL, NULL, 0, &error);
+ if (error)
+ {
+ 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()))
+ {
+ 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);
+ }
+ // check for EOF
+ if (!thd->is_error())
+ error= 0;
+
+ end_read_record(&read_record);
+ delete sql_select;
+ close_log_table(thd, &open_tables_backup);
+ }
+
+ 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);
+ 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->m_sp);
+ thd->spcont->m_sp->set_sp_cache_version(0);
+ }
+ return false;
+}
diff --git a/sql/vtmd.h b/sql/vtmd.h
new file mode 100644
index 00000000000..29657ece0f4
--- /dev/null
+++ b/sql/vtmd.h
@@ -0,0 +1,187 @@
+#ifndef VTMD_INCLUDED
+#define VTMD_INCLUDED
+
+#include <mysqld_error.h>
+
+#include "mariadb.h"
+#include "sql_priv.h"
+
+#include "my_sys.h"
+#include "table.h"
+#include "unireg.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<uchar *>(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<uchar *>(buf);
+ }
+};
+
+class THD;
+
+class VTMD_table
+{
+ Open_tables_backup open_tables_backup;
+
+protected:
+ TABLE_LIST vtmd;
+ 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) :
+ about(_about)
+ {
+ vtmd.table= NULL;
+ }
+
+ bool create(THD *thd);
+ bool find_record(ulonglong row_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)
+ {
+ archive_name(thd, about.table_name, new_name, new_name_size);
+ }
+
+ bool find_archive_name(THD *thd, String &out);
+ static bool get_archive_tables(THD *thd, const char *db, size_t db_length,
+ Dynamic_array<String> &result);
+};
+
+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/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc
index d0aa841b25a..132e7960541 100644
--- a/storage/innobase/dict/dict0mem.cc
+++ b/storage/innobase/dict/dict0mem.cc
@@ -311,6 +311,16 @@ dict_mem_table_add_col(
col = dict_table_get_nth_col(table, i);
dict_mem_fill_column_struct(col, i, mtype, prtype, len);
+
+ switch (prtype & DATA_VERSIONED) {
+ case DATA_VERS_START:
+ ut_ad(!table->vers_start);
+ table->vers_start = i;
+ break;
+ case DATA_VERS_END:
+ ut_ad(!table->vers_end);
+ table->vers_end = i;
+ }
}
/** Adds a virtual column definition to a table.
@@ -1464,3 +1474,73 @@ void dict_table_t::rollback_instant(unsigned n)
field->name = sys + sizeof "DB_ROW_ID\0DB_TRX_ID";
field->col = dict_table_get_sys_col(this, DATA_ROLL_PTR);
}
+
+
+/** Check if record in clustered index is historical row.
+@param[in] rec clustered row
+@param[in] offsets offsets
+@return true if row is historical */
+bool
+dict_index_t::vers_history_row(
+ const rec_t* rec,
+ const ulint* offsets)
+{
+ ut_a(is_clust());
+
+ ulint len;
+ dict_col_t& col= table->cols[table->vers_end];
+ ut_ad(col.vers_sys_end());
+ ulint nfield = dict_col_get_clust_pos(&col, this);
+ const byte *data = rec_get_nth_field(rec, offsets, nfield, &len);
+ if (col.mtype == DATA_FIXBINARY) {
+ ut_ad(len == sizeof timestamp_max_bytes);
+ return 0 != memcmp(data, timestamp_max_bytes, len);
+ } else {
+ ut_ad(col.mtype == DATA_INT);
+ ut_ad(len == sizeof trx_id_max_bytes);
+ return 0 != memcmp(data, trx_id_max_bytes, len);
+ }
+ ut_ad(0);
+ return false;
+}
+
+/** Check if record in secondary index is historical row.
+@param[in] rec record in a secondary index
+@param[out] history_row true if row is historical
+@return true on error */
+bool
+dict_index_t::vers_history_row(
+ const rec_t* rec,
+ bool &history_row)
+{
+ ut_ad(!is_clust());
+
+ bool error = false;
+ mem_heap_t* heap = NULL;
+ dict_index_t* clust_index = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ rec_offs_init(offsets_);
+
+ mtr_t mtr;
+ mtr.start();
+
+ rec_t* clust_rec =
+ row_get_clust_rec(BTR_SEARCH_LEAF, rec, this, &clust_index, &mtr);
+ if (clust_rec) {
+ offsets = rec_get_offsets(clust_rec, clust_index, offsets, true,
+ ULINT_UNDEFINED, &heap);
+
+ history_row = clust_index->vers_history_row(clust_rec, offsets);
+ } else {
+ ib::error() << "foreign constraints: secondary index is out of "
+ "sync";
+ ut_ad(!"secondary index is out of sync");
+ error = true;
+ }
+ mtr.commit();
+ if (heap) {
+ mem_heap_free(heap);
+ }
+ return(error);
+}
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 53aab576202..e8b1ea7350e 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -3623,6 +3623,38 @@ static const char* ha_innobase_exts[] = {
NullS
};
+/** Determine if system-versioned data was modified by the transaction.
+@param[in,out] thd current session
+@param[out] trx_id transaction start ID
+@return transaction commit ID
+@retval 0 if no system-versioned data was affected by the transaction */
+static ulonglong innodb_prepare_commit_versioned(THD* thd, ulonglong *trx_id)
+{
+ if (const trx_t* trx = thd_to_trx(thd)) {
+ *trx_id = trx->id;
+
+ for (trx_mod_tables_t::const_iterator t
+ = trx->mod_tables.begin();
+ t != trx->mod_tables.end(); t++) {
+ if (t->second.is_trx_versioned()) {
+ DBUG_ASSERT(t->first->versioned());
+ DBUG_ASSERT(trx->rsegs.m_redo.rseg);
+
+ mutex_enter(&trx_sys->mutex);
+ trx_id_t commit_id = trx_sys_get_new_trx_id();
+ mutex_exit(&trx_sys->mutex);
+
+ return commit_id;
+ }
+ }
+
+ return 0;
+ }
+
+ *trx_id = 0;
+ return 0;
+}
+
/*********************************************************************//**
Opens an InnoDB database.
@return 0 on success, 1 on failure */
@@ -3675,7 +3707,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_NATIVE_SYS_VERSIONING;
#ifdef WITH_WSREP
innobase_hton->abort_transaction=wsrep_abort_transaction;
@@ -3690,6 +3722,10 @@ innobase_init(
innobase_hton->table_options = innodb_table_option_list;
+ /* System Versioning */
+ innobase_hton->prepare_commit_versioned
+ = innodb_prepare_commit_versioned;
+
innodb_remember_check_sysvar_funcs();
ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR);
@@ -6520,7 +6556,11 @@ no_such_table:
}
}
- info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
+ if (table && m_prebuilt->table) {
+ ut_ad(table->versioned() == m_prebuilt->table->versioned());
+ }
+
+ info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST | HA_STATUS_OPEN);
DBUG_RETURN(0);
}
@@ -7741,6 +7781,7 @@ ha_innobase::build_template(
index = whole_row ? clust_index : m_prebuilt->index;
+ m_prebuilt->versioned_write = table->versioned_write(VERS_TRX_ID);
m_prebuilt->need_to_access_clustered = (index == clust_index);
/* Either m_prebuilt->index should be a secondary index, or it
@@ -8163,6 +8204,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()) {
@@ -8363,8 +8405,11 @@ no_commit:
innobase_srv_conc_enter_innodb(m_prebuilt);
+ vers_set_fields = table->versioned_write(VERS_TRX_ID) ?
+ 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");
@@ -9137,12 +9182,34 @@ ha_innobase::update_row(
DB_FORCED_ABORT, 0, m_user_thd));
}
- /* This is not a delete */
- m_prebuilt->upd_node->is_delete = FALSE;
+ {
+ const bool vers_set_fields = m_prebuilt->versioned_write
+ && m_prebuilt->upd_node->update->affects_versioned();
+ const bool vers_ins_row = vers_set_fields
+ && (table->s->vtmd
+ || thd_sql_command(m_user_thd) != SQLCOM_ALTER_TABLE);
+
+ /* This is not a delete */
+ m_prebuilt->upd_node->is_delete =
+ (vers_set_fields && !vers_ins_row) ||
+ (thd_sql_command(m_user_thd) == SQLCOM_DELETE &&
+ table->versioned(VERS_TIMESTAMP))
+ ? VERSIONED_DELETE
+ : NO_DELETE;
- innobase_srv_conc_enter_innodb(m_prebuilt);
+ innobase_srv_conc_enter_innodb(m_prebuilt);
- error = row_update_for_mysql(m_prebuilt);
+ error = row_update_for_mysql(m_prebuilt);
+
+ if (error == DB_SUCCESS && vers_ins_row
+ /* Multiple UPDATE of same rows in single transaction create
+ historical rows only once. */
+ && trx->id != table->vers_start_id()) {
+ error = row_insert_for_mysql((byte*) old_row,
+ m_prebuilt,
+ ROW_INS_HISTORICAL);
+ }
+ }
if (error == DB_SUCCESS && autoinc) {
/* A value for an AUTO_INCREMENT column
@@ -9252,8 +9319,10 @@ ha_innobase::delete_row(
}
/* This is a delete */
-
- m_prebuilt->upd_node->is_delete = TRUE;
+ m_prebuilt->upd_node->is_delete = table->versioned_write(VERS_TRX_ID)
+ && table->vers_end_field()->is_max()
+ ? VERSIONED_DELETE
+ : PLAIN_DELETE;
innobase_srv_conc_enter_innodb(m_prebuilt);
@@ -11347,6 +11416,18 @@ create_table_info_t::create_table_def()
bool is_stored = false;
Field* field = m_form->field[i];
+ ulint vers_row = 0;
+
+ if (m_form->versioned()) {
+ if (i == m_form->s->row_start_field) {
+ vers_row = DATA_VERS_START;
+ } else if (i == m_form->s->row_end_field) {
+ vers_row = DATA_VERS_END;
+ } else if (!(field->flags
+ & VERS_UPDATE_UNVERSIONED_FLAG)) {
+ vers_row = DATA_VERSIONED;
+ }
+ }
col_type = get_innobase_type_from_mysql_type(
&unsigned_type, field);
@@ -11437,7 +11518,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,
charset_no),
col_len);
} else {
@@ -11447,6 +11529,7 @@ err_col:
(ulint) field->type()
| nulls_allowed | unsigned_type
| binary_type | long_true_varchar
+ | vers_row
| is_virtual,
charset_no),
col_len, i, 0);
@@ -14361,7 +14444,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++;
}
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index 7d4b15fc40e..a8cb749c5b1 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -87,6 +87,9 @@ static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_ALTER_REBUILD
/*
| Alter_inplace_info::ALTER_STORED_COLUMN_TYPE
*/
+ | Alter_inplace_info::ALTER_COLUMN_UNVERSIONED
+ | Alter_inplace_info::ALTER_ADD_SYSTEM_VERSIONING
+ | Alter_inplace_info::ALTER_DROP_SYSTEM_VERSIONING
;
/** Operations that require changes to data */
@@ -631,6 +634,11 @@ instant_alter_column_possible(
const Alter_inplace_info* ha_alter_info,
const TABLE* table)
{
+ // Making table system-versioned instantly is not implemented yet.
+ if (ha_alter_info->handler_flags & Alter_inplace_info::ALTER_ADD_SYSTEM_VERSIONING) {
+ return false;
+ }
+
if (~ha_alter_info->handler_flags
& Alter_inplace_info::ADD_STORED_BASE_COLUMN) {
return false;
@@ -688,6 +696,13 @@ ha_innobase::check_if_supported_inplace_alter(
{
DBUG_ENTER("check_if_supported_inplace_alter");
+ if ((table->versioned(VERS_TIMESTAMP) || altered_table->versioned(VERS_TIMESTAMP))
+ && innobase_need_rebuild(ha_alter_info, table)) {
+ ha_alter_info->unsupported_reason =
+ innobase_get_err_msg(ER_VERS_INPLACE_NOT_IMPLEMENTED);
+ DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+ }
+
/* Before 10.2.2 information about virtual columns was not stored in
system tables. We need to do a full alter to rebuild proper 10.2.2+
metadata with the information about virtual columns */
@@ -1216,6 +1231,14 @@ next_column:
}
}
+ // FIXME: implement Online DDL for system-versioned tables
+ if ((table->versioned(VERS_TRX_ID) || altered_table->versioned(VERS_TRX_ID))
+ && innobase_need_rebuild(ha_alter_info, table)) {
+ ha_alter_info->unsupported_reason =
+ innobase_get_err_msg(ER_VERS_INPLACE_NOT_IMPLEMENTED);
+ online = false;
+ }
+
DBUG_RETURN(online
? HA_ALTER_INPLACE_NO_LOCK_AFTER_PREPARE
: HA_ALTER_INPLACE_SHARED_LOCK_AFTER_PREPARE);
@@ -4972,6 +4995,18 @@ new_clustered_failed:
field_type |= DATA_UNSIGNED;
}
+ if (altered_table->versioned()) {
+ if (i == altered_table->s->row_start_field) {
+ field_type |= DATA_VERS_START;
+ } else if (i ==
+ altered_table->s->row_end_field) {
+ field_type |= DATA_VERS_END;
+ } else if (!(field->flags
+ & VERS_UPDATE_UNVERSIONED_FLAG)) {
+ field_type |= DATA_VERSIONED;
+ }
+ }
+
if (dtype_is_string_type(col_type)) {
charset_no = (ulint) field->charset()->number;
@@ -7070,7 +7105,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);
#ifndef DBUG_OFF
oom:
diff --git a/storage/innobase/include/data0data.h b/storage/innobase/include/data0data.h
index a0b3059ad40..d3361ad8b3b 100644
--- a/storage/innobase/include/data0data.h
+++ b/storage/innobase/include/data0data.h
@@ -591,6 +591,22 @@ struct dfield_t{
@param[in,out] heap memory heap in which the clone will be created
@return the cloned object */
dfield_t* clone(mem_heap_t* heap) const;
+
+ /** @return system field indicates history row */
+ bool vers_history_row() const
+ {
+ ut_ad(type.vers_sys_end());
+ if (type.mtype == DATA_FIXBINARY) {
+ ut_ad(len == sizeof timestamp_max_bytes);
+ return 0 != memcmp(data, timestamp_max_bytes, len);
+ } else {
+ ut_ad(type.mtype == DATA_INT);
+ ut_ad(len == sizeof trx_id_max_bytes);
+ return 0 != memcmp(data, trx_id_max_bytes, len);
+ }
+ ut_ad(0);
+ return false;
+ }
};
/** Structure for an SQL data tuple of fields (logical record) */
diff --git a/storage/innobase/include/data0type.h b/storage/innobase/include/data0type.h
index bd2a15fe881..8dab756c7a5 100644
--- a/storage/innobase/include/data0type.h
+++ b/storage/innobase/include/data0type.h
@@ -189,6 +189,12 @@ be less than 256 */
for shorter VARCHARs MySQL uses only 1 byte */
#define DATA_VIRTUAL 8192U /* Virtual column */
+/** System Versioning */
+#define DATA_VERS_START 16384U /* start system field */
+#define DATA_VERS_END 32768U /* end system field */
+/** system-versioned user data column */
+#define DATA_VERSIONED (DATA_VERS_START|DATA_VERS_END)
+
/** Check whether locking is disabled (never). */
#define dict_table_is_locking_disabled(table) false
@@ -554,6 +560,21 @@ struct dtype_t{
DATA_MBMINMAXLEN(mbminlen,mbmaxlen);
mbminlen=DATA_MBMINLEN(mbminmaxlen);
mbmaxlen=DATA_MBMINLEN(mbminmaxlen) */
+
+ /** @return whether this is system field */
+ bool vers_sys_field() const { return prtype & DATA_VERSIONED; }
+ /** @return whether this is system versioned user field */
+ bool is_versioned() const { return !(~prtype & DATA_VERSIONED); }
+ /** @return whether this is the system field start */
+ bool vers_sys_start() const
+ {
+ return (prtype & DATA_VERSIONED) == DATA_VERS_START;
+ }
+ /** @return whether this is the system field end */
+ bool vers_sys_end() const
+ {
+ return (prtype & DATA_VERSIONED) == DATA_VERS_END;
+ }
};
#include "data0type.ic"
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index 726a98a2984..8c5a33312de 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -652,6 +652,22 @@ struct dict_col_t{
bool is_virtual() const { return prtype & DATA_VIRTUAL; }
/** @return whether NULL is an allowed value for this column */
bool is_nullable() const { return !(prtype & DATA_NOT_NULL); }
+
+ /** @return whether this is system field */
+ bool vers_sys_field() const { return prtype & DATA_VERSIONED; }
+ /** @return whether this is system versioned */
+ bool is_versioned() const { return !(~prtype & DATA_VERSIONED); }
+ /** @return whether this is the system version start */
+ bool vers_sys_start() const
+ {
+ return (prtype & DATA_VERSIONED) == DATA_VERS_START;
+ }
+ /** @return whether this is the system version end */
+ bool vers_sys_end() const
+ {
+ return (prtype & DATA_VERSIONED) == DATA_VERS_END;
+ }
+
/** @return whether this is an instantly-added column */
bool is_instant() const
{
@@ -1117,6 +1133,20 @@ struct dict_index_t{
n_core_fields = n_fields;
n_core_null_bytes = UT_BITS_IN_BYTES(n_nullable);
}
+
+ /** Check if record in clustered index is historical row.
+ @param[in] rec clustered row
+ @param[in] offsets offsets
+ @return true if row is historical */
+ bool
+ vers_history_row(const rec_t* rec, const ulint* offsets);
+
+ /** Check if record in secondary index is historical row.
+ @param[in] rec record in a secondary index
+ @param[out] history_row true if row is historical
+ @return true on error */
+ bool
+ vers_history_row(const rec_t* rec, bool &history_row);
};
/** The status of online index creation */
@@ -1512,6 +1542,8 @@ struct dict_table_t {
/** Add the table definition to the data dictionary cache */
void add_to_cache();
+ bool versioned() const { return vers_start || vers_end; }
+
/** Id of the table. */
table_id_t id;
@@ -1625,7 +1657,10 @@ struct dict_table_t {
/** Virtual column names */
const char* v_col_names;
-
+ unsigned vers_start:10;
+ /*!< System Versioning: row start col index */
+ unsigned vers_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/dict0types.h b/storage/innobase/include/dict0types.h
index 27b4cc0e694..6984351cc06 100644
--- a/storage/innobase/include/dict0types.h
+++ b/storage/innobase/include/dict0types.h
@@ -52,6 +52,13 @@ DICT_IBUF_ID_MIN plus the space id */
typedef ib_id_t table_id_t;
typedef ib_id_t index_id_t;
+/** Maximum transaction identifier */
+#define TRX_ID_MAX IB_ID_MAX
+
+/** The bit pattern corresponding to TRX_ID_MAX */
+extern const byte trx_id_max_bytes[8];
+extern const byte timestamp_max_bytes[7];
+
/** Error to ignore when we load table dictionary into memory. However,
the table and index will be marked as "corrupted", and caller will
be responsible to deal with corrupted table or index.
diff --git a/storage/innobase/include/row0ins.h b/storage/innobase/include/row0ins.h
index 8cb3a2f16cd..21e5cd7e9ea 100644
--- a/storage/innobase/include/row0ins.h
+++ b/storage/innobase/include/row0ins.h
@@ -202,6 +202,8 @@ struct ins_node_t{
trx_id_t trx_id; /*!< trx id or the last trx which executed the
node */
byte* trx_id_buf;/* buffer for the trx id sys field in row */
+ byte vers_start_buf[8]; /* Buffers for System Versioning */
+ byte vers_end_buf[8]; /* system fields. */
mem_heap_t* entry_sys_heap;
/* memory heap used as auxiliary storage;
entry_list and sys fields are stored here;
@@ -227,5 +229,4 @@ struct ins_node_t{
#define INS_NODE_ALLOC_ROW_ID 2 /* row id should be allocated */
#define INS_NODE_INSERT_ENTRIES 3 /* index entries should be built and
inserted */
-
#endif
diff --git a/storage/innobase/include/row0merge.h b/storage/innobase/include/row0merge.h
index ca620cbef59..327efb50578 100644
--- a/storage/innobase/include/row0merge.h
+++ b/storage/innobase/include/row0merge.h
@@ -325,6 +325,7 @@ this function and it will be passed to other functions for further accounting.
@param[in] add_v new virtual columns added along with indexes
@param[in] eval_table mysql table used to evaluate virtual column
value, see innobase_get_computed_value().
+@param[in] drop_historical whether to drop historical system rows
@return DB_SUCCESS or error code */
dberr_t
row_merge_build_indexes(
@@ -343,7 +344,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/include/row0mysql.h b/storage/innobase/include/row0mysql.h
index 044e732c22d..2ba23b6e68c 100644
--- a/storage/innobase/include/row0mysql.h
+++ b/storage/innobase/include/row0mysql.h
@@ -235,14 +235,26 @@ row_lock_table_for_mysql(
(ignored if table==NULL) */
MY_ATTRIBUTE((nonnull(1)));
+/** System Versioning: row_insert_for_mysql() modes */
+enum ins_mode_t {
+ /* plain row (without versioning) */
+ ROW_INS_NORMAL = 0,
+ /* row_start = TRX_ID, row_end = MAX */
+ ROW_INS_VERSIONED,
+ /* row_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
+@param[in] ins_mode what row type we're inserting
@return error code or DB_SUCCESS*/
dberr_t
row_insert_for_mysql(
const byte* mysql_rec,
- row_prebuilt_t* prebuilt)
+ row_prebuilt_t* prebuilt,
+ ins_mode_t ins_mode)
MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
@@ -266,7 +278,8 @@ row_get_prebuilt_update_vector(
@param[in,out] prebuilt prebuilt struct in MySQL handle
@return error code or DB_SUCCESS */
dberr_t
-row_update_for_mysql(row_prebuilt_t* prebuilt)
+row_update_for_mysql(
+ row_prebuilt_t* prebuilt)
MY_ATTRIBUTE((warn_unused_result));
/** This can only be used when srv_locks_unsafe_for_binlog is TRUE or this
@@ -672,6 +685,8 @@ struct row_prebuilt_t {
not to be confused with InnoDB
externally stored columns
(VARCHAR can be off-page too) */
+ unsigned versioned_write:1;/*!< whether this is
+ a versioned write */
mysql_row_templ_t* mysql_template;/*!< template used to transform
rows fast between MySQL and Innobase
formats; memory for this template
@@ -848,6 +863,20 @@ struct row_prebuilt_t {
/** The MySQL table object */
TABLE* m_mysql_table;
+
+ /** Get template by dict_table_t::cols[] number */
+ const mysql_row_templ_t* get_template_by_col(ulint col) const
+ {
+ ut_ad(col < n_template);
+ ut_ad(mysql_template);
+ for (int i = col; i < n_template; ++i) {
+ const mysql_row_templ_t* templ = &mysql_template[i];
+ if (!templ->is_virtual && templ->col_no == col) {
+ return templ;
+ }
+ }
+ return NULL;
+ }
};
/** Callback for row_mysql_sys_index_iterate() */
diff --git a/storage/innobase/include/row0upd.h b/storage/innobase/include/row0upd.h
index 92b5942966b..877b44a5b07 100644
--- a/storage/innobase/include/row0upd.h
+++ b/storage/innobase/include/row0upd.h
@@ -464,6 +464,7 @@ struct upd_t{
virtual column update now */
ulint n_fields; /*!< number of update fields */
upd_field_t* fields; /*!< array of update fields */
+ byte vers_sys_value[8]; /*!< buffer for updating system fields */
/** Append an update field to the end of array
@param[in] field an update field */
@@ -484,6 +485,17 @@ struct upd_t{
return(false);
}
+ /** Determine if the update affects a system versioned column. */
+ bool affects_versioned() const
+ {
+ for (ulint i = 0; i < n_fields; i++) {
+ if (fields[i].new_val.type.vers_sys_field()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
#ifdef UNIV_DEBUG
bool validate() const
{
@@ -500,12 +512,19 @@ struct upd_t{
};
+/** Kinds of update operation */
+enum delete_mode_t {
+ NO_DELETE = 0, /*!< this operation does not delete */
+ PLAIN_DELETE, /*!< ordinary delete */
+ VERSIONED_DELETE /*!< update old and insert a new row */
+};
+
/* Update node structure which also implements the delete operation
of a row */
struct upd_node_t{
que_common_t common; /*!< node type: QUE_NODE_UPDATE */
- ibool is_delete;/* TRUE if delete, FALSE if update */
+ delete_mode_t is_delete; /*!< kind of DELETE */
ibool searched_update;
/* TRUE if searched update, FALSE if
positioned */
diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h
index 580a660cedc..4c47ea393f5 100644
--- a/storage/innobase/include/srv0srv.h
+++ b/storage/innobase/include/srv0srv.h
@@ -611,16 +611,16 @@ extern mysql_pfs_key_t trx_rollback_clean_thread_key;
schema */
# define pfs_register_thread(key) \
do { \
- struct PSI_thread* psi = PSI_THREAD_CALL(new_thread)(key, NULL, 0);\
+ struct PSI_thread* psi = PSI_CALL_new_thread(key, NULL, 0);\
/* JAN: TODO: MYSQL 5.7 PSI \
- PSI_THREAD_CALL(set_thread_os_id)(psi); */ \
- PSI_THREAD_CALL(set_thread)(psi); \
+ PSI_CALL_set_thread_os_id(psi); */ \
+ PSI_CALL_set_thread(psi); \
} while (0)
/* This macro delist the current thread from performance schema */
# define pfs_delete_thread() \
do { \
- PSI_THREAD_CALL(delete_current_thread)(); \
+ PSI_CALL_delete_current_thread(); \
} while (0)
# else
# define pfs_register_thread(key)
diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h
index 81ef6093e2e..9f9369b5f67 100644
--- a/storage/innobase/include/trx0trx.h
+++ b/storage/innobase/include/trx0trx.h
@@ -779,8 +779,69 @@ struct trx_lock_t {
bool start_stmt;
};
-/** The first modification time of a table in a transaction */
-typedef undo_no_t trx_mod_table_time_t;
+/** Logical first modification time of a table in a transaction */
+class trx_mod_table_time_t
+{
+ /** First modification of the table */
+ undo_no_t first;
+ /** First modification of a system versioned column */
+ undo_no_t first_versioned;
+ bool vers_by_trx;
+
+ /** Magic value signifying that a system versioned column of a
+ table was never modified in a transaction. */
+ static const undo_no_t UNVERSIONED = IB_ID_MAX;
+
+public:
+ /** Constructor
+ @param[in] rows number of modified rows so far */
+ trx_mod_table_time_t(undo_no_t rows)
+ : first(rows), first_versioned(UNVERSIONED),
+ vers_by_trx(false) {}
+
+#ifdef UNIV_DEBUG
+ /** Validation
+ @param[in] rows number of modified rows so far
+ @return whether the object is valid */
+ bool valid(undo_no_t rows = UNVERSIONED) const
+ {
+ return first <= first_versioned && first <= rows;
+ }
+#endif /* UNIV_DEBUG */
+ /** @return if versioned columns were modified */
+ bool is_versioned() const { return first_versioned != UNVERSIONED; }
+ bool is_trx_versioned() const
+ {
+ return is_versioned() && vers_by_trx;
+ }
+
+ /** After writing an undo log record, set is_versioned() if needed
+ @param[in] rows number of modified rows so far */
+ void set_versioned(undo_no_t rows, bool by_trx_id)
+ {
+ ut_ad(!is_versioned());
+ first_versioned = rows;
+ vers_by_trx = by_trx_id;
+ ut_ad(valid());
+ }
+
+ /** Invoked after partial rollback
+ @param[in] limit number of surviving modified rows
+ @return whether this should be erased from trx_t::mod_tables */
+ bool rollback(undo_no_t limit)
+ {
+ ut_ad(valid());
+ if (first >= limit) {
+ return true;
+ }
+
+ if (first_versioned < limit && is_versioned()) {
+ first_versioned = UNVERSIONED;
+ }
+
+ return false;
+ }
+};
/** Collection of persistent tables and their first modification
in a transaction.
@@ -841,7 +902,6 @@ typedef enum {
TRX_WSREP_ABORT = 1
} trx_abort_t;
-
/** 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
diff --git a/storage/innobase/include/trx0types.h b/storage/innobase/include/trx0types.h
index 8092246c7fa..be8ef3398ad 100644
--- a/storage/innobase/include/trx0types.h
+++ b/storage/innobase/include/trx0types.h
@@ -140,9 +140,6 @@ typedef ib_id_t roll_ptr_t;
/** Undo number */
typedef ib_id_t undo_no_t;
-/** Maximum transaction identifier */
-#define TRX_ID_MAX IB_ID_MAX
-
/** Transaction savepoint */
struct trx_savept_t{
undo_no_t least_undo_no; /*!< least undo number to undo */
diff --git a/storage/innobase/pars/pars0pars.cc b/storage/innobase/pars/pars0pars.cc
index d0696ab5cfc..11195287d8f 100644
--- a/storage/innobase/pars/pars0pars.cc
+++ b/storage/innobase/pars/pars0pars.cc
@@ -1085,7 +1085,7 @@ pars_update_statement_start(
node = upd_node_create(pars_sym_tab_global->heap);
- node->is_delete = is_delete;
+ node->is_delete = is_delete ? PLAIN_DELETE : NO_DELETE;
node->table_sym = table_sym;
node->col_assign_list = col_assign_list;
@@ -1250,9 +1250,9 @@ pars_update_statement(
node->select = sel_node;
ut_a(!node->is_delete || (node->col_assign_list == NULL));
- ut_a(node->is_delete || (node->col_assign_list != NULL));
+ ut_a(node->is_delete == PLAIN_DELETE || node->col_assign_list != NULL);
- if (node->is_delete) {
+ if (node->is_delete == PLAIN_DELETE) {
node->cmpl_info = 0;
} else {
pars_process_assign_list(node);
diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc
index 51b299e1215..e71629b568b 100644
--- a/storage/innobase/row/row0ins.cc
+++ b/storage/innobase/row/row0ins.cc
@@ -429,7 +429,7 @@ row_ins_cascade_ancestor_updates_table(
upd_node = static_cast<upd_node_t*>(parent);
- if (upd_node->table == table && upd_node->is_delete == FALSE) {
+ if (upd_node->table == table && !upd_node->is_delete) {
return(TRUE);
}
@@ -1147,9 +1147,9 @@ row_ins_foreign_check_on_constraint(
if (node->is_delete
&& (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE)) {
- cascade->is_delete = TRUE;
+ cascade->is_delete = PLAIN_DELETE;
} else {
- cascade->is_delete = FALSE;
+ cascade->is_delete = NO_DELETE;
if (foreign->n_fields > cascade->update_n_fields) {
/* We have to make the update vector longer */
@@ -1346,7 +1346,7 @@ row_ins_foreign_check_on_constraint(
goto nonstandard_exit_func;
}
}
- } else if (table->fts && cascade->is_delete) {
+ } else if (table->fts && cascade->is_delete == PLAIN_DELETE) {
/* DICT_FOREIGN_ON_DELETE_CASCADE case */
for (i = 0; i < foreign->n_fields; i++) {
if (table->fts && dict_table_is_fts_column(
@@ -1625,8 +1625,14 @@ 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 row_end != Inf, we
+ suppress the foreign key check */
+ if (field->type.vers_sys_end() && field->vers_history_row()) {
goto exit_func;
}
}
@@ -1757,6 +1763,23 @@ row_ins_check_foreign_constraint(
cmp = cmp_dtuple_rec(entry, rec, offsets);
if (cmp == 0) {
+ if (check_table->versioned()) {
+ bool history_row = false;
+
+ if (check_index->is_clust()) {
+ history_row = check_index->
+ vers_history_row(rec, offsets);
+ } else if (check_index->
+ vers_history_row(rec, history_row))
+ {
+ break;
+ }
+
+ if (history_row) {
+ continue;
+ }
+ }
+
if (rec_get_deleted_flag(rec,
rec_offs_comp(offsets))) {
/* In delete-marked records, DB_TRX_ID must
diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc
index 53e51bdd930..3f906539ed8 100644
--- a/storage/innobase/row/row0merge.cc
+++ b/storage/innobase/row/row0merge.cc
@@ -1707,7 +1707,8 @@ row_merge_read_clustered_index(
ut_stage_alter_t* stage,
double pct_cost,
row_merge_block_t* crypt_block,
- struct TABLE* eval_table)
+ struct TABLE* eval_table,
+ bool drop_historical)
{
dict_index_t* clust_index; /* Clustered index */
mem_heap_t* row_heap; /* Heap memory to create
@@ -1741,6 +1742,10 @@ row_merge_read_clustered_index(
double curr_progress = 0.0;
ib_uint64_t read_rows = 0;
ib_uint64_t table_total_rows = 0;
+ char new_sys_trx_start[8];
+ char new_sys_trx_end[8];
+ byte any_autoinc_data[8] = {0};
+ bool vers_update_trt = false;
DBUG_ENTER("row_merge_read_clustered_index");
@@ -1915,6 +1920,9 @@ row_merge_read_clustered_index(
prev_fields = NULL;
}
+ mach_write_to_8(new_sys_trx_start, trx->id);
+ mach_write_to_8(new_sys_trx_end, TRX_ID_MAX);
+
/* Scan the clustered index. */
for (;;) {
const rec_t* rec;
@@ -2239,9 +2247,33 @@ end_of_index:
ut_ad(add_autoinc
< dict_table_get_n_user_cols(new_table));
- const dfield_t* dfield;
+ bool history_row = false;
+ if (new_table->versioned()) {
+ const dfield_t* dfield = dtuple_get_nth_field(
+ row, new_table->vers_end);
+ history_row = dfield->vers_history_row();
+ }
+
+ dfield_t* dfield;
dfield = dtuple_get_nth_field(row, add_autoinc);
+
+ if (new_table->versioned()) {
+ if (history_row) {
+ if (dfield_get_type(dfield)->prtype & DATA_NOT_NULL) {
+ err = DB_UNSUPPORTED;
+ my_error(ER_UNSUPPORTED_EXTENSION, MYF(0),
+ old_table->name);
+ goto func_exit;
+ }
+ dfield_set_null(dfield);
+ } else {
+ // set not null
+ ulint len = dfield_get_type(dfield)->len;
+ dfield_set_data(dfield, any_autoinc_data, len);
+ }
+ }
+
if (dfield_is_null(dfield)) {
goto write_buffers;
}
@@ -2287,6 +2319,21 @@ end_of_index:
}
}
+ if (old_table->versioned()) {
+ if ((!new_table->versioned() || drop_historical)
+ && clust_index->vers_history_row(rec, offsets)) {
+ continue;
+ }
+ } else if (new_table->versioned()) {
+ dfield_t* start =
+ dtuple_get_nth_field(row, new_table->vers_start);
+ dfield_t* end =
+ dtuple_get_nth_field(row, new_table->vers_end);
+ dfield_set_data(start, new_sys_trx_start, 8);
+ dfield_set_data(end, new_sys_trx_end, 8);
+ vers_update_trt = true;
+ }
+
write_buffers:
/* Build all entries for all the indexes to be created
in a single scan of the clustered index. */
@@ -2828,6 +2875,15 @@ wait_again:
}
}
+ if (vers_update_trt) {
+ trx_mod_table_time_t& time =
+ trx->mod_tables
+ .insert(trx_mod_tables_t::value_type(
+ const_cast<dict_table_t*>(new_table), 0))
+ .first->second;
+ time.set_versioned(0, true);
+ }
+
trx->op_info = "";
DBUG_RETURN(err);
@@ -4547,6 +4603,7 @@ this function and it will be passed to other functions for further accounting.
@param[in] add_v new virtual columns added along with indexes
@param[in] eval_table mysql table used to evaluate virtual column
value, see innobase_get_computed_value().
+@param[in] drop_historical whether to drop historical system rows
@return DB_SUCCESS or error code */
dberr_t
row_merge_build_indexes(
@@ -4565,7 +4622,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;
@@ -4725,7 +4783,7 @@ 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_block, eval_table);
+ pct_cost, crypt_block, eval_table, drop_historical);
stage->end_phase_read_pk();
diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc
index ee47d9c0a0c..0e7712f453c 100644
--- a/storage/innobase/row/row0mysql.cc
+++ b/storage/innobase/row/row0mysql.cc
@@ -821,6 +821,12 @@ handle_new_error:
<< FK_MAX_CASCADE_DEL << ". Please drop excessive"
" foreign constraints and try again";
break;
+ case DB_UNSUPPORTED:
+ ib::error() << "Cannot delete/update rows with cascading"
+ " foreign key constraints in timestamp-based temporal"
+ " table. Please drop excessive"
+ " foreign constraints and try again";
+ break;
default:
ib::fatal() << "Unknown error code " << err << ": "
<< ut_strerr(err);
@@ -1387,6 +1393,23 @@ row_mysql_get_table_status(
return(err);
}
+/** Writes 8 bytes to nth tuple field
+@param[in] tuple where to write
+@param[in] nth index in tuple
+@param[in] data what to write
+@param[in] buf field data buffer */
+static
+void
+set_tuple_col_8(dtuple_t* tuple, int col, uint64_t data, byte* buf) {
+ dfield_t* dfield = dtuple_get_nth_field(tuple, col);
+ ut_ad(dfield->type.len == 8);
+ if (dfield->len == UNIV_SQL_NULL) {
+ dfield_set_data(dfield, buf, 8);
+ }
+ ut_ad(dfield->len == dfield->type.len && dfield->data);
+ mach_write_to_8(dfield->data, data);
+}
+
/** Does an insert for MySQL.
@param[in] mysql_rec row in the MySQL format
@param[in,out] prebuilt prebuilt struct in MySQL handle
@@ -1394,7 +1417,8 @@ row_mysql_get_table_status(
dberr_t
row_insert_for_mysql(
const byte* mysql_rec,
- row_prebuilt_t* prebuilt)
+ row_prebuilt_t* prebuilt,
+ ins_mode_t ins_mode)
{
trx_savept_t savept;
que_thr_t* thr;
@@ -1461,6 +1485,29 @@ row_insert_for_mysql(
row_mysql_convert_row_to_innobase(node->row, prebuilt, mysql_rec,
&blob_heap);
+ if (ins_mode != ROW_INS_NORMAL)
+ {
+ ut_ad(table->vers_start != table->vers_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->get_template_by_col(table->vers_end);
+ ut_ad(t);
+ ut_ad(t->mysql_col_len == 8);
+
+ if (ins_mode == ROW_INS_HISTORICAL) {
+ set_tuple_col_8(node->row, table->vers_end, trx->id, node->vers_end_buf);
+ }
+ else /* ROW_INS_VERSIONED */ {
+ set_tuple_col_8(node->row, table->vers_end, TRX_ID_MAX, node->vers_end_buf);
+ int8store(&mysql_rec[t->mysql_col_offset], TRX_ID_MAX);
+ t = prebuilt->get_template_by_col(table->vers_start);
+ ut_ad(t);
+ ut_ad(t->mysql_col_len == 8);
+ set_tuple_col_8(node->row, table->vers_start, trx->id, node->vers_start_buf);
+ int8store(&mysql_rec[t->mysql_col_offset], trx->id);
+ }
+ }
+
savept = trx_savept_take(trx);
thr = que_fork_get_first_thr(prebuilt->ins_graph);
@@ -1639,7 +1686,7 @@ row_create_update_node_for_mysql(
node = upd_node_create(heap);
node->in_mysql_interface = TRUE;
- node->is_delete = FALSE;
+ node->is_delete = NO_DELETE;
node->searched_update = FALSE;
node->select = NULL;
node->pcur = btr_pcur_create_for_mysql();
@@ -1734,7 +1781,7 @@ row_fts_update_or_delete(
ut_a(dict_table_has_fts_index(node->table));
/* Deletes are simple; get them out of the way first. */
- if (node->is_delete) {
+ if (node->is_delete == PLAIN_DELETE) {
/* A delete affects all FTS indexes, so we pass NULL */
fts_trx_add_op(trx, table, old_doc_id, FTS_DELETE, NULL);
} else {
@@ -1863,7 +1910,7 @@ row_update_for_mysql(row_prebuilt_t* prebuilt)
}
node = prebuilt->upd_node;
- const bool is_delete = node->is_delete;
+ const bool is_delete = node->is_delete == PLAIN_DELETE;
ut_ad(node->table == table);
if (node->cascade_heap) {
@@ -1929,7 +1976,51 @@ row_update_for_mysql(row_prebuilt_t* prebuilt)
thr->fk_cascade_depth = 0;
+ ut_ad(!prebuilt->versioned_write || node->table->versioned());
+
+ bool vers_set_fields = prebuilt->versioned_write
+ && (node->is_delete ? node->is_delete == VERSIONED_DELETE
+ : node->update->affects_versioned());
run_again:
+ if (vers_set_fields) {
+ /* System Versioning: modify update vector to set
+ row_start (or row_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 = VERSIONED_DELETE;
+ col_idx = table->vers_end;
+ } else {
+ ut_ad(uvect->n_fields < table->n_cols);
+ ufield = &uvect->fields[uvect->n_fields];
+ col_idx = table->vers_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;
+
+ mach_write_to_8(node->update->vers_sys_value, trx->id);
+ dfield_t* dfield = &ufield->new_val;
+ dfield_set_data(dfield, node->update->vers_sys_value, 8);
+ 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);
@@ -1945,7 +2036,7 @@ run_again:
err = trx->error_state;
if (err != DB_SUCCESS) {
-
+handle_error:
que_thr_stop_for_mysql(thr);
if (err == DB_RECORD_NOT_FOUND) {
@@ -2023,7 +2114,18 @@ run_again:
node->cascade_upd_nodes = cascade_upd_nodes;
cascade_upd_nodes->pop_front();
thr->fk_cascade_depth++;
+ vers_set_fields = node->table->versioned()
+ && (node->is_delete == PLAIN_DELETE
+ || node->update->affects_versioned());
+ if (vers_set_fields && !prebuilt->versioned_write)
+ {
+ // FIXME: timestamp-based update of row_end in run_again
+ err = DB_UNSUPPORTED;
+ trx->error_state = err;
+
+ goto handle_error;
+ }
goto run_again;
}
@@ -2045,7 +2147,7 @@ run_again:
node = *i;
- if (node->is_delete) {
+ if (node->is_delete == PLAIN_DELETE) {
/* Not protected by dict_table_stats_lock() for
performance reasons, we would rather get garbage
in stat_n_rows (which is just an estimate anyway)
diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc
index 53f60f2f70b..78e5bbcd15b 100644
--- a/storage/innobase/row/row0sel.cc
+++ b/storage/innobase/row/row0sel.cc
@@ -5742,7 +5742,14 @@ lock_table_wait:
normal_return:
/*-------------------------------------------------------------*/
- que_thr_stop_for_mysql_no_error(thr, trx);
+ {
+ /* handler_index_cond_check() may pull TR_table search
+ which initates another row_search_mvcc(). */
+ ulint n_active_thrs= trx->lock.n_active_thrs;
+ trx->lock.n_active_thrs= 1;
+ que_thr_stop_for_mysql_no_error(thr, trx);
+ trx->lock.n_active_thrs= n_active_thrs - 1;
+ }
mtr_commit(&mtr);
diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc
index c2ae828b1e0..4c2fd94c1cd 100644
--- a/storage/innobase/row/row0upd.cc
+++ b/storage/innobase/row/row0upd.cc
@@ -2241,7 +2241,7 @@ row_upd_store_row(
thd, mysql_table);
}
- if (node->is_delete) {
+ if (node->is_delete == PLAIN_DELETE) {
node->upd_row = NULL;
node->upd_ext = NULL;
} else {
@@ -2516,7 +2516,7 @@ row_upd_sec_index_entry(
btr_pcur_close(&pcur);
mtr_commit(&mtr);
- if (node->is_delete || err != DB_SUCCESS) {
+ if (node->is_delete == PLAIN_DELETE || err != DB_SUCCESS) {
goto func_exit;
}
@@ -2969,7 +2969,7 @@ row_upd_del_mark_clust_rec(
ut_ad(node);
ut_ad(dict_index_is_clust(index));
- ut_ad(node->is_delete);
+ ut_ad(node->is_delete == PLAIN_DELETE);
pcur = node->pcur;
btr_cur = btr_pcur_get_btr_cur(pcur);
@@ -3121,7 +3121,8 @@ row_upd_clust_step(
then we have to free the file segments of the index tree associated
with the index */
- if (node->is_delete && node->table->id == DICT_INDEXES_ID) {
+ if (node->is_delete == PLAIN_DELETE
+ && node->table->id == DICT_INDEXES_ID) {
ut_ad(!dict_index_is_online_ddl(index));
@@ -3165,7 +3166,7 @@ row_upd_clust_step(
/* NOTE: the following function calls will also commit mtr */
- if (node->is_delete) {
+ if (node->is_delete == PLAIN_DELETE) {
err = row_upd_del_mark_clust_rec(
node, index, offsets, thr, referenced, foreign, &mtr);
@@ -3270,7 +3271,7 @@ row_upd(
/* We do not get the cmpl_info value from the MySQL
interpreter: we must calculate it on the fly: */
- if (node->is_delete
+ if (node->is_delete == PLAIN_DELETE
|| row_upd_changes_some_index_ord_field_binary(
node->table, node->update)) {
node->cmpl_info = 0;
diff --git a/storage/innobase/trx/trx0rec.cc b/storage/innobase/trx/trx0rec.cc
index ce291b7add9..a7fcca97a98 100644
--- a/storage/innobase/trx/trx0rec.cc
+++ b/storage/innobase/trx/trx0rec.cc
@@ -2102,10 +2102,27 @@ trx_undo_report_row_operation(
mutex_exit(&trx->undo_mutex);
if (!is_temp) {
- trx->mod_tables.insert(
- trx_mod_tables_t::value_type(
- index->table,
- undo->top_undo_no));
+ const undo_no_t limit = undo->top_undo_no;
+ /* Determine if this is the first time
+ when this transaction modifies a
+ system-versioned column in this table. */
+ trx_mod_table_time_t& time
+ = trx->mod_tables.insert(
+ trx_mod_tables_t::value_type(
+ index->table, limit))
+ .first->second;
+ ut_ad(time.valid(limit));
+
+ if (!time.is_versioned()
+ && index->table->versioned()
+ && (!rec /* INSERT */
+ || !update /* DELETE */
+ || update->affects_versioned()))
+ {
+ dict_col_t &col = index->table->cols[index->table->vers_start];
+ bool by_trx_id = col.mtype == DATA_INT;
+ time.set_versioned(limit, by_trx_id);
+ }
}
*roll_ptr = trx_undo_build_roll_ptr(
diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc
index a48c5294330..be4e4c3294a 100644
--- a/storage/innobase/trx/trx0roll.cc
+++ b/storage/innobase/trx/trx0roll.cc
@@ -125,7 +125,8 @@ trx_rollback_to_savepoint_low(
for (trx_mod_tables_t::iterator i = trx->mod_tables.begin();
i != trx->mod_tables.end(); ) {
trx_mod_tables_t::iterator j = i++;
- if (j->second >= limit) {
+ ut_ad(j->second.valid());
+ if (j->second.rollback(limit)) {
trx->mod_tables.erase(j);
}
}
diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc
index fde7443394e..882fd6f90a4 100644
--- a/storage/innobase/trx/trx0trx.cc
+++ b/storage/innobase/trx/trx0trx.cc
@@ -62,6 +62,17 @@ Created 3/26/1996 Heikki Tuuri
extern "C"
int thd_deadlock_victim_preference(const MYSQL_THD thd1, const MYSQL_THD thd2);
+/** The bit pattern corresponding to TRX_ID_MAX */
+const byte trx_id_max_bytes[8] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+/** The bit pattern corresponding to max timestamp */
+const byte timestamp_max_bytes[7] = {
+ 0x7f, 0xff, 0xff, 0xff, 0x0f, 0x42, 0x3f
+};
+
+
static const ulint MAX_DETAILED_ERROR_LEN = 256;
/** Set of table_id */
diff --git a/storage/maria/ma_checkpoint.c b/storage/maria/ma_checkpoint.c
index 0933ca7d736..06d48569b2a 100644
--- a/storage/maria/ma_checkpoint.c
+++ b/storage/maria/ma_checkpoint.c
@@ -562,9 +562,7 @@ pthread_handler_t ma_checkpoint_background(void *arg)
DBUG_PRINT("info",("Maria background checkpoint thread starts"));
DBUG_ASSERT(interval > 0);
-#ifdef HAVE_PSI_THREAD_INTERFACE
- PSI_THREAD_CALL(set_thread_user_host)(0,0,0,0);
-#endif
+ PSI_CALL_set_thread_user_host(0,0,0,0);
/*
Recovery ended with all tables closed and a checkpoint: no need to take
diff --git a/storage/rocksdb/mysql-test/rocksdb/r/misc.result b/storage/rocksdb/mysql-test/rocksdb/r/misc.result
index 4a39f1cbff4..6087928b80f 100644
--- a/storage/rocksdb/mysql-test/rocksdb/r/misc.result
+++ b/storage/rocksdb/mysql-test/rocksdb/r/misc.result
@@ -30,6 +30,7 @@ FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE ORDER BY TABLE_NAME;
TABLE_NAME COLUMN_NAME REFERENCED_TABLE_NAME REFERENCED_COLUMN_NAME
Warning 1286 Unknown storage engine 'InnoDB'
Warning 1286 Unknown storage engine 'InnoDB'
+Warning 1286 Unknown storage engine 'InnoDB'
Warnings:
column_stats column_name NULL NULL
column_stats db_name NULL NULL
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