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

SQL: derived tables improvements [closes #185]

This commit is contained in:
Aleksey Midenkov
2017-04-28 12:07:04 +03:00
parent 79688b0546
commit 7153ff85a1
11 changed files with 247 additions and 35 deletions

View File

@ -19,13 +19,13 @@ execute stmt;
emp_id name mgr emp_id name mgr
4 john 1 4 john 1
drop prepare stmt; drop prepare stmt;
with ancestors as (select * from emp for system_time all) select * from ancestors for system_time all; with ancestors as (select * from emp for system_time all) select * from ancestors;
emp_id name mgr emp_id name mgr
1 bill 0 1 bill 0
2 bill 1 2 bill 1
3 kate 1 3 kate 1
4 john 1 4 john 1
set @tmp= "with ancestors as (select * from emp for system_time all) select * from ancestors for system_time all"; set @tmp= "with ancestors as (select * from emp for system_time all) select * from ancestors";
prepare stmt from @tmp; prepare stmt from @tmp;
execute stmt; execute stmt;
emp_id name mgr emp_id name mgr
@ -80,8 +80,7 @@ as
from emp as ee, ancestors as a from emp as ee, ancestors as a
where ee.mgr = a.emp_id where ee.mgr = a.emp_id
) )
select * from ancestors select * from ancestors";
";
prepare stmt from @tmp; prepare stmt from @tmp;
execute stmt; execute stmt;
emp_id name mgr emp_id name mgr
@ -99,7 +98,7 @@ select ee.emp_id, ee.name, ee.mgr
from emp as ee for system_time as of timestamp @ts, ancestors as a for system_time as of timestamp @ts from emp as ee for system_time as of timestamp @ts, ancestors as a for system_time as of timestamp @ts
where ee.mgr = a.emp_id where ee.mgr = a.emp_id
) )
select * from ancestors for system_time as of timestamp @ts; select * from ancestors;
emp_id name mgr emp_id name mgr
1 bill 0 1 bill 0
2 bill 1 2 bill 1
@ -117,8 +116,7 @@ as
from emp as ee for system_time as of timestamp @ts, ancestors as a for system_time as of timestamp @ts from emp as ee for system_time as of timestamp @ts, ancestors as a for system_time as of timestamp @ts
where ee.mgr = a.emp_id where ee.mgr = a.emp_id
) )
select * from ancestors for system_time as of timestamp @ts; select * from ancestors";
";
prepare stmt from @tmp; prepare stmt from @tmp;
execute stmt; execute stmt;
emp_id name mgr emp_id name mgr
@ -127,3 +125,41 @@ emp_id name mgr
3 kate 1 3 kate 1
drop prepare stmt; drop prepare stmt;
drop table emp; 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);
insert into t1 values (2);
delete from t1 where x = 1;
insert into t2 values (10);
select * from (select *, t1.sys_trx_end, t1.sys_trx_end as endo from t1) as s0;
ERROR HY000: Derived table is prohibited: multiple end system fields `t1.sys_trx_end`, `t1.sys_trx_end` in query!
select * from (select *, t1.sys_trx_end, t2.sys_trx_start from t1, t2) as s0;
ERROR HY000: Derived table is prohibited: system fields from multiple tables `t1`, `t2` in query!
select * from (select * from t1 for system_time as of timestamp @t0, t2) as s0;
x y
1 10
select * from (select *, t1.sys_trx_end from t2, t1 for system_time as of timestamp @t0) as s0;
y x
10 1
select * from (select *, t1.sys_trx_start from t2 for system_time as of now, t1) as s0 query for system_time as of timestamp @t0;
y x
10 1
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;
select * from vt1;
x
1
select * from (select * from vt1, t2) as s0;
x y
1 10
select * from (select *, vt1.sys_trx_end from t2, vt1) as s0;
y x
10 1
select * from (select *, vt1.sys_trx_start from t2 for system_time as of now, vt1) as s0 query for system_time as of timestamp @t0;
y x
10 1
drop table t1, t2;
drop view vt1;

View File

