Skip to content

Commit 7153ff8

Browse files
committed
SQL: derived tables improvements [closes #185]
1 parent 79688b0 commit 7153ff8

File tree

11 files changed

+247
-35
lines changed

11 files changed

+247
-35
lines changed

mysql-test/suite/versioning/r/derived_tables.result renamed to mysql-test/suite/versioning/r/derived.result

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ execute stmt;
1919
emp_id name mgr
2020
4 john 1
2121
drop prepare stmt;
22-
with ancestors as (select * from emp for system_time all) select * from ancestors for system_time all;
22+
with ancestors as (select * from emp for system_time all) select * from ancestors;
2323
emp_id name mgr
2424
1 bill 0
2525
2 bill 1
2626
3 kate 1
2727
4 john 1
28-
set @tmp= "with ancestors as (select * from emp for system_time all) select * from ancestors for system_time all";
28+
set @tmp= "with ancestors as (select * from emp for system_time all) select * from ancestors";
2929
prepare stmt from @tmp;
3030
execute stmt;
3131
emp_id name mgr
@@ -80,8 +80,7 @@ as
8080
from emp as ee, ancestors as a
8181
where ee.mgr = a.emp_id
8282
)
83-
select * from ancestors
84-
";
83+
select * from ancestors";
8584
prepare stmt from @tmp;
8685
execute stmt;
8786
emp_id name mgr
@@ -99,7 +98,7 @@ select ee.emp_id, ee.name, ee.mgr
9998
from emp as ee for system_time as of timestamp @ts, ancestors as a for system_time as of timestamp @ts
10099
where ee.mgr = a.emp_id
101100
)
102-
select * from ancestors for system_time as of timestamp @ts;
101+
select * from ancestors;
103102
emp_id name mgr
104103
1 bill 0
105104
2 bill 1
@@ -117,8 +116,7 @@ as
117116
from emp as ee for system_time as of timestamp @ts, ancestors as a for system_time as of timestamp @ts
118117
where ee.mgr = a.emp_id
119118
)
120-
select * from ancestors for system_time as of timestamp @ts;
121-
";
119+
select * from ancestors";
122120
prepare stmt from @tmp;
123121
execute stmt;
124122
emp_id name mgr
@@ -127,3 +125,41 @@ emp_id name mgr
127125
3 kate 1
128126
drop prepare stmt;
129127
drop table emp;
128+
create or replace table t1 (x int) with system versioning;
129+
create or replace table t2 (y int) with system versioning;
130+
insert into t1 values (1);
131+
set @t0= now(6);
132+
insert into t1 values (2);
133+
delete from t1 where x = 1;
134+
insert into t2 values (10);
135+
select * from (select *, t1.sys_trx_end, t1.sys_trx_end as endo from t1) as s0;
136+
ERROR HY000: Derived table is prohibited: multiple end system fields `t1.sys_trx_end`, `t1.sys_trx_end` in query!
137+
select * from (select *, t1.sys_trx_end, t2.sys_trx_start from t1, t2) as s0;
138+
ERROR HY000: Derived table is prohibited: system fields from multiple tables `t1`, `t2` in query!
139+
select * from (select * from t1 for system_time as of timestamp @t0, t2) as s0;
140+
x y
141+
1 10
142+
select * from (select *, t1.sys_trx_end from t2, t1 for system_time as of timestamp @t0) as s0;
143+
y x
144+
10 1
145+
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;
146+
y x
147+
10 1
148+
set @q= concat("create view vt1 as select * from t1 for system_time as of timestamp '", @t0, "'");
149+
prepare q from @q;
150+
execute q;
151+
drop prepare q;
152+
select * from vt1;
153+
x
154+
1
155+
select * from (select * from vt1, t2) as s0;
156+
x y
157+
1 10
158+
select * from (select *, vt1.sys_trx_end from t2, vt1) as s0;
159+
y x
160+
10 1
161+
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;
162+
y x
163+
10 1
164+
drop table t1, t2;
165+
drop view vt1;

mysql-test/suite/versioning/t/derived_tables.test renamed to mysql-test/suite/versioning/t/derived.test

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ with ancestors as (select * from emp) select * from ancestors;
1616
set @tmp= "with ancestors as (select * from emp) select * from ancestors";
1717
prepare stmt from @tmp; execute stmt; drop prepare stmt;
1818

