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:
@ -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"
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
20
sql/table.h
20
sql/table.h
@ -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;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user