@ -16,8 +16,8 @@ with ancestors as (select * from emp) select * from ancestors;
set @tmp= "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; prepare stmt from @tmp; execute stmt; drop prepare stmt;
with ancestors as (select * from emp for system_time all) select * from ancestors for system_time all; 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 for system_time all"; set @tmp= "with ancestors as (select * from emp for system_time all) select * from ancestors";
prepare stmt from @tmp; execute stmt; drop prepare stmt; prepare stmt from @tmp; execute stmt; drop prepare stmt;
with recursive ancestors as (select * from emp) select * from ancestors; with recursive ancestors as (select * from emp) select * from ancestors;
@ -54,8 +54,7 @@ as
from emp as ee, ancestors as a from emp as ee, ancestors as a
where ee.mgr = a.emp_id where ee.mgr = a.emp_id
) )
select * from ancestors select * from ancestors";
";
prepare stmt from @tmp; execute stmt; drop prepare stmt; prepare stmt from @tmp; execute stmt; drop prepare stmt;
with recursive with recursive
@ -70,7 +69,7 @@ as
from emp as ee for system_time as of timestamp @ts, ancestors as a for system_time as of timestamp @ts from emp as ee for system_time as of timestamp @ts, ancestors as a for system_time as of timestamp @ts
where ee.mgr = a.emp_id where ee.mgr = a.emp_id
) )
select * from ancestors for system_time as of timestamp @ts; select * from ancestors;
set @tmp= " set @tmp= "
with recursive with recursive
ancestors ancestors
@ -84,8 +83,43 @@ as
from emp as ee for system_time as of timestamp @ts, ancestors as a for system_time as of timestamp @ts from emp as ee for system_time as of timestamp @ts, ancestors as a for system_time as of timestamp @ts
where ee.mgr = a.emp_id where ee.mgr = a.emp_id
) )
select * from ancestors for system_time as of timestamp @ts; select * from ancestors";
";
prepare stmt from @tmp; execute stmt; drop prepare stmt; prepare stmt from @tmp; execute stmt; drop prepare stmt;
drop table emp; 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);
insert into t1 values (2);
delete from t1 where x = 1;
insert into t2 values (10);
--error ER_VERS_DERIVED_PROHIBITED
select * from (select *, t1.sys_trx_end, t1.sys_trx_end as endo from t1) as s0;
--error ER_VERS_DERIVED_PROHIBITED
select * from (select *, t1.sys_trx_end, t2.sys_trx_start from t1, t2) as s0;
# system_time propagation from inner to outer
select * from (select * from t1 for system_time as of timestamp @t0, t2) as s0;
# leading table selection
select * from (select *, t1.sys_trx_end from t2, t1 for system_time as of timestamp @t0) as s0;
# system_time propagation from outer to inner
select * from (select *, t1.sys_trx_start from t2 for system_time as of now, t1) as s0 query for system_time as of timestamp @t0;
# 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;
# system_time propagation from view
select * from vt1;
# system_time propagation from inner to outer
select * from (select * from vt1, t2) as s0;
# leading table selection
select * from (select *, vt1.sys_trx_end from t2, vt1) as s0;
# system_time propagation from outer to inner
select * from (select *, vt1.sys_trx_start from t2 for system_time as of now, vt1) as s0 query for system_time as of timestamp @t0;
drop table t1, t2;
drop view vt1;

View File

@ -1 +0,0 @@
--vers-hide=implicit

View File

@ -7538,6 +7538,9 @@ ER_VERS_WRONG_QUERY_TYPE
ER_VERS_VIEW_PROHIBITED ER_VERS_VIEW_PROHIBITED
eng "Creating VIEW %`s is prohibited!" eng "Creating VIEW %`s is prohibited!"
ER_VERS_DERIVED_PROHIBITED
eng "Derived table is prohibited!"
ER_VERS_WRONG_QUERY ER_VERS_WRONG_QUERY
eng "Wrong versioned query: %s" eng "Wrong versioned query: %s"

View File

@ -7597,6 +7597,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
slex->vers_conditions.type : tl->vers_conditions.type; slex->vers_conditions.type : tl->vers_conditions.type;
if ((sys_field && (thd->lex->sql_command == SQLCOM_CREATE_VIEW || if ((sys_field && (thd->lex->sql_command == SQLCOM_CREATE_VIEW ||
slex->nest_level > 0 ||
vers_hide == VERS_HIDE_FULL && thd->lex->sql_command != SQLCOM_CREATE_TABLE)) || vers_hide == VERS_HIDE_FULL && thd->lex->sql_command != SQLCOM_CREATE_TABLE)) ||
((fl & HIDDEN_FLAG) && ( ((fl & HIDDEN_FLAG) && (
!sys_field || !sys_field ||

View File

@ -713,23 +713,127 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
cursor= cursor->next_local) cursor= cursor->next_local)
cursor->outer_join|= JOIN_TYPE_OUTER; cursor->outer_join|= JOIN_TYPE_OUTER;
} }
if ((thd->stmt_arena->is_stmt_prepare() ||
!thd->stmt_arena->is_stmt_execute()) && // System Versioning begin
!derived->is_view() && sl->table_list.elements > 0) #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
#pragma GCC diagnostic ignored "-Wformat-extra-args"
if ((thd->stmt_arena->is_stmt_prepare() || !thd->stmt_arena->is_stmt_execute())
&& sl->table_list.elements > 0)
{ {
TABLE_LIST *tl= sl->table_list.first; // Similar logic as in mysql_create_view()
if (tl->table && tl->table->versioned()) TABLE_LIST *impli_table= NULL, *expli_table= NULL;
const char *impli_start, *impli_end;
Item_field *expli_start= NULL, *expli_end= NULL;
for (TABLE_LIST *table= sl->table_list.first; table; table= table->next_local)
{
if (!table->table || !table->table->versioned())
continue;
const char *table_start= table->table->vers_start_field()->field_name;
const char *table_end= table->table->vers_end_field()->field_name;
if (!impli_table)
{
impli_table= table;
impli_start= table_start;
impli_end= table_end;
}
/* Implicitly add versioning fields if needed */
Item *item;
List_iterator_fast<Item> it(sl->item_list);
DBUG_ASSERT(table->alias);
while ((item= it++))
{
if (item->real_item()->type() != Item::FIELD_ITEM)
continue;
Item_field *fld= (Item_field*) (item->real_item());
if (fld->table_name && 0 != my_strcasecmp(table_alias_charset, table->alias, fld->table_name))
continue;
DBUG_ASSERT(fld->field_name);
if (0 == my_strcasecmp(system_charset_info, table_start, fld->field_name))
{
if (expli_start)
{
my_printf_error(
ER_VERS_DERIVED_PROHIBITED,
"Derived table is prohibited: multiple start system fields `%s.%s`, `%s.%s` in query!", MYF(0),
expli_table->alias,
expli_start->field_name,
table->alias,
fld->field_name);
res= true;
goto exit;
}
if (expli_table)
{
if (expli_table != table)
{
expli_table_err:
my_printf_error(
ER_VERS_DERIVED_PROHIBITED,
"Derived table is prohibited: system fields from multiple tables %`s, %`s in query!", MYF(0),
expli_table->alias,
table->alias);
res= true;
goto exit;
}
}
else
expli_table= table;
expli_start= fld;
impli_end= table_end;
}
else if (0 == my_strcasecmp(system_charset_info, table_end, fld->field_name))
{
if (expli_end)
{
my_printf_error(
ER_VERS_DERIVED_PROHIBITED,
"Derived table is prohibited: multiple end system fields `%s.%s`, `%s.%s` in query!", MYF(0),
expli_table->alias,
expli_end->field_name,
table->alias,
fld->field_name);
res= true;
goto exit;
}
if (expli_table)
{
if (expli_table != table)
goto expli_table_err;
}
else
expli_table= table;
expli_end= fld;
impli_start= table_start;
}
} // while ((item= it++))
} // for (TABLE_LIST *table)
if (expli_table)
impli_table= expli_table;
if (impli_table)
{ {
TABLE_SHARE *s= tl->table->s;
const char *db= tl->db;
const char *alias= tl->alias;
Query_arena_stmt on_stmt_arena(thd); Query_arena_stmt on_stmt_arena(thd);
sl->item_list.push_back(new (thd->mem_root) Item_field( if (!expli_start && (res= sl->vers_push_field(thd, impli_table, impli_start)))
thd, &sl->context, db, alias, s->vers_start_field()->field_name)); goto exit;
sl->item_list.push_back(new (thd->mem_root) Item_field( if (!expli_end && (res= sl->vers_push_field(thd, impli_table, impli_end)))
thd, &sl->context, db, alias, s->vers_end_field()->field_name)); goto exit;
if (impli_table->vers_conditions)
sl->vers_derived_conds= impli_table->vers_conditions;
else if (sl->vers_conditions)
sl->vers_derived_conds= sl->vers_conditions;
else
sl->vers_conditions.import_outer= true;
} }
} } // if (sl->table_list.elements > 0)
#pragma GCC diagnostic pop
// System Versioning end
} }
unit->derived= derived; unit->derived= derived;

View File

@ -2298,6 +2298,7 @@ void st_select_lex::init_select()
join= 0; join= 0;
lock_type= TL_READ_DEFAULT; lock_type= TL_READ_DEFAULT;
vers_conditions.empty(); vers_conditions.empty();
vers_derived_conds.empty();
} }
/* /*
@ -7048,7 +7049,6 @@ bool LEX::sp_add_cfetch(THD *thd, const LEX_STRING &name)
bool SELECT_LEX::vers_push_field(THD *thd, TABLE_LIST *table, const char* field_name) bool SELECT_LEX::vers_push_field(THD *thd, TABLE_LIST *table, const char* field_name)
{ {
char buf[MAX_FIELD_NAME];
Item_field *fld= new (thd->mem_root) Item_field(thd, &context, Item_field *fld= new (thd->mem_root) Item_field(thd, &context,
table->db, table->alias, field_name); table->db, table->alias, field_name);
if (!fld) if (!fld)

View File

@ -993,6 +993,7 @@ public:
/* System Versioning */ /* System Versioning */
vers_select_conds_t vers_conditions; vers_select_conds_t vers_conditions;
vers_select_conds_t vers_derived_conds;
bool vers_push_field(THD *thd, TABLE_LIST *table, const char* field_name); bool vers_push_field(THD *thd, TABLE_LIST *table, const char* field_name);
void init_query(); void init_query();