19-
with ancestors as (select * from emp for system_time all) select * from ancestors for system_time all;
20-
set @tmp= "with ancestors as (select * from emp for system_time all) select * from ancestors for system_time all";
19+
with ancestors as (select * from emp for system_time all) select * from ancestors;
20+
set @tmp= "with ancestors as (select * from emp for system_time all) select * from ancestors";
2121
prepare stmt from @tmp; execute stmt; drop prepare stmt;
2222

2323
with recursive ancestors as (select * from emp) select * from ancestors;
@@ -54,8 +54,7 @@ as
5454
from emp as ee, ancestors as a
5555
where ee.mgr = a.emp_id
5656
)
57-
select * from ancestors
58-
";
57+
select * from ancestors";
5958
prepare stmt from @tmp; execute stmt; drop prepare stmt;
6059

6160
with recursive
@@ -70,7 +69,7 @@ as
7069
from emp as ee for system_time as of timestamp @ts, ancestors as a for system_time as of timestamp @ts
7170
where ee.mgr = a.emp_id
7271
)
73-
select * from ancestors for system_time as of timestamp @ts;
72+
select * from ancestors;
7473
set @tmp= "
7574
with recursive
7675
ancestors
@@ -84,8 +83,43 @@ as
8483
from emp as ee for system_time as of timestamp @ts, ancestors as a for system_time as of timestamp @ts
8584
where ee.mgr = a.emp_id
8685
)
87-
select * from ancestors for system_time as of timestamp @ts;
88-
";
86+
select * from ancestors";
8987
prepare stmt from @tmp; execute stmt; drop prepare stmt;
9088

9189
drop table emp;
90+
91+
create or replace table t1 (x int) with system versioning;
92+
create or replace table t2 (y int) with system versioning;
93+
insert into t1 values (1);
94+
set @t0= now(6);
95+
insert into t1 values (2);
96+
delete from t1 where x = 1;
97+
insert into t2 values (10);
98+
99+
--error ER_VERS_DERIVED_PROHIBITED
100+
select * from (select *, t1.sys_trx_end, t1.sys_trx_end as endo from t1) as s0;
101+
--error ER_VERS_DERIVED_PROHIBITED
102+
select * from (select *, t1.sys_trx_end, t2.sys_trx_start from t1, t2) as s0;
103+
104+
# system_time propagation from inner to outer
105+
select * from (select * from t1 for system_time as of timestamp @t0, t2) as s0;
106+
# leading table selection
107+
select * from (select *, t1.sys_trx_end from t2, t1 for system_time as of timestamp @t0) as s0;
108+
# system_time propagation from outer to inner
109+
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;
110+
111+
# VIEW instead of t1
112+
set @q= concat("create view vt1 as select * from t1 for system_time as of timestamp '", @t0, "'");
113+
prepare q from @q; execute q; drop prepare q;
114+
115+
# system_time propagation from view
116+
select * from vt1;
117+
# system_time propagation from inner to outer
118+
select * from (select * from vt1, t2) as s0;
119+
# leading table selection
120+
select * from (select *, vt1.sys_trx_end from t2, vt1) as s0;
121+
# system_time propagation from outer to inner
122+
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;
123+
124+
drop table t1, t2;
125+
drop view vt1;

mysql-test/suite/versioning/t/derived_tables.opt

Lines changed: 0 additions & 1 deletion
This file was deleted.

sql/share/errmsg-utf8.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7538,6 +7538,9 @@ ER_VERS_WRONG_QUERY_TYPE
75387538
ER_VERS_VIEW_PROHIBITED
75397539
eng "Creating VIEW %`s is prohibited!"
75407540

7541+
ER_VERS_DERIVED_PROHIBITED
7542+
eng "Derived table is prohibited!"
7543+
75417544
ER_VERS_WRONG_QUERY
75427545
eng "Wrong versioned query: %s"
75437546

sql/sql_base.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7597,6 +7597,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
75977597
slex->vers_conditions.type : tl->vers_conditions.type;
75987598

75997599
if ((sys_field && (thd->lex->sql_command == SQLCOM_CREATE_VIEW ||
7600+
slex->nest_level > 0 ||
76007601
vers_hide == VERS_HIDE_FULL && thd->lex->sql_command != SQLCOM_CREATE_TABLE)) ||
76017602
((fl & HIDDEN_FLAG) && (
76027603
!sys_field ||

sql/sql_derived.cc

Lines changed: 117 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -713,23 +713,127 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
713713
cursor= cursor->next_local)
714714
cursor->outer_join|= JOIN_TYPE_OUTER;
715715
}
716-
if ((thd->stmt_arena->is_stmt_prepare() ||
717-
!thd->stmt_arena->is_stmt_execute()) &&
718-
!derived->is_view() && sl->table_list.elements > 0)
716+
717+
// System Versioning begin
718+
#pragma GCC diagnostic push
719+
#pragma GCC diagnostic ignored "-Wformat"
720+
#pragma GCC diagnostic ignored "-Wformat-extra-args"
721+
if ((thd->stmt_arena->is_stmt_prepare() || !thd->stmt_arena->is_stmt_execute())
722+
&& sl->table_list.elements > 0)
719723
{
720-
TABLE_LIST *tl= sl->table_list.first;
721-
if (tl->table && tl->table->versioned())
724+
// Similar logic as in mysql_create_view()
725+
TABLE_LIST *impli_table= NULL, *expli_table= NULL;
726+
const char *impli_start, *impli_end;
727+
Item_field *expli_start= NULL, *expli_end= NULL;
728+
729+
for (TABLE_LIST *table= sl->table_list.first; table; table= table->next_local)
730+
{
731+
if (!table->table || !table->table->versioned())
732+
continue;
733+
734+
const char *table_start= table->table->vers_start_field()->field_name;
735+
const char *table_end= table->table->vers_end_field()->field_name;
736+
if (!impli_table)
737+
{
738+
impli_table= table;
739+
impli_start= table_start;
740+
impli_end= table_end;
741+
}
742+
743+
/* Implicitly add versioning fields if needed */
744+
Item *item;
745+
List_iterator_fast<Item> it(sl->item_list);
746+
747+
DBUG_ASSERT(table->alias);
748+
while ((item= it++))
749+
{
750+
if (item->real_item()->type() != Item::FIELD_ITEM)
751+
continue;
752+
Item_field *fld= (Item_field*) (item->real_item());
753+
if (fld->table_name && 0 != my_strcasecmp(table_alias_charset, table->alias, fld->table_name))
754+
continue;
755+
DBUG_ASSERT(fld->field_name);
756+
if (0 == my_strcasecmp(system_charset_info, table_start, fld->field_name))
757+
{
758+
if (expli_start)
759+
{
760+
my_printf_error(
761+
ER_VERS_DERIVED_PROHIBITED,
762+
"Derived table is prohibited: multiple start system fields `%s.%s`, `%s.%s` in query!", MYF(0),
763+
expli_table->alias,
764+
expli_start->field_name,
765+
table->alias,
766+
fld->field_name);
767+
res= true;
768+
goto exit;
769+
}
770+
if (expli_table)
771+
{
772+
if (expli_table != table)
773+
{
774+
expli_table_err:
775+
my_printf_error(
776+
ER_VERS_DERIVED_PROHIBITED,
777+
"Derived table is prohibited: system fields from multiple tables %`s, %`s in query!", MYF(0),
778+
expli_table->alias,
779+
table->alias);
780+
res= true;
781+
goto exit;
782+
}
783+
}
784+
else
785+
expli_table= table;
786+
expli_start= fld;
787+
impli_end= table_end;
788+
}
789+
else if (0 == my_strcasecmp(system_charset_info, table_end, fld->field_name))
790+
{
791+
if (expli_end)
792+
{
793+
my_printf_error(
794+
ER_VERS_DERIVED_PROHIBITED,
795+
"Derived table is prohibited: multiple end system fields `%s.%s`, `%s.%s` in query!", MYF(0),
796+
expli_table->alias,
797+
expli_end->field_name,
798+
table->alias,
799+
fld->field_name);
800+
res= true;
801+
goto exit;
802+
}
803+
if (expli_table)
804+
{
805+
if (expli_table != table)
806+
goto expli_table_err;
807+
}
808+
else
809+
expli_table= table;
810+
expli_end= fld;
811+
impli_start= table_start;
812+
}
813+
} // while ((item= it++))
814+
} // for (TABLE_LIST *table)
815+
816+
if (expli_table)
817+
impli_table= expli_table;
818+
819+
if (impli_table)
722820
{
723-
TABLE_SHARE *s= tl->table->s;
724-
const char *db= tl->db;
725-
const char *alias= tl->alias;
726821
Query_arena_stmt on_stmt_arena(thd);
727-
sl->item_list.push_back(new (thd->mem_root) Item_field(
728-
thd, &sl->context, db, alias, s->vers_start_field()->field_name));
729-
sl->item_list.push_back(new (thd->mem_root) Item_field(
730-
thd, &sl->context, db, alias, s->vers_end_field()->field_name));
822+
if (!expli_start && (res= sl->vers_push_field(thd, impli_table, impli_start)))
823+
goto exit;
824+
if (!expli_end && (res= sl->vers_push_field(thd, impli_table, impli_end)))
825+
goto exit;
826+
827+
if (impli_table->vers_conditions)
828+
sl->vers_derived_conds= impli_table->vers_conditions;
829+
else if (sl->vers_conditions)
830+
sl->vers_derived_conds= sl->vers_conditions;
831+
else
832+
sl->vers_conditions.import_outer= true;
731833
}
732-
}
834+
} // if (sl->table_list.elements > 0)
835+
#pragma GCC diagnostic pop
836+
// System Versioning end
733837
}
734838

735839
unit->derived= derived;

sql/sql_lex.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2298,6 +2298,7 @@ void st_select_lex::init_select()
22982298
join= 0;
22992299
lock_type= TL_READ_DEFAULT;
23002300
vers_conditions.empty();
2301+
vers_derived_conds.empty();
23012302
}
23022303

23032304
/*
@@ -7048,7 +7049,6 @@ bool LEX::sp_add_cfetch(THD *thd, const LEX_STRING &name)
70487049

70497050
bool SELECT_LEX::vers_push_field(THD *thd, TABLE_LIST *table, const char* field_name)
70507051
{
7051-
char buf[MAX_FIELD_NAME];
70527052
Item_field *fld= new (thd->mem_root) Item_field(thd, &context,
70537053
table->db, table->alias, field_name);
70547054
if (!fld)

sql/sql_lex.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -993,6 +993,7 @@ class st_select_lex: public st_select_lex_node
993993

994994
/* System Versioning */
995995
vers_select_conds_t vers_conditions;
996+
vers_select_conds_t vers_derived_conds;
996997
bool vers_push_field(THD *thd, TABLE_LIST *table, const char* field_name);
997998

998999
void init_query();

sql/sql_select.cc

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,28 @@ int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr,
771771
}
772772
}
773773

774+
SELECT_LEX *outer_slex= slex->next_select_in_list();
775+
if (outer_slex)
776+
{
777+
if (slex->vers_derived_conds)
778+
{
779+
// Propagate derived conditions to outer SELECT_LEX:
780+
if (!outer_slex->vers_conditions)
781+
{
782+
(outer_slex->vers_conditions= slex->vers_derived_conds).
783+
from_inner= true;
784+
}
785+
}
786+
else if (slex->vers_conditions.import_outer)
787+
{
788+
// Propagate query conditions from nearest outer SELECT_LEX:
789+
while (outer_slex && (!outer_slex->vers_conditions || outer_slex->vers_conditions.from_inner))
790+
outer_slex= outer_slex->next_select_in_list();
791+
if (outer_slex)
792+
slex->vers_conditions= outer_slex->vers_conditions;
793+
}
794+
}
795+
774796
for (table= tables; table; table= table->next_local)
775797
{
776798
if (table->table && table->table->versioned())
@@ -1059,7 +1081,7 @@ JOIN::prepare(TABLE_LIST *tables_init,
10591081
remove_redundant_subquery_clauses(select_lex);
10601082
}
10611083

1062-
/* Handle FOR SYSTEM_TIME clause. */
1084+
/* System Versioning: handle FOR SYSTEM_TIME clause. */
10631085
if (vers_setup_select(thd, tables_list, &conds, select_lex) < 0)
10641086
DBUG_RETURN(-1);
10651087

0 commit comments

Comments
 (0)