diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index e215395c3c2..5e3a725a895 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7537,3 +7537,9 @@ ER_SYS_END_FIELD_MUST_BE_BIGINT ER_NO_VERSIONED_FIELDS_IN_VERSIONED_TABLE eng "Every field specified unversioned in versioned table" + +ER_VERS_TRX_ID_UNSUPPORTED + eng "Engine does not support versioned TRX_ID" + +ER_VERS_RANGE_UNITS_MISMATCH + eng "Range units mismatch" diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 40ead5824fb..3375324b027 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -33,9 +33,9 @@ #include "sql_signal.h" -void LEX::parse_error() +void LEX::parse_error(uint err_number) { - thd->parse_error(); + thd->parse_error(err_number); } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 826ebd03063..c0e28ab8fd2 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -2649,7 +2649,6 @@ struct LEX: public Query_tables_list private: Query_arena_memroot *arena_for_set_stmt; MEM_ROOT *mem_root_for_set_stmt; - void parse_error(); bool sp_block_finalize(THD *thd, const Lex_spblock_st spblock, class sp_label **splabel); bool sp_change_context(THD *thd, const sp_pcontext *ctx, bool exclusive); @@ -2663,6 +2662,7 @@ private: bool sp_for_loop_increment(THD *thd, const Lex_for_loop_st &loop); public: + void parse_error(uint err_number= ER_SYNTAX_ERROR); inline bool is_arena_for_set_stmt() {return arena_for_set_stmt != 0;} bool set_arena_for_set_stmt(Query_arena *backup); void reset_arena_for_set_stmt(Query_arena *backup); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 4e7ca4663b1..81ff9b7246a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -668,7 +668,7 @@ setup_without_group(THD *thd, Ref_ptr_array ref_pointer_array, } static int -setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LEX *select_lex) +setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LEX *slex) { DBUG_ENTER("setup_for_system_time"); @@ -698,11 +698,11 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LE because they must outlive execution phase for multiple executions. */ arena= thd->activate_stmt_arena_if_needed(&backup); - if (select_lex->saved_where) + if (slex->saved_where) { DBUG_ASSERT(thd->stmt_arena->is_sp_execute()); /* 2. this copy_andor_structure() is also required by the same reason */ - *where_expr= select_lex->saved_where->copy_andor_structure(thd); + *where_expr= slex->saved_where->copy_andor_structure(thd); } else if (thd->stmt_arena->is_sp_execute()) { @@ -711,7 +711,7 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LE else if (*where_expr) // SP executed first time (STMT_INITIALIZED_FOR_SP) /* 1. copy_andor_structure() is required since this andor tree is modified later (and on shorter arena) */ - select_lex->saved_where= (*where_expr)->copy_andor_structure(thd); + slex->saved_where= (*where_expr)->copy_andor_structure(thd); } /* We have to save also non-versioned on_expr since we may have @@ -754,15 +754,23 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LE Field *fstart= table->table->vers_start_field(); Field *fend= table->table->vers_end_field(); - DBUG_ASSERT(select_lex->parent_lex); - Name_resolution_context *context= select_lex->parent_lex->current_context(); + DBUG_ASSERT(slex->parent_lex); + Name_resolution_context *context= slex->parent_lex->current_context(); DBUG_ASSERT(context); Item *row_start= new (thd->mem_root) Item_field(thd, context, fstart); Item *row_end= new (thd->mem_root) Item_field(thd, context, fend); Item *row_end2= row_end; - if (!table->table->versioned_by_sql()) + if (table->table->versioned_by_sql()) + { + if (slex->vers_conditions.unit == UNIT_TRX_ID) + { + my_error(ER_VERS_TRX_ID_UNSUPPORTED, MYF(0), table->table_name); + DBUG_RETURN(-1); + } + } + else if (slex->vers_conditions.unit == UNIT_TIMESTAMP) { DBUG_ASSERT(table->table->s && table->table->s->db_plugin); row_start= new (thd->mem_root) Item_func_vtq_ts( @@ -778,7 +786,7 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LE } Item *cond1= 0, *cond2= 0, *curr= 0; - switch (select_lex->vers_conditions.type) + switch (slex->vers_conditions.type) { case FOR_SYSTEM_TIME_UNSPECIFIED: if (table->table->versioned_by_sql()) @@ -796,21 +804,21 @@ setup_for_system_time(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LE break; case FOR_SYSTEM_TIME_AS_OF: cond1= new (thd->mem_root) Item_func_le(thd, row_start, - select_lex->vers_conditions.start); + slex->vers_conditions.start); cond2= new (thd->mem_root) Item_func_gt(thd, row_end, - select_lex->vers_conditions.start); + slex->vers_conditions.start); break; case FOR_SYSTEM_TIME_FROM_TO: cond1= new (thd->mem_root) Item_func_lt(thd, row_start, - select_lex->vers_conditions.end); + slex->vers_conditions.end); cond2= new (thd->mem_root) Item_func_ge(thd, row_end, - select_lex->vers_conditions.start); + slex->vers_conditions.start); break; case FOR_SYSTEM_TIME_BETWEEN: cond1= new (thd->mem_root) Item_func_le(thd, row_start, - select_lex->vers_conditions.end); + slex->vers_conditions.end); cond2= new (thd->mem_root) Item_func_ge(thd, row_end, - select_lex->vers_conditions.start); + slex->vers_conditions.start); break; default: DBUG_ASSERT(0); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index bbcb0630bd7..0f810d72f66 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -849,6 +849,7 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr) enum Window_frame::Frame_exclusion frame_exclusion; enum trigger_order_type trigger_action_order_type; DDL_options_st object_ddl_options; + enum vers_range_unit_t vers_range_unit; } %{ @@ -1968,6 +1969,8 @@ END_OF_INPUT %type opt_with_column_list +%type trans_or_timestamp + %% @@ -8673,14 +8676,25 @@ select_options: } ; +trans_or_timestamp: + TRANSACTION_SYM + { + $$ = UNIT_TRX_ID; + } + | TIMESTAMP + { + $$ = UNIT_TIMESTAMP; + } + ; + opt_for_system_time_clause: /* empty */ {} | FOR_SYSTEM_TIME_SYM AS OF_SYM - TIMESTAMP simple_expr + trans_or_timestamp simple_expr { - Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_AS_OF, $5); + Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_AS_OF, $4, $5); } | FOR_SYSTEM_TIME_SYM AS OF_SYM @@ -8689,23 +8703,55 @@ opt_for_system_time_clause: Item *item= new (thd->mem_root) Item_func_now_local(thd, 6); if (item == NULL) MYSQL_YYABORT; - Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_AS_OF, item); + Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_AS_OF, UNIT_TIMESTAMP, item); } | FOR_SYSTEM_TIME_SYM FROM - TIMESTAMP simple_expr + trans_or_timestamp + simple_expr TO_SYM - TIMESTAMP simple_expr + trans_or_timestamp + simple_expr { - Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_FROM_TO, $4, $7); + if ($3 != $6) + { + Lex->parse_error(ER_VERS_RANGE_UNITS_MISMATCH); + MYSQL_YYABORT; + } + Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_FROM_TO, $3, $4, $7); + } + | FOR_SYSTEM_TIME_SYM + trans_or_timestamp + FROM + simple_expr + TO_SYM + simple_expr + { + Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_FROM_TO, $2, $4, $6); } | FOR_SYSTEM_TIME_SYM BETWEEN_SYM - TIMESTAMP simple_expr + trans_or_timestamp + simple_expr AND_SYM - TIMESTAMP simple_expr + trans_or_timestamp + simple_expr { - Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_BETWEEN, $4, $7); + if ($3 != $6) + { + Lex->parse_error(ER_VERS_RANGE_UNITS_MISMATCH); + MYSQL_YYABORT; + } + Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_BETWEEN, $3, $4, $7); + } + | FOR_SYSTEM_TIME_SYM + trans_or_timestamp + BETWEEN_SYM + simple_expr + AND_SYM + simple_expr + { + Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_BETWEEN, $2, $4, $6); } ; diff --git a/sql/table.h b/sql/table.h index e2c055b14d5..df0300d498c 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1812,7 +1812,7 @@ class Item_in_subselect; 4) jtbm semi-join (jtbm_subselect != NULL) */ -enum for_system_time_type +enum vers_range_type_t { FOR_SYSTEM_TIME_UNSPECIFIED = 0, FOR_SYSTEM_TIME_AS_OF, @@ -1820,24 +1820,34 @@ enum for_system_time_type FOR_SYSTEM_TIME_BETWEEN }; +enum vers_range_unit_t +{ + UNIT_TIMESTAMP = 0, + UNIT_TRX_ID +}; + /** System versioning support. */ struct vers_select_conds_t { - enum for_system_time_type type; + vers_range_type_t type; + vers_range_unit_t unit; Item *start, *end; void empty() { type= FOR_SYSTEM_TIME_UNSPECIFIED; + unit= UNIT_TIMESTAMP; start= end= NULL; } void init( - const enum for_system_time_type t, - Item * const s, - Item * const e= NULL) + vers_range_type_t t, + vers_range_unit_t u, + Item * s, + Item * e= NULL) { type= t; + unit= u; start= s; end= e; }