View File

@ -771,6 +771,28 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr,
} }
} }
SELECT_LEX *outer_slex= slex->next_select_in_list();
if (outer_slex)
{
if (slex->vers_derived_conds)
{
// Propagate derived conditions to outer SELECT_LEX:
if (!outer_slex->vers_conditions)
{
(outer_slex->vers_conditions= slex->vers_derived_conds).
from_inner= true;
}
}
else if (slex->vers_conditions.import_outer)
{
// Propagate query conditions from nearest outer SELECT_LEX:
while (outer_slex && (!outer_slex->vers_conditions || outer_slex->vers_conditions.from_inner))
outer_slex= outer_slex->next_select_in_list();
if (outer_slex)
slex->vers_conditions= outer_slex->vers_conditions;
}
}
for (table= tables; table; table= table->next_local) for (table= tables; table; table= table->next_local)
{ {
if (table->table && table->table->versioned()) if (table->table && table->table->versioned())
@ -1059,7 +1081,7 @@ JOIN::prepare(TABLE_LIST *tables_init,
remove_redundant_subquery_clauses(select_lex); remove_redundant_subquery_clauses(select_lex);
} }
/* Handle FOR SYSTEM_TIME clause. */ /* System Versioning: handle FOR SYSTEM_TIME clause. */
if (vers_setup_select(thd, tables_list, &conds, select_lex) < 0) if (vers_setup_select(thd, tables_list, &conds, select_lex) < 0)
DBUG_RETURN(-1); DBUG_RETURN(-1);

View File

@ -454,6 +454,9 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
} }
{ /* System Versioning begin */ { /* System Versioning begin */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
#pragma GCC diagnostic ignored "-Wformat-extra-args"
TABLE_LIST *impli_table= NULL, *expli_table= NULL; TABLE_LIST *impli_table= NULL, *expli_table= NULL;
const char *impli_start, *impli_end; const char *impli_start, *impli_end;
Item_field *expli_start= NULL, *expli_end= NULL; Item_field *expli_start= NULL, *expli_end= NULL;
@ -498,7 +501,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
{ {
if (item->real_item()->type() != Item::FIELD_ITEM) if (item->real_item()->type() != Item::FIELD_ITEM)
continue; continue;
Item_field *fld= (Item_field*) (item->real_item()); Item_field *fld= (Item_field*) item->real_item();
if (fld->table_name && 0 != my_strcasecmp(table_alias_charset, table->alias, fld->table_name)) if (fld->table_name && 0 != my_strcasecmp(table_alias_charset, table->alias, fld->table_name))
continue; continue;
DBUG_ASSERT(fld->field_name); DBUG_ASSERT(fld->field_name);
@ -567,10 +570,15 @@ expli_table_err:
if (expli_table) if (expli_table)
impli_table= expli_table; impli_table= expli_table;
if (!expli_start && select_lex->vers_push_field(thd, impli_table, impli_start))
goto err; if (impli_table)
if (!expli_end && select_lex->vers_push_field(thd, impli_table, impli_end)) {
goto err; if (!expli_start && select_lex->vers_push_field(thd, impli_table, impli_start))
goto err;
if (!expli_end && select_lex->vers_push_field(thd, impli_table, impli_end))
goto err;
}
#pragma GCC diagnostic pop
} /* System Versioning end */ } /* System Versioning end */
view= lex->unlink_first_table(&link_to_local); view= lex->unlink_first_table(&link_to_local);

View File

@ -1853,12 +1853,15 @@ struct vers_select_conds_t
{ {
vers_range_type_t type; vers_range_type_t type;
vers_range_unit_t unit; vers_range_unit_t unit;
bool import_outer:1;
bool from_inner:1;
Item *start, *end; Item *start, *end;
void empty() void empty()
{ {
type= FOR_SYSTEM_TIME_UNSPECIFIED; type= FOR_SYSTEM_TIME_UNSPECIFIED;
unit= UNIT_TIMESTAMP; unit= UNIT_TIMESTAMP;
import_outer= from_inner= false;
start= end= NULL; start= end= NULL;
} }
@ -1872,6 +1875,7 @@ struct vers_select_conds_t
unit= u; unit= u;
start= s; start= s;
end= e; end= e;
import_outer= from_inner= false;
} }
bool init_from_sysvar(THD *thd); bool init_from_sysvar(THD *thd);