Commit 3a64d55a authored by Aleksey Midenkov's avatar Aleksey Midenkov

Parser, SQL: table-specific FOR SYSTEM_TIME [closes #116]

* Syntax sugar: query-global QUERY FOR SYSTEM_TIME
parent 57692d71
......@@ -25,7 +25,7 @@ a b
3 NULL
Warnings:
Warning 4075 Attempt to read unversioned field `b` in historical query
select count(*) from t group by b for system_time as of timestamp now(6);
select count(*) from t group by b query for system_time as of timestamp now(6);
count(*)
2
Warnings:
......@@ -42,23 +42,23 @@ a b
3 NULL
Warnings:
Warning 4075 Attempt to read unversioned field `b` in historical query
select * from t group by a having a=2 for system_time as of timestamp now(6);
select * from t group by a having a=2 query for system_time as of timestamp now(6);
a b
Warnings:
Warning 4075 Attempt to read unversioned field `b` in historical query
select * from t group by b having b=2 for system_time as of timestamp now(6);
select * from t group by b having b=2 query for system_time as of timestamp now(6);
a b
Warnings:
Warning 4075 Attempt to read unversioned field `b` in historical query
select a from t where b=2 for system_time as of timestamp now(6);
select a from t where b=2 query for system_time as of timestamp now(6);
a
Warnings:
Warning 4075 Attempt to read unversioned field `b` in historical query
select a from t where b=NULL for system_time as of timestamp now(6);
select a from t where b=NULL query for system_time as of timestamp now(6);
a
Warnings:
Warning 4075 Attempt to read unversioned field `b` in historical query
select count(*), b from t group by b having b=NULL for system_time as of timestamp now(6);
select count(*), b from t group by b having b=NULL query for system_time as of timestamp now(6);
count(*) b
Warnings:
Warning 4075 Attempt to read unversioned field `b` in historical query
......
......@@ -95,11 +95,11 @@ select t1.x as RJ1_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2
delete from t1;
delete from t2;
select t1.x as IJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x
for system_time as of timestamp @t0;
query for system_time as of timestamp @t0;
select t1.x as LJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x
for system_time as of timestamp @t0;
query for system_time as of timestamp @t0;
select t1.x as RJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x
for system_time as of timestamp @t0;
query for system_time as of timestamp @t0;
drop table t1;
drop table t2;
end~~
......
......@@ -23,7 +23,7 @@ x
create or replace view vt1 as select * from t1;
show create view vt1;
View Create View character_set_client collation_connection
vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`x` AS `x` from `t1` where `t1`.`sys_trx_end` = 18446744073709551615 for system_time all latin1 latin1_swedish_ci
vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`x` AS `x` from `t1` where `t1`.`sys_trx_end` = 18446744073709551615 query for system_time all latin1 latin1_swedish_ci
drop view vt1;
drop view vt2;
drop table t1;
......@@ -9,14 +9,14 @@ select * from t;
select a from t for system_time as of timestamp now(6);
select a, b, b+0 from t for system_time as of timestamp now(6);
select * from t for system_time as of timestamp now(6);
select count(*) from t group by b for system_time as of timestamp now(6);
select count(*) from t group by b query for system_time as of timestamp now(6);
select * from t for system_time as of timestamp now(6) order by b asc;
select * from t for system_time as of timestamp now(6) order by b desc;
select * from t group by a having a=2 for system_time as of timestamp now(6);
select * from t group by b having b=2 for system_time as of timestamp now(6);
select a from t where b=2 for system_time as of timestamp now(6);
select a from t where b=NULL for system_time as of timestamp now(6);
select count(*), b from t group by b having b=NULL for system_time as of timestamp now(6);
select * from t group by a having a=2 query for system_time as of timestamp now(6);
select * from t group by b having b=2 query for system_time as of timestamp now(6);
select a from t where b=2 query for system_time as of timestamp now(6);
select a from t where b=NULL query for system_time as of timestamp now(6);
select count(*), b from t group by b having b=NULL query for system_time as of timestamp now(6);
select a, b from t;
drop table t;
......@@ -91,11 +91,11 @@ begin
delete from t2;
select t1.x as IJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x
for system_time as of timestamp @t0;
query for system_time as of timestamp @t0;
select t1.x as LJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x
for system_time as of timestamp @t0;
query for system_time as of timestamp @t0;
select t1.x as RJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x
for system_time as of timestamp @t0;
query for system_time as of timestamp @t0;
drop table t1;
drop table t2;
......
......@@ -2762,8 +2762,10 @@ void Item_field::set_field(Field *field_par)
field->force_null= false;
if (field->flags & VERS_OPTIMIZED_UPDATE_FLAG && context &&
context->select_lex &&
context->select_lex->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED)
((field->table->pos_in_table_list &&
field->table->pos_in_table_list->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED) ||
(context->select_lex &&
context->select_lex->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED)))
{
field->force_null= true;
push_warning_printf(
......
......@@ -766,6 +766,8 @@ void LEX::start(THD *thd_arg)
frame_bottom_bound= NULL;
win_spec= NULL;
vers_conditions.empty();
is_lex_started= TRUE;
DBUG_VOID_RETURN;
}
......@@ -1366,6 +1368,19 @@ int MYSQLlex(YYSTYPE *yylval, THD *thd)
return FOR_SYM;
}
break;
case QUERY_SYM:
token= lex_one_token(yylval, thd);
lip->add_digest_token(token, yylval);
switch(token) {
case FOR_SYM:
return QUERY_FOR_SYM;
default:
lip->lookahead_yylval= lip->yylval;
lip->yylval= NULL;
lip->lookahead_token= token;
return QUERY_SYM;
}
break;
default:
break;
}
......
......@@ -2920,6 +2920,9 @@ struct LEX: public Query_tables_list
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());
......
......@@ -688,42 +688,21 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr,
{
if (table->table && table->table->versioned())
versioned_tables++;
}
vers_range_type_t query_type= slex->vers_conditions.type;
if (versioned_tables == 0)
{
if (query_type != FOR_SYSTEM_TIME_UNSPECIFIED)
else if (table->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED)
{
my_error(ER_VERSIONING_REQUIRED, MYF(0), "`FOR SYSTEM_TIME` query");
DBUG_RETURN(-1);
}
DBUG_RETURN(0);
}
if (query_type != FOR_SYSTEM_TIME_UNSPECIFIED)
if (versioned_tables == 0)
{
switch (slex->lock_type)
if (slex->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED)
{
case TL_WRITE_ALLOW_WRITE:
case TL_WRITE_CONCURRENT_INSERT:
case TL_WRITE_DELAYED:
case TL_WRITE_DEFAULT:
case TL_WRITE_LOW_PRIORITY:
case TL_WRITE:
case TL_WRITE_ONLY:
my_error(ER_VERS_WRONG_PARAMS, MYF(0), "FOR SYSTEM_TIME query", "write-locking of historic rows");
my_error(ER_VERSIONING_REQUIRED, MYF(0), "`FOR SYSTEM_TIME` query");
DBUG_RETURN(-1);
default:
break;
}
if (query_type == FOR_SYSTEM_TIME_ALL)
{
slex->vers_conditions.unwrapped= true;
DBUG_RETURN(0);
}
DBUG_RETURN(0);
}
/* For prepared statements we create items on statement arena,
......@@ -779,6 +758,36 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr,
{
if (table->table && table->table->versioned())
{
vers_select_conds_t &vers_conditions=
table->vers_conditions.type == FOR_SYSTEM_TIME_UNSPECIFIED ?
slex->vers_conditions : table->vers_conditions;
if (vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED)
{
switch (slex->lock_type)
{
case TL_WRITE_ALLOW_WRITE:
case TL_WRITE_CONCURRENT_INSERT:
case TL_WRITE_DELAYED:
case TL_WRITE_DEFAULT:
case TL_WRITE_LOW_PRIORITY:
case TL_WRITE:
case TL_WRITE_ONLY:
my_error(ER_VERS_WRONG_PARAMS, MYF(0), "FOR SYSTEM_TIME query", "write-locking of historic rows");
if (arena)
thd->restore_active_arena(arena, &backup);
DBUG_RETURN(-1);
default:
break;
}
if (vers_conditions.type == FOR_SYSTEM_TIME_ALL)
{
vers_conditions.unwrapped= true;
continue;
}
}
COND** dst_cond= where_expr;
if (table->on_expr)
{
......@@ -798,14 +807,14 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr,
if (table->table->versioned_by_sql())
{
if (slex->vers_conditions.unit == UNIT_TRX_ID)
if (vers_conditions.unit == UNIT_TRX_ID)
{
my_error(ER_VERS_ENGINE_UNSUPPORTED, MYF(0), table->table_name);
DBUG_RETURN(-1);
}
}
else if (vers_simple_select && slex->vers_conditions.unit == UNIT_TIMESTAMP
&& query_type != FOR_SYSTEM_TIME_UNSPECIFIED)
else if (vers_simple_select && vers_conditions.unit == UNIT_TIMESTAMP
&& vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED)
{
DBUG_ASSERT(table->table->s && table->table->s->db_plugin);
handlerton *hton= plugin_hton(table->table->s->db_plugin);
......@@ -826,7 +835,7 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr,
Item *cond1= 0, *cond2= 0, *curr= 0;
if (table->table->versioned_by_sql() || vers_simple_select)
{
switch (query_type)
switch (vers_conditions.type)
{
case FOR_SYSTEM_TIME_UNSPECIFIED:
if (table->table->versioned_by_sql())
......@@ -844,21 +853,21 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr,
break;
case FOR_SYSTEM_TIME_AS_OF:
cond1= newx Item_func_le(thd, row_start,
slex->vers_conditions.start);
vers_conditions.start);
cond2= newx Item_func_gt(thd, row_end,
slex->vers_conditions.start);
vers_conditions.start);
break;
case FOR_SYSTEM_TIME_FROM_TO:
cond1= newx Item_func_lt(thd, row_start,
slex->vers_conditions.end);
vers_conditions.end);
cond2= newx Item_func_ge(thd, row_end,
slex->vers_conditions.start);
vers_conditions.start);
break;
case FOR_SYSTEM_TIME_BETWEEN:
cond1= newx Item_func_le(thd, row_start,
slex->vers_conditions.end);
vers_conditions.end);
cond2= newx Item_func_ge(thd, row_end,
slex->vers_conditions.start);
vers_conditions.start);
break;
default:
DBUG_ASSERT(0);
......@@ -872,33 +881,33 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr,
Item *trx_id0, *trx_id1;
switch (query_type)
switch (vers_conditions.type)
{
case FOR_SYSTEM_TIME_UNSPECIFIED:
curr= newx Item_int(thd, ULONGLONG_MAX);
cond1= newx Item_func_eq(thd, row_end2, curr);
break;
case FOR_SYSTEM_TIME_AS_OF:
trx_id0= slex->vers_conditions.unit == UNIT_TIMESTAMP ?
newx Item_func_vtq_id(thd, slex->vers_conditions.start, VTQ_TRX_ID) :
slex->vers_conditions.start;
trx_id0= vers_conditions.unit == UNIT_TIMESTAMP ?
newx Item_func_vtq_id(thd, vers_conditions.start, VTQ_TRX_ID) :
vers_conditions.start;
cond1= newx Item_func_vtq_trx_sees_eq(thd, trx_id0, row_start);
cond2= newx Item_func_vtq_trx_sees(thd, row_end, trx_id0);
break;
case FOR_SYSTEM_TIME_FROM_TO:
case FOR_SYSTEM_TIME_BETWEEN:
if (slex->vers_conditions.unit == UNIT_TIMESTAMP)
if (vers_conditions.unit == UNIT_TIMESTAMP)
{
trx_id0= newx Item_func_vtq_id(thd, slex->vers_conditions.start, VTQ_TRX_ID, true);
trx_id1= newx Item_func_vtq_id(thd, slex->vers_conditions.end, VTQ_TRX_ID, false);
trx_id0= newx Item_func_vtq_id(thd, vers_conditions.start, VTQ_TRX_ID, true);
trx_id1= newx Item_func_vtq_id(thd, vers_conditions.end, VTQ_TRX_ID, false);
}
else
{
trx_id0= slex->vers_conditions.start;
trx_id1= slex->vers_conditions.end;
trx_id0= vers_conditions.start;
trx_id1= vers_conditions.end;
}
cond1= query_type == FOR_SYSTEM_TIME_FROM_TO ?
cond1= vers_conditions.type == FOR_SYSTEM_TIME_FROM_TO ?
newx Item_func_vtq_trx_sees(thd, trx_id1, row_start) :
newx Item_func_vtq_trx_sees_eq(thd, trx_id1, row_start);
cond2= newx Item_func_vtq_trx_sees_eq(thd, row_end, trx_id0);
......@@ -925,9 +934,7 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr,
} // for (table= tables; ...)
if (arena)
{
thd->restore_active_arena(arena, &backup);
}
slex->vers_conditions.unwrapped= true;
......@@ -25554,7 +25561,7 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type)
if (vers_conditions.unwrapped)
{
// versioning conditions are already unwrapped to WHERE clause
str->append(STRING_WITH_LEN(" for system_time all "));
str->append(STRING_WITH_LEN(" query for system_time all "));
}
if (order_list.elements)
......
......@@ -751,6 +751,7 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr)
%}
%union {
bool BOOL;
int num;
ulong ulong_num;
ulonglong ulonglong_number;
......@@ -1352,6 +1353,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token PURGE
%token QUARTER_SYM
%token QUERY_SYM
%token QUERY_FOR_SYM /* INTERNAL */
%token QUICK
%token RAISE_SYM /* Oracle-PLSQL-R */
%token RANGE_SYM /* SQL-2003-R */
......@@ -1970,6 +1972,7 @@ END_OF_INPUT
%type <lex_str_list> opt_with_column_list
%type <vers_range_unit> trans_or_timestamp
%type <BOOL> opt_for_system_time_clause
%%
......@@ -8762,7 +8765,7 @@ table_expression:
opt_group_clause
opt_having_clause
opt_window_clause
opt_for_system_time_clause
opt_query_for_system_time_clause
;
opt_table_expression:
......@@ -8808,75 +8811,74 @@ trans_or_timestamp:
}
;
opt_for_system_time_clause:
opt_query_for_system_time_clause:
/* empty */
{}
| FOR_SYSTEM_TIME_SYM
AS OF_SYM
trans_or_timestamp simple_expr
| QUERY_FOR_SYM SYSTEM_TIME_SYM for_system_time_expr
{
DBUG_ASSERT(Select);
Select->vers_conditions= Lex->vers_conditions;
}
;
opt_for_system_time_clause:
/* empty */
{
$$= false;
}
| FOR_SYSTEM_TIME_SYM for_system_time_expr
{
$$= true;
}
;
for_system_time_expr:
AS OF_SYM trans_or_timestamp simple_expr
{
Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_AS_OF, $4, $5);
Lex->vers_conditions.init(FOR_SYSTEM_TIME_AS_OF, $3, $4);
}
| FOR_SYSTEM_TIME_SYM
AS OF_SYM
NOW_SYM
| AS OF_SYM NOW_SYM
{
Item *item= new (thd->mem_root) Item_func_now_local(thd, 6);
if (item == NULL)
MYSQL_YYABORT;
Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_AS_OF, UNIT_TIMESTAMP, item);
Lex->vers_conditions.init(FOR_SYSTEM_TIME_AS_OF, UNIT_TIMESTAMP, item);
}
| FOR_SYSTEM_TIME_SYM ALL
| ALL
{
Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_ALL, UNIT_TIMESTAMP);
Lex->vers_conditions.init(FOR_SYSTEM_TIME_ALL, UNIT_TIMESTAMP);
}
| FOR_SYSTEM_TIME_SYM
FROM
trans_or_timestamp
simple_expr
TO_SYM
trans_or_timestamp
simple_expr
| FROM trans_or_timestamp simple_expr
TO_SYM trans_or_timestamp simple_expr
{
if ($3 != $6)
if ($2 != $5)
{
Lex->parse_error(ER_VERS_RANGE_UNITS_MISMATCH);
MYSQL_YYABORT;
}
Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_FROM_TO, $3, $4, $7);
Lex->vers_conditions.init(FOR_SYSTEM_TIME_FROM_TO, $2, $3, $6);
}
| FOR_SYSTEM_TIME_SYM
trans_or_timestamp
FROM
simple_expr
TO_SYM
simple_expr
| trans_or_timestamp
FROM simple_expr
TO_SYM simple_expr
{
Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_FROM_TO, $2, $4, $6);
Lex->vers_conditions.init(FOR_SYSTEM_TIME_FROM_TO, $1, $3, $5);
}
| FOR_SYSTEM_TIME_SYM
BETWEEN_SYM
trans_or_timestamp
simple_expr
AND_SYM
trans_or_timestamp
simple_expr
| BETWEEN_SYM trans_or_timestamp simple_expr
AND_SYM trans_or_timestamp simple_expr
{
if ($3 != $6)
if ($2 != $5)
{
Lex->parse_error(ER_VERS_RANGE_UNITS_MISMATCH);
MYSQL_YYABORT;
}
Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_BETWEEN, $3, $4, $7);
Lex->vers_conditions.init(FOR_SYSTEM_TIME_BETWEEN, $2, $3, $6);
}
| FOR_SYSTEM_TIME_SYM
trans_or_timestamp
BETWEEN_SYM
simple_expr
AND_SYM
simple_expr
| trans_or_timestamp
BETWEEN_SYM simple_expr
AND_SYM simple_expr
{
Lex->current_select->vers_conditions.init(FOR_SYSTEM_TIME_BETWEEN, $2, $4, $6);
Lex->vers_conditions.init(FOR_SYSTEM_TIME_BETWEEN, $1, $3, $5);
}
;
......@@ -11284,10 +11286,11 @@ table_factor:
table_primary_ident:
{
DBUG_ASSERT(Select);
SELECT_LEX *sel= Select;
sel->table_join_options= 0;
}
table_ident opt_use_partition opt_table_alias opt_key_definition
table_ident opt_use_partition opt_table_alias opt_key_definition opt_for_system_time_clause
{
if (!($$= Select->add_table_to_list(thd, $2, $4,
Select->get_table_join_options(),
......@@ -11297,6 +11300,8 @@ table_primary_ident:
$3)))
MYSQL_YYABORT;
Select->add_joined_table($$);
if ($6)
$$->vers_conditions= Lex->vers_conditions;
}
;
......@@ -13007,6 +13012,8 @@ truncate:
lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_truncate_table();
if (lex->m_sql_cmd == NULL)
MYSQL_YYABORT;
if ($5)
Select->vers_conditions= Lex->vers_conditions;
}
;
......
......@@ -1856,7 +1856,7 @@ enum vers_range_unit_t
UNIT_TRX_ID
};
/** System versioning support. */
/** last_leaf_for_name_resolutioning support. */
struct vers_select_conds_t
{
vers_range_type_t type;
......@@ -2344,6 +2344,9 @@ struct TABLE_LIST
TABLE_LIST *first_leaf_for_name_resolution();
TABLE_LIST *last_leaf_for_name_resolution();
/* System Versioning */
vers_select_conds_t vers_conditions;
/**
@brief
Find the bottom in the chain of embedded table VIEWs.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment