1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

Parser, SQL: (0.4) TRANSACTION support in queries

Syntax extension: TIMESTAMP/TRANSACTION keyword can be used before FROM ... TO, BETWEEN ... AND.
Example:
    SELECT * FROM t1 FOR SYSTEM_TIME TIMESTAMP FROM '1-1-1' TO NOW();

Closes #27
This commit is contained in:
Aleksey Midenkov
2016-10-14 13:25:28 +00:00
parent a22cbc453f
commit 6d89a4a49b
6 changed files with 101 additions and 31 deletions

View File

@ -7537,3 +7537,9 @@ ER_SYS_END_FIELD_MUST_BE_BIGINT
ER_NO_VERSIONED_FIELDS_IN_VERSIONED_TABLE ER_NO_VERSIONED_FIELDS_IN_VERSIONED_TABLE
eng "Every field specified unversioned 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"

View File

@ -33,9 +33,9 @@
#include "sql_signal.h" #include "sql_signal.h"
void LEX::parse_error() void LEX::parse_error(uint err_number)
{ {
thd->parse_error(); thd->parse_error(err_number);
} }

View File

@ -2649,7 +2649,6 @@ struct LEX: public Query_tables_list
private: private:
Query_arena_memroot *arena_for_set_stmt; Query_arena_memroot *arena_for_set_stmt;
MEM_ROOT *mem_root_for_set_stmt; MEM_ROOT *mem_root_for_set_stmt;
void parse_error();
bool sp_block_finalize(THD *thd, const Lex_spblock_st spblock, bool sp_block_finalize(THD *thd, const Lex_spblock_st spblock,
class sp_label **splabel); class sp_label **splabel);
bool sp_change_context(THD *thd, const sp_pcontext *ctx, bool exclusive); 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); bool sp_for_loop_increment(THD *thd, const Lex_for_loop_st &loop);
public: public:
void parse_error(uint err_number= ER_SYNTAX_ERROR);
inline bool is_arena_for_set_stmt() {return arena_for_set_stmt != 0;} inline bool is_arena_for_set_stmt() {return arena_for_set_stmt != 0;}
bool set_arena_for_set_stmt(Query_arena *backup); bool set_arena_for_set_stmt(Query_arena *backup);
void reset_arena_for_set_stmt(Query_arena *backup); void reset_arena_for_set_stmt(Query_arena *backup);

View File

