mirror of
https://github.com/MariaDB/server.git
synced 2025-08-07 00:04:31 +03:00
SQL: derived tables improvements [closes #185]
This commit is contained in:
@@ -19,13 +19,13 @@ execute stmt;
|
||||
emp_id name mgr
|
||||
4 john 1
|
||||
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
|
||||
1 bill 0
|
||||
2 bill 1
|
||||
3 kate 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;
|
||||
execute stmt;
|
||||
emp_id name mgr
|
||||
@@ -80,8 +80,7 @@ as
|
||||
from emp as ee, ancestors as a
|
||||
where ee.mgr = a.emp_id
|
||||
)
|
||||
select * from ancestors
|
||||
";
|
||||
select * from ancestors";
|
||||
prepare stmt from @tmp;
|
||||
execute stmt;
|
||||
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
|
||||
where ee.mgr = a.emp_id
|
||||
)
|
||||
select * from ancestors for system_time as of timestamp @ts;
|
||||
select * from ancestors;
|
||||
emp_id name mgr
|
||||
1 bill 0
|
||||
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
|
||||
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;
|
||||
emp_id name mgr
|
||||
@@ -127,3 +125,41 @@ emp_id name mgr
|
||||
3 kate 1
|
||||
drop prepare stmt;
|
||||
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;
|
@@ -16,8 +16,8 @@ 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;
|
||||
|
||||
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 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";
|
||||
prepare stmt from @tmp; execute stmt; drop prepare stmt;
|
||||
|
||||
with recursive ancestors as (select * from emp) select * from ancestors;
|
||||
@@ -54,8 +54,7 @@ as
|
||||
from emp as ee, ancestors as a
|
||||
where ee.mgr = a.emp_id
|
||||
)
|
||||
select * from ancestors
|
||||
";
|
||||
select * from ancestors";
|
||||
prepare stmt from @tmp; execute stmt; drop prepare stmt;
|
||||
|
||||
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
|
||||
where ee.mgr = a.emp_id
|
||||
)
|
||||
select * from ancestors for system_time as of timestamp @ts;
|
||||
select * from ancestors;
|
||||
set @tmp= "
|
||||
with recursive
|
||||
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
|
||||
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;
|
||||
|
||||
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;
|
@@ -1 +0,0 @@
|
||||
--vers-hide=implicit
|
@@ -7538,6 +7538,9 @@ ER_VERS_WRONG_QUERY_TYPE
|
||||
ER_VERS_VIEW_PROHIBITED
|
||||
eng "Creating VIEW %`s is prohibited!"
|
||||
|
||||
ER_VERS_DERIVED_PROHIBITED
|
||||
eng "Derived table is prohibited!"
|
||||
|
||||
ER_VERS_WRONG_QUERY
|
||||
eng "Wrong versioned query: %s"
|
||||
|
||||
|
@@ -7597,6 +7597,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
|
||||
slex->vers_conditions.type : tl->vers_conditions.type;
|
||||
|
||||
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)) ||
|
||||
((fl & HIDDEN_FLAG) && (
|
||||
!sys_field ||
|
||||
|
@@ -713,23 +713,127 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
|
||||
cursor= cursor->next_local)
|
||||
cursor->outer_join|= JOIN_TYPE_OUTER;
|
||||
}
|
||||
if ((thd->stmt_arena->is_stmt_prepare() ||
|
||||
!thd->stmt_arena->is_stmt_execute()) &&
|
||||
!derived->is_view() && sl->table_list.elements > 0)
|
||||
|
||||
// System Versioning begin
|
||||
#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;
|
||||
if (tl->table && tl->table->versioned())
|
||||
// Similar logic as in mysql_create_view()
|
||||
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);
|
||||
sl->item_list.push_back(new (thd->mem_root) Item_field(
|
||||
thd, &sl->context, db, alias, s->vers_start_field()->field_name));
|
||||
sl->item_list.push_back(new (thd->mem_root) Item_field(
|
||||
thd, &sl->context, db, alias, s->vers_end_field()->field_name));
|
||||
}
|
||||
if (!expli_start && (res= sl->vers_push_field(thd, impli_table, impli_start)))
|
||||
goto exit;
|
||||
if (!expli_end && (res= sl->vers_push_field(thd, impli_table, impli_end)))
|
||||
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;
|
||||
|
@@ -2298,6 +2298,7 @@ void st_select_lex::init_select()
|
||||
join= 0;
|
||||
lock_type= TL_READ_DEFAULT;
|
||||
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)
|
||||
{
|
||||
char buf[MAX_FIELD_NAME];
|
||||
Item_field *fld= new (thd->mem_root) Item_field(thd, &context,
|
||||
table->db, table->alias, field_name);
|
||||
if (!fld)
|
||||
|
@@ -993,6 +993,7 @@ public:
|
||||
|
||||
/* System Versioning */
|
||||
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);
|
||||
|
||||
void init_query();
|
||||
|
@@ -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)
|
||||
{
|
||||
if (table->table && table->table->versioned())
|
||||
@@ -1059,7 +1081,7 @@ JOIN::prepare(TABLE_LIST *tables_init,
|
||||
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)
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
|
@@ -454,6 +454,9 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
|
||||
}
|
||||
|
||||
{ /* 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;
|
||||
const char *impli_start, *impli_end;
|
||||
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)
|
||||
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))
|
||||
continue;
|
||||
DBUG_ASSERT(fld->field_name);
|
||||
@@ -567,10 +570,15 @@ expli_table_err:
|
||||
|
||||
if (expli_table)
|
||||
impli_table= expli_table;
|
||||
|
||||
if (impli_table)
|
||||
{
|
||||
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 */
|
||||
|
||||
view= lex->unlink_first_table(&link_to_local);
|
||||
|
@@ -1853,12 +1853,15 @@ struct vers_select_conds_t
|
||||
{
|
||||
vers_range_type_t type;
|
||||
vers_range_unit_t unit;
|
||||
bool import_outer:1;
|
||||
bool from_inner:1;
|
||||
Item *start, *end;
|
||||
|
||||
void empty()
|
||||
{
|
||||
type= FOR_SYSTEM_TIME_UNSPECIFIED;
|
||||
unit= UNIT_TIMESTAMP;
|
||||
import_outer= from_inner= false;
|
||||
start= end= NULL;
|
||||
}
|
||||
|
||||
@@ -1872,6 +1875,7 @@ struct vers_select_conds_t
|
||||
unit= u;
|
||||
start= s;
|
||||
end= e;
|
||||
import_outer= from_inner= false;
|
||||
}
|
||||
|
||||
bool init_from_sysvar(THD *thd);
|
||||
|
Reference in New Issue
Block a user