@ -668,7 +668,7 @@ setup_without_group(THD *thd, Ref_ptr_array ref_pointer_array,
} }
static int 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"); 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. */ because they must outlive execution phase for multiple executions. */
arena= thd->activate_stmt_arena_if_needed(&backup); 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()); DBUG_ASSERT(thd->stmt_arena->is_sp_execute());
/* 2. this copy_andor_structure() is also required by the same reason */ /* 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()) 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) else if (*where_expr) // SP executed first time (STMT_INITIALIZED_FOR_SP)
/* 1. copy_andor_structure() is required since this andor tree /* 1. copy_andor_structure() is required since this andor tree
is modified later (and on shorter arena) */ 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 /* 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 *fstart= table->table->vers_start_field();
Field *fend= table->table->vers_end_field(); Field *fend= table->table->vers_end_field();
DBUG_ASSERT(select_lex->parent_lex); DBUG_ASSERT(slex->parent_lex);
Name_resolution_context *context= select_lex->parent_lex->current_context(); Name_resolution_context *context= slex->parent_lex->current_context();
DBUG_ASSERT(context); DBUG_ASSERT(context);
Item *row_start= new (thd->mem_root) Item_field(thd, context, fstart); 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_end= new (thd->mem_root) Item_field(thd, context, fend);
Item *row_end2= row_end; 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); DBUG_ASSERT(table->table->s && table->table->s->db_plugin);
row_start= new (thd->mem_root) Item_func_vtq_ts( 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; Item *cond1= 0, *cond2= 0, *curr= 0;
switch (select_lex->vers_conditions.type) switch (slex->vers_conditions.type)
{ {
case FOR_SYSTEM_TIME_UNSPECIFIED: case FOR_SYSTEM_TIME_UNSPECIFIED:
if (table->table->versioned_by_sql()) 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; break;
case FOR_SYSTEM_TIME_AS_OF: case FOR_SYSTEM_TIME_AS_OF:
cond1= new (thd->mem_root) Item_func_le(thd, row_start, 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, cond2= new (thd->mem_root) Item_func_gt(thd, row_end,
select_lex->vers_conditions.start); slex->vers_conditions.start);
break; break;
case FOR_SYSTEM_TIME_FROM_TO: case FOR_SYSTEM_TIME_FROM_TO:
cond1= new (thd->mem_root) Item_func_lt(thd, row_start, 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, cond2= new (thd->mem_root) Item_func_ge(thd, row_end,
select_lex->vers_conditions.start); slex->vers_conditions.start);
break; break;
case FOR_SYSTEM_TIME_BETWEEN: case FOR_SYSTEM_TIME_BETWEEN:
cond1= new (thd->mem_root) Item_func_le(thd, row_start, 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, cond2= new (thd->mem_root) Item_func_ge(thd, row_end,
select_lex->vers_conditions.start); slex->vers_conditions.start);
break; break;
default: default:
DBUG_ASSERT(0); DBUG_ASSERT(0);

View File

@ -849,6 +849,7 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr)
enum Window_frame::Frame_exclusion frame_exclusion; enum Window_frame::Frame_exclusion frame_exclusion;
enum trigger_order_type trigger_action_order_type; enum trigger_order_type trigger_action_order_type;
DDL_options_st object_ddl_options; DDL_options_st object_ddl_options;
enum vers_range_unit_t vers_range_unit;
} }
%{ %{
@ -1968,6 +1969,8 @@ END_OF_INPUT
%type <lex_str_list> opt_with_column_list %type <lex_str_list> opt_with_column_list
%type <vers_range_unit> 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: opt_for_system_time_clause:
/* empty */ /* empty */
{} {}
| FOR_SYSTEM_TIME_SYM | FOR_SYSTEM_TIME_SYM
AS OF_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 | FOR_SYSTEM_TIME_SYM
AS OF_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); Item *item= new (thd->mem_root) Item_func_now_local(thd, 6);
if (item == NULL) if (item == NULL)
MYSQL_YYABORT; 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 | FOR_SYSTEM_TIME_SYM
FROM FROM
TIMESTAMP simple_expr trans_or_timestamp
simple_expr
TO_SYM 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 | FOR_SYSTEM_TIME_SYM
BETWEEN_SYM BETWEEN_SYM
TIMESTAMP simple_expr trans_or_timestamp
simple_expr
AND_SYM 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);
} }
; ;

View File

@ -1812,7 +1812,7 @@ class Item_in_subselect;
4) jtbm semi-join (jtbm_subselect != NULL) 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_UNSPECIFIED = 0,
FOR_SYSTEM_TIME_AS_OF, FOR_SYSTEM_TIME_AS_OF,
@ -1820,24 +1820,34 @@ enum for_system_time_type
FOR_SYSTEM_TIME_BETWEEN FOR_SYSTEM_TIME_BETWEEN
}; };
enum vers_range_unit_t
{
UNIT_TIMESTAMP = 0,
UNIT_TRX_ID
};
/** System versioning support. */ /** System versioning support. */
struct vers_select_conds_t struct vers_select_conds_t
{ {
enum for_system_time_type type; vers_range_type_t type;
vers_range_unit_t unit;
Item *start, *end; Item *start, *end;
void empty() void empty()
{ {
type= FOR_SYSTEM_TIME_UNSPECIFIED; type= FOR_SYSTEM_TIME_UNSPECIFIED;
unit= UNIT_TIMESTAMP;
start= end= NULL; start= end= NULL;
} }
void init( void init(
const enum for_system_time_type t, vers_range_type_t t,
Item * const s, vers_range_unit_t u,
Item * const e= NULL) Item * s,
Item * e= NULL)
{ {
type= t; type= t;
unit= u;
start= s; start= s;
end= e; end= e;
} }