Commit b2bd5229 authored by Nikita Malyavin's avatar Nikita Malyavin Committed by Sergei Golubchik

MDEV-16974 Application-time periods: UPDATE

parent 47e28a94
create or replace table t (id int, s date, e date, period for apptime(s,e));
insert into t values(1, '1999-01-01', '2018-12-12');
insert into t values(1, '1999-01-01', '2017-01-01');
insert into t values(1, '2017-01-01', '2019-01-01');
insert into t values(2, '1998-01-01', '2018-12-12');
insert into t values(3, '1997-01-01', '2015-01-01');
insert into t values(4, '2016-01-01', '2020-01-01');
insert into t values(5, '2010-01-01', '2015-01-01');
create or replace table t1 (id int, s date, e date, period for apptime(s,e));
insert t1 select * from t;
create or replace table t2 (id int, s date, e date, period for apptime(s,e));
insert t2 select * from t;
update t for portion of apptime from '2000-01-01' to '2018-01-01'
set id=id + 6;
select * from t;
id s e
1 1999-01-01 2000-01-01
1 1999-01-01 2000-01-01
1 2018-01-01 2018-12-12
1 2018-01-01 2019-01-01
10 2016-01-01 2018-01-01
11 2010-01-01 2015-01-01
2 1998-01-01 2000-01-01
2 2018-01-01 2018-12-12
3 1997-01-01 2000-01-01
4 2018-01-01 2020-01-01
7 2000-01-01 2017-01-01
7 2000-01-01 2018-01-01
7 2017-01-01 2018-01-01
8 2000-01-01 2018-01-01
9 2000-01-01 2015-01-01
# Check triggers
update t1 for portion of apptime from '2000-01-01' to '2018-01-01'
set id=id + 6;
select * from t1;
id s e
1 1999-01-01 2000-01-01
1 1999-01-01 2000-01-01
1 2018-01-01 2018-12-12
1 2018-01-01 2019-01-01
10 2016-01-01 2018-01-01
11 2010-01-01 2015-01-01
2 1998-01-01 2000-01-01
2 2018-01-01 2018-12-12
3 1997-01-01 2000-01-01
4 2018-01-01 2020-01-01
7 2000-01-01 2017-01-01
7 2000-01-01 2018-01-01
7 2017-01-01 2018-01-01
8 2000-01-01 2018-01-01
9 2000-01-01 2015-01-01
select * from log_tbl order by id;
id log
1 >UPD: 1, 1999-01-01, 2018-12-12 -> 7, 2000-01-01, 2018-01-01
2 >INS: 1, 1999-01-01, 2000-01-01
3 <INS: 1, 1999-01-01, 2000-01-01
4 >INS: 1, 2018-01-01, 2018-12-12
5 <INS: 1, 2018-01-01, 2018-12-12
6 <UPD: 1, 1999-01-01, 2018-12-12 -> 7, 2000-01-01, 2018-01-01
7 >UPD: 1, 1999-01-01, 2017-01-01 -> 7, 2000-01-01, 2017-01-01
8 >INS: 1, 1999-01-01, 2000-01-01
9 <INS: 1, 1999-01-01, 2000-01-01
10 <UPD: 1, 1999-01-01, 2017-01-01 -> 7, 2000-01-01, 2017-01-01
11 >UPD: 1, 2017-01-01, 2019-01-01 -> 7, 2017-01-01, 2018-01-01
12 >INS: 1, 2018-01-01, 2019-01-01
13 <INS: 1, 2018-01-01, 2019-01-01
14 <UPD: 1, 2017-01-01, 2019-01-01 -> 7, 2017-01-01, 2018-01-01
15 >UPD: 2, 1998-01-01, 2018-12-12 -> 8, 2000-01-01, 2018-01-01
16 >INS: 2, 1998-01-01, 2000-01-01
17 <INS: 2, 1998-01-01, 2000-01-01
18 >INS: 2, 2018-01-01, 2018-12-12
19 <INS: 2, 2018-01-01, 2018-12-12
20 <UPD: 2, 1998-01-01, 2018-12-12 -> 8, 2000-01-01, 2018-01-01
21 >UPD: 3, 1997-01-01, 2015-01-01 -> 9, 2000-01-01, 2015-01-01
22 >INS: 3, 1997-01-01, 2000-01-01
23 <INS: 3, 1997-01-01, 2000-01-01
24 <UPD: 3, 1997-01-01, 2015-01-01 -> 9, 2000-01-01, 2015-01-01
25 >UPD: 4, 2016-01-01, 2020-01-01 -> 10, 2016-01-01, 2018-01-01
26 >INS: 4, 2018-01-01, 2020-01-01
27 <INS: 4, 2018-01-01, 2020-01-01
28 <UPD: 4, 2016-01-01, 2020-01-01 -> 10, 2016-01-01, 2018-01-01
29 >UPD: 5, 2010-01-01, 2015-01-01 -> 11, 2010-01-01, 2015-01-01
30 <UPD: 5, 2010-01-01, 2015-01-01 -> 11, 2010-01-01, 2015-01-01
# INSERT trigger only also works
drop trigger tr1upd_t2;
drop trigger tr2upd_t2;
update t2 for portion of apptime from '2000-01-01' to '2018-01-01'
set id=id + 6;
select * from t2;
id s e
1 1999-01-01 2000-01-01
1 1999-01-01 2000-01-01
1 2018-01-01 2018-12-12
1 2018-01-01 2019-01-01
10 2016-01-01 2018-01-01
11 2010-01-01 2015-01-01
2 1998-01-01 2000-01-01
2 2018-01-01 2018-12-12
3 1997-01-01 2000-01-01
4 2018-01-01 2020-01-01
7 2000-01-01 2017-01-01
7 2000-01-01 2018-01-01
7 2017-01-01 2018-01-01
8 2000-01-01 2018-01-01
9 2000-01-01 2015-01-01
select * from log_tbl order by id;
id log
1 >INS: 1, 1999-01-01, 2000-01-01
2 <INS: 1, 1999-01-01, 2000-01-01
3 >INS: 1, 2018-01-01, 2018-12-12
4 <INS: 1, 2018-01-01, 2018-12-12
5 >INS: 1, 1999-01-01, 2000-01-01
6 <INS: 1, 1999-01-01, 2000-01-01
7 >INS: 1, 2018-01-01, 2019-01-01
8 <INS: 1, 2018-01-01, 2019-01-01
9 >INS: 2, 1998-01-01, 2000-01-01
10 <INS: 2, 1998-01-01, 2000-01-01
11 >INS: 2, 2018-01-01, 2018-12-12
12 <INS: 2, 2018-01-01, 2018-12-12
13 >INS: 3, 1997-01-01, 2000-01-01
14 <INS: 3, 1997-01-01, 2000-01-01
15 >INS: 4, 2018-01-01, 2020-01-01
16 <INS: 4, 2018-01-01, 2020-01-01
select * from t for portion of apptime from 0 to 1 for system_time all;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'portion of apptime from 0 to 1 for system_time all' at line 1
update t for portion of apptime from 0 to 1 for system_time all set id=1;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'system_time all set id=1' at line 1
# Modifying period start/end fields is forbidden.
# SQL16: 14.14 <update statement: searched>, Syntax Rules, 7)a)ii)
# Neither BSTARTCOL nor BENDCOL shall be an explicit <object column>
# contained in the <set clause list>.
update t for portion of apptime from '2000-01-01' to '2018-01-01'
set id= id + 6, s=subdate(s, 5), e=adddate(e, 5);
ERROR HY000: Column `s` used in period `apptime` specified in update SET list
# Precision timestamps
create or replace table t (id int, s timestamp(5), e timestamp(5),
period for apptime(s,e));
insert into t values(1, '1999-01-01', '2018-12-12');
insert into t values(1, '1999-01-01', '2017-01-01');
update t for portion of apptime from '2000-01-01 00:00:00.00015'
to '2018-01-01 12:34:56.31415'
set id= id + 5;
select * from t;
id s e
1 1999-01-01 00:00:00.00000 2000-01-01 00:00:00.00015
1 1999-01-01 00:00:00.00000 2000-01-01 00:00:00.00015
1 2018-01-01 12:34:56.31415 2018-12-12 00:00:00.00000
6 2000-01-01 00:00:00.00015 2017-01-01 00:00:00.00000
6 2000-01-01 00:00:00.00015 2018-01-01 12:34:56.31415
# Strings
create or replace table t (id int, str text, s date, e date,
period for apptime(s,e));
insert into t values(1, 'data', '1999-01-01', '2018-12-12');
insert into t values(1, 'other data', '1999-01-01', '2018-12-12');
update t for portion of apptime from '2000-01-01' to '2018-01-01'
set id= id + 5;
select * from t;
id str s e
1 data 1999-01-01 2000-01-01
1 data 2018-01-01 2018-12-12
1 other data 1999-01-01 2000-01-01
1 other data 2018-01-01 2018-12-12
6 data 2000-01-01 2018-01-01
6 other data 2000-01-01 2018-01-01
# multi-table UPDATE is impossible
create or replace table t1(x int);
update t for portion of apptime from '2000-01-01' to '2018-01-01', t1
set t.id= t.id + 5;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ' t1
set t.id= t.id + 5' at line 1
update t1 set x= (select id from t for portion of apptime from '2000-01-01' to '2018-01-01');
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'portion of apptime from '2000-01-01' to '2018-01-01')' at line 1
# SQL16: 14.14 <update statement: searched>, Syntax Rules, 7)a) iii-iv)
# Let FROMVAL be <point in time 1>. FROMVAL shall not generally contain a
# reference to a column of T or a <routine invocation>
# whose subject routine is an SQL-invoked routine that
# is possibly non-deterministic or that possibly modifies SQL-data.
# ...Same for <point in time 2> (TOVAL)
update t for portion of apptime from 5*(5+s) to 1 set t.id= t.id + 5;
ERROR HY000: Expression in FOR PORTION OF must be constant
update t for portion of apptime from 1 to e set t.id= t.id + 5;
ERROR HY000: Expression in FOR PORTION OF must be constant
set @s= '2000-01-01';
set @e= '2018-01-01';
create or replace function f() returns date return @e;
create or replace function g() returns date not deterministic return @e;
create or replace function h() returns date deterministic return @e;
update t for portion of apptime from @s to f() set t.id= t.id + 5;
ERROR HY000: Expression in FOR PORTION OF must be constant
update t for portion of apptime from @s to g() set t.id= t.id + 5;
ERROR HY000: Expression in FOR PORTION OF must be constant
# success
update t for portion of apptime from @s to h() set t.id= t.id + 5;
# select value is cached
update t for portion of apptime from (select s from t2 limit 1) to h() set t.id= t.id + 5;
# auto_inrement field is updated
create or replace table t (id int primary key auto_increment, x int,
s date, e date, period for apptime(s, e));
insert into t values (default, 1, '1999-01-01', '2018-12-12');
update t for portion of apptime from '2000-01-01' to '2018-01-01' set x= x + 5;
select * from t;
id x s e
1 6 2000-01-01 2018-01-01
2 1 1999-01-01 2000-01-01
3 1 2018-01-01 2018-12-12
truncate t;
insert into t values (default, 1, '1999-01-01', '2018-12-12');
update t for portion of apptime from '2000-01-01' to '2018-01-01' set x= 1;
select * from t;
id x s e
1 1 2000-01-01 2018-01-01
2 1 1999-01-01 2000-01-01
3 1 2018-01-01 2018-12-12
# generated columns are updated
create or replace table t (x int, s date, e date,
xs date as (s) stored, xe date as (e) stored,
period for apptime(s, e));
insert into t values(1, '1999-01-01', '2018-12-12', default, default);
select * from t;
x s e xs xe
1 1999-01-01 2018-12-12 1999-01-01 2018-12-12
update t for portion of apptime from '2000-01-01' to '2018-01-01' set x= x + 5;
select *, xs=s and xe=e from t;
x s e xs xe xs=s and xe=e
1 1999-01-01 2000-01-01 1999-01-01 2000-01-01 1
1 2018-01-01 2018-12-12 2018-01-01 2018-12-12 1
6 2000-01-01 2018-01-01 2000-01-01 2018-01-01 1
# system_time columns are updated
create or replace table t (x int, s date, e date,
row_start SYS_TYPE as row start invisible,
row_end SYS_TYPE as row end invisible,
period for apptime(s, e),
period for system_time(row_start, row_end)) with system versioning;
insert into t values(1, '1999-01-01', '2018-12-12'),
(2, '1999-01-01', '1999-12-12');
select row_start into @ins_time from t limit 1;
select * from t;
x s e
1 1999-01-01 2018-12-12
2 1999-01-01 1999-12-12
update t for portion of apptime from '2000-01-01' to '2018-01-01' set x= x + 5;
select *, if(row_start = @ins_time, "OLD", "NEW"), check_row(row_start, row_end)
from t for system_time all
order by x, s, e, row_start;
x s e if(row_start = @ins_time, "OLD", "NEW") check_row(row_start, row_end)
1 1999-01-01 2000-01-01 NEW CURRENT ROW
1 1999-01-01 2018-12-12 OLD HISTORICAL ROW
1 2018-01-01 2018-12-12 NEW CURRENT ROW
2 1999-01-01 1999-12-12 OLD CURRENT ROW
6 2000-01-01 2018-01-01 NEW CURRENT ROW
create or replace database test;
source suite/versioning/engines.inc;
source suite/versioning/common.inc;
create or replace table t (id int, s date, e date, period for apptime(s,e));
insert into t values(1, '1999-01-01', '2018-12-12');
insert into t values(1, '1999-01-01', '2017-01-01');
insert into t values(1, '2017-01-01', '2019-01-01');
insert into t values(2, '1998-01-01', '2018-12-12');
insert into t values(3, '1997-01-01', '2015-01-01');
insert into t values(4, '2016-01-01', '2020-01-01');
insert into t values(5, '2010-01-01', '2015-01-01');
create or replace table t1 (id int, s date, e date, period for apptime(s,e));
insert t1 select * from t;
create or replace table t2 (id int, s date, e date, period for apptime(s,e));
insert t2 select * from t;
update t for portion of apptime from '2000-01-01' to '2018-01-01'
set id=id + 6;
--sorted_result
select * from t;
--echo # Check triggers
--let $trig_cols=id, s, e
--let $trig_table=t1
--source suite/period/create_triggers.inc
update t1 for portion of apptime from '2000-01-01' to '2018-01-01'
set id=id + 6;
--sorted_result
select * from t1;
select * from log_tbl order by id;
--echo # INSERT trigger only also works
--let $trig_cols=id, s, e
--let $trig_table=t2
--source suite/period/create_triggers.inc
drop trigger tr1upd_t2;
drop trigger tr2upd_t2;
update t2 for portion of apptime from '2000-01-01' to '2018-01-01'
set id=id + 6;
--sorted_result
select * from t2;
select * from log_tbl order by id;
--error ER_PARSE_ERROR
select * from t for portion of apptime from 0 to 1 for system_time all;
--error ER_PARSE_ERROR
update t for portion of apptime from 0 to 1 for system_time all set id=1;
--echo # Modifying period start/end fields is forbidden.
--echo # SQL16: 14.14 <update statement: searched>, Syntax Rules, 7)a)ii)
--echo # Neither BSTARTCOL nor BENDCOL shall be an explicit <object column>
--echo # contained in the <set clause list>.
--error ER_PERIOD_COLUMNS_UPDATED
update t for portion of apptime from '2000-01-01' to '2018-01-01'
set id= id + 6, s=subdate(s, 5), e=adddate(e, 5);
--echo # Precision timestamps
create or replace table t (id int, s timestamp(5), e timestamp(5),
period for apptime(s,e));
insert into t values(1, '1999-01-01', '2018-12-12');
insert into t values(1, '1999-01-01', '2017-01-01');
update t for portion of apptime from '2000-01-01 00:00:00.00015'
to '2018-01-01 12:34:56.31415'
set id= id + 5;
--sorted_result
select * from t;
-- echo # Strings
create or replace table t (id int, str text, s date, e date,
period for apptime(s,e));
insert into t values(1, 'data', '1999-01-01', '2018-12-12');
insert into t values(1, 'other data', '1999-01-01', '2018-12-12');
update t for portion of apptime from '2000-01-01' to '2018-01-01'
set id= id + 5;
--sorted_result
select * from t;
--echo # multi-table UPDATE is impossible
create or replace table t1(x int);
--error ER_PARSE_ERROR
update t for portion of apptime from '2000-01-01' to '2018-01-01', t1
set t.id= t.id + 5;
--error ER_PARSE_ERROR
update t1 set x= (select id from t for portion of apptime from '2000-01-01' to '2018-01-01');
--echo # SQL16: 14.14 <update statement: searched>, Syntax Rules, 7)a) iii-iv)
--echo # Let FROMVAL be <point in time 1>. FROMVAL shall not generally contain a
--echo # reference to a column of T or a <routine invocation>
--echo # whose subject routine is an SQL-invoked routine that
--echo # is possibly non-deterministic or that possibly modifies SQL-data.
--echo # ...Same for <point in time 2> (TOVAL)
--error ER_NOT_CONSTANT_EXPRESSION
update t for portion of apptime from 5*(5+s) to 1 set t.id= t.id + 5;
--error ER_NOT_CONSTANT_EXPRESSION
update t for portion of apptime from 1 to e set t.id= t.id + 5;
set @s= '2000-01-01';
set @e= '2018-01-01';
create or replace function f() returns date return @e;
create or replace function g() returns date not deterministic return @e;
create or replace function h() returns date deterministic return @e;
--error ER_NOT_CONSTANT_EXPRESSION
update t for portion of apptime from @s to f() set t.id= t.id + 5;
--error ER_NOT_CONSTANT_EXPRESSION
update t for portion of apptime from @s to g() set t.id= t.id + 5;
--echo # success
update t for portion of apptime from @s to h() set t.id= t.id + 5;
--echo # select value is cached
update t for portion of apptime from (select s from t2 limit 1) to h() set t.id= t.id + 5;
--echo # auto_inrement field is updated
create or replace table t (id int primary key auto_increment, x int,
s date, e date, period for apptime(s, e));
insert into t values (default, 1, '1999-01-01', '2018-12-12');
update t for portion of apptime from '2000-01-01' to '2018-01-01' set x= x + 5;
--sorted_result
select * from t;
truncate t;
insert into t values (default, 1, '1999-01-01', '2018-12-12');
update t for portion of apptime from '2000-01-01' to '2018-01-01' set x= 1;
--sorted_result
select * from t;
--echo # generated columns are updated
create or replace table t (x int, s date, e date,
xs date as (s) stored, xe date as (e) stored,
period for apptime(s, e));
insert into t values(1, '1999-01-01', '2018-12-12', default, default);
--sorted_result
select * from t;
update t for portion of apptime from '2000-01-01' to '2018-01-01' set x= x + 5;
--sorted_result
select *, xs=s and xe=e from t;
--echo # system_time columns are updated
--replace_result $sys_datatype_expl SYS_TYPE
eval create or replace table t (x int, s date, e date,
row_start $sys_datatype_expl as row start invisible,
row_end $sys_datatype_expl as row end invisible,
period for apptime(s, e),
period for system_time(row_start, row_end)) with system versioning;
insert into t values(1, '1999-01-01', '2018-12-12'),
(2, '1999-01-01', '1999-12-12');
select row_start into @ins_time from t limit 1;
--sorted_result
select * from t;
update t for portion of apptime from '2000-01-01' to '2018-01-01' set x= x + 5;
select *, if(row_start = @ins_time, "OLD", "NEW"), check_row(row_start, row_end)
from t for system_time all
order by x, s, e, row_start;
create or replace database test;
...@@ -5838,10 +5838,10 @@ ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR ...@@ -5838,10 +5838,10 @@ ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
eng "Constant, random or timezone-dependent expressions in (sub)partitioning function are not allowed" eng "Constant, random or timezone-dependent expressions in (sub)partitioning function are not allowed"
ger "Konstante oder Random-Ausdrücke in (Unter-)Partitionsfunktionen sind nicht erlaubt" ger "Konstante oder Random-Ausdrücke in (Unter-)Partitionsfunktionen sind nicht erlaubt"
swe "Konstanta uttryck eller slumpmässiga uttryck är inte tillåtna (sub)partitioneringsfunktioner" swe "Konstanta uttryck eller slumpmässiga uttryck är inte tillåtna (sub)partitioneringsfunktioner"
ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR ER_NOT_CONSTANT_EXPRESSION
eng "Expression in RANGE/LIST VALUES must be constant" eng "Expression in %s must be constant"
ger "Ausdrücke in RANGE/LIST VALUES müssen konstant sein" ger "Ausdrücke in %s müssen konstant sein"
swe "Uttryck i RANGE/LIST VALUES måste vara ett konstant uttryck" swe "Uttryck i %s måste vara ett konstant uttryck"
ER_FIELD_NOT_FOUND_PART_ERROR ER_FIELD_NOT_FOUND_PART_ERROR
eng "Field in list of fields for partition function not found in table" eng "Field in list of fields for partition function not found in table"
ger "Felder in der Feldliste der Partitionierungsfunktion wurden in der Tabelle nicht gefunden" ger "Felder in der Feldliste der Partitionierungsfunktion wurden in der Tabelle nicht gefunden"
...@@ -7946,3 +7946,5 @@ ER_PERIOD_FIELD_WRONG_ATTRIBUTES ...@@ -7946,3 +7946,5 @@ ER_PERIOD_FIELD_WRONG_ATTRIBUTES
eng "Period field %`s cannot be %s" eng "Period field %`s cannot be %s"
ER_PERIOD_NOT_FOUND ER_PERIOD_NOT_FOUND
eng "Period %`s is not found in table" eng "Period %`s is not found in table"
ER_PERIOD_COLUMNS_UPDATED
eng "Column %`s used in period %`s specified in update SET list"
...@@ -842,9 +842,11 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ...@@ -842,9 +842,11 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
{ {
error= table->delete_row(); error= table->delete_row();
ha_rows rows_inserted;
if (likely(!error) && table_list->has_period() if (likely(!error) && table_list->has_period()
&& !portion_of_time_through_update) && !portion_of_time_through_update)
error= table->insert_portion_of_time(thd, table_list->period_conditions); error= table->insert_portion_of_time(thd, table_list->period_conditions,
&rows_inserted);
} }
if (likely(!error)) if (likely(!error))
......
...@@ -132,7 +132,8 @@ bool compare_record(const TABLE *table) ...@@ -132,7 +132,8 @@ bool compare_record(const TABLE *table)
FALSE Items are OK FALSE Items are OK
*/ */
static bool check_fields(THD *thd, List<Item> &items, bool update_view) static bool check_fields(THD *thd, TABLE_LIST *table, List<Item> &items,
bool update_view)
{ {
Item *item; Item *item;
if (update_view) if (update_view)
...@@ -177,6 +178,22 @@ static bool check_fields(THD *thd, List<Item> &items, bool update_view) ...@@ -177,6 +178,22 @@ static bool check_fields(THD *thd, List<Item> &items, bool update_view)
f->set_has_explicit_value(); f->set_has_explicit_value();
} }
} }
if (table->has_period())
{
DBUG_ASSERT(thd->lex->sql_command == SQLCOM_UPDATE);
for (List_iterator_fast<Item> it(items); (item=it++);)
{
Field *f= item->field_for_view_update()->field;
vers_select_conds_t &period= table->period_conditions;
if (period.field_start->field == f || period.field_end->field == f)
{
my_error(ER_PERIOD_COLUMNS_UPDATED, MYF(0),
item->name.str, period.name.str);
return true;
}
}
}
return FALSE; return FALSE;
} }
...@@ -267,6 +284,31 @@ static void prepare_record_for_error_message(int error, TABLE *table) ...@@ -267,6 +284,31 @@ static void prepare_record_for_error_message(int error, TABLE *table)
} }
static
int cut_fields_for_portion_of_time(THD *thd, TABLE *table,
const vers_select_conds_t &period_conds)
{
bool lcond= period_conds.field_start->val_datetime_packed(thd)
< period_conds.start.item->val_datetime_packed(thd);
bool rcond= period_conds.field_end->val_datetime_packed(thd)
> period_conds.end.item->val_datetime_packed(thd);
Field *start_field= table->field[table->s->period.start_fieldno];
Field *end_field= table->field[table->s->period.end_fieldno];
DBUG_ASSERT(!start_field->has_explicit_value()
&& !end_field->has_explicit_value());
int res= 0;
if (lcond)
res= period_conds.start.item->save_in_field(start_field, true);
if (likely(!res) && rcond)
res= period_conds.end.item->save_in_field(end_field, true);
return res;
}
/* /*
Process usual UPDATE Process usual UPDATE
...@@ -330,7 +372,7 @@ int mysql_update(THD *thd, ...@@ -330,7 +372,7 @@ int mysql_update(THD *thd,
query_plan.using_filesort= FALSE; query_plan.using_filesort= FALSE;
// For System Versioning (may need to insert new fields to a table). // For System Versioning (may need to insert new fields to a table).
ha_rows updated_sys_ver= 0; ha_rows rows_inserted= 0;
DBUG_ENTER("mysql_update"); DBUG_ENTER("mysql_update");
...@@ -398,7 +440,7 @@ int mysql_update(THD *thd, ...@@ -398,7 +440,7 @@ int mysql_update(THD *thd,
if (setup_fields_with_no_wrap(thd, Ref_ptr_array(), if (setup_fields_with_no_wrap(thd, Ref_ptr_array(),
fields, MARK_COLUMNS_WRITE, 0, 0)) fields, MARK_COLUMNS_WRITE, 0, 0))
DBUG_RETURN(1); /* purecov: inspected */ DBUG_RETURN(1); /* purecov: inspected */
if (check_fields(thd, fields, table_list->view)) if (check_fields(thd, table_list, fields, table_list->view))
{ {
DBUG_RETURN(1); DBUG_RETURN(1);
} }
...@@ -509,7 +551,10 @@ int mysql_update(THD *thd, ...@@ -509,7 +551,10 @@ int mysql_update(THD *thd,
if (unlikely(init_ftfuncs(thd, select_lex, 1))) if (unlikely(init_ftfuncs(thd, select_lex, 1)))
goto err; goto err;
table->mark_columns_needed_for_update(); if (table_list->has_period())
table->use_all_columns();
else
table->mark_columns_needed_for_update();
table->update_const_key_parts(conds); table->update_const_key_parts(conds);
order= simple_remove_const(order, conds); order= simple_remove_const(order, conds);
...@@ -590,6 +635,14 @@ int mysql_update(THD *thd, ...@@ -590,6 +635,14 @@ int mysql_update(THD *thd,
TRG_ACTION_BEFORE) || TRG_ACTION_BEFORE) ||
table->triggers->has_triggers(TRG_EVENT_UPDATE, table->triggers->has_triggers(TRG_EVENT_UPDATE,
TRG_ACTION_AFTER))); TRG_ACTION_AFTER)));
if (table_list->has_period())
has_triggers= table->triggers &&
(table->triggers->has_triggers(TRG_EVENT_INSERT,
TRG_ACTION_BEFORE)
|| table->triggers->has_triggers(TRG_EVENT_INSERT,
TRG_ACTION_AFTER)
|| has_triggers);
DBUG_PRINT("info", ("has_triggers: %s", has_triggers ? "TRUE" : "FALSE")); DBUG_PRINT("info", ("has_triggers: %s", has_triggers ? "TRUE" : "FALSE"));
binlog_is_row= thd->is_current_stmt_binlog_format_row(); binlog_is_row= thd->is_current_stmt_binlog_format_row();
DBUG_PRINT("info", ("binlog_is_row: %s", binlog_is_row ? "TRUE" : "FALSE")); DBUG_PRINT("info", ("binlog_is_row: %s", binlog_is_row ? "TRUE" : "FALSE"));
...@@ -880,14 +933,25 @@ int mysql_update(THD *thd, ...@@ -880,14 +933,25 @@ int mysql_update(THD *thd,
explain->tracker.on_record_after_where(); explain->tracker.on_record_after_where();
store_record(table,record[1]); store_record(table,record[1]);
if (table_list->has_period())
cut_fields_for_portion_of_time(thd, table,
table_list->period_conditions);
if (fill_record_n_invoke_before_triggers(thd, table, fields, values, 0, if (fill_record_n_invoke_before_triggers(thd, table, fields, values, 0,
TRG_EVENT_UPDATE)) TRG_EVENT_UPDATE))
break; /* purecov: inspected */ break; /* purecov: inspected */
found++; found++;
if (!can_compare_record || compare_record(table)) bool record_was_same= false;
bool need_update= !can_compare_record || compare_record(table);
if (need_update)
{ {
if (table->versioned(VERS_TIMESTAMP) &&
thd->lex->sql_command == SQLCOM_DELETE)
table->vers_update_end();
if (table->default_field && table->update_default_fields(1, ignore)) if (table->default_field && table->update_default_fields(1, ignore))
{ {
error= 1; error= 1;
...@@ -946,7 +1010,9 @@ int mysql_update(THD *thd, ...@@ -946,7 +1010,9 @@ int mysql_update(THD *thd,
error= table->file->ha_update_row(table->record[1], error= table->file->ha_update_row(table->record[1],
table->record[0]); table->record[0]);
} }
if (unlikely(error == HA_ERR_RECORD_IS_THE_SAME))
record_was_same= error == HA_ERR_RECORD_IS_THE_SAME;
if (unlikely(record_was_same))
{ {
error= 0; error= 0;
} }
...@@ -961,12 +1027,22 @@ int mysql_update(THD *thd, ...@@ -961,12 +1027,22 @@ int mysql_update(THD *thd,
restore_record(table, record[2]); restore_record(table, record[2]);
} }
if (likely(!error)) if (likely(!error))
updated_sys_ver++; rows_inserted++;
} }
if (likely(!error)) if (likely(!error))
updated++; updated++;
} }
if (likely(!error) && !record_was_same && table_list->has_period())
{
store_record(table, record[2]);
restore_record(table, record[1]);
error= table->insert_portion_of_time(thd,
table_list->period_conditions,
&rows_inserted);
restore_record(table, record[2]);
}
if (unlikely(error) && if (unlikely(error) &&
(!ignore || table->file->is_fatal_error(error, HA_CHECK_ALL))) (!ignore || table->file->is_fatal_error(error, HA_CHECK_ALL)))
{ {
...@@ -1107,6 +1183,8 @@ int mysql_update(THD *thd, ...@@ -1107,6 +1183,8 @@ int mysql_update(THD *thd,
delete select; delete select;
select= NULL; select= NULL;
THD_STAGE_INFO(thd, stage_end); THD_STAGE_INFO(thd, stage_end);
if (table_list->has_period())
table->file->ha_release_auto_increment();
(void) table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); (void) table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
/* /*
...@@ -1169,14 +1247,14 @@ int mysql_update(THD *thd, ...@@ -1169,14 +1247,14 @@ int mysql_update(THD *thd,
if (likely(error < 0) && likely(!thd->lex->analyze_stmt)) if (likely(error < 0) && likely(!thd->lex->analyze_stmt))
{ {
char buff[MYSQL_ERRMSG_SIZE]; char buff[MYSQL_ERRMSG_SIZE];
if (!table->versioned(VERS_TIMESTAMP)) if (!table->versioned(VERS_TIMESTAMP) && !table_list->has_period())
my_snprintf(buff, sizeof(buff), ER_THD(thd, ER_UPDATE_INFO), (ulong) found, my_snprintf(buff, sizeof(buff), ER_THD(thd, ER_UPDATE_INFO), (ulong) found,
(ulong) updated, (ulong) updated,
(ulong) thd->get_stmt_da()->current_statement_warn_count()); (ulong) thd->get_stmt_da()->current_statement_warn_count());
else else
my_snprintf(buff, sizeof(buff), my_snprintf(buff, sizeof(buff),
ER_THD(thd, ER_UPDATE_INFO_WITH_SYSTEM_VERSIONING), ER_THD(thd, ER_UPDATE_INFO_WITH_SYSTEM_VERSIONING),
(ulong) found, (ulong) updated, (ulong) updated_sys_ver, (ulong) found, (ulong) updated, (ulong) rows_inserted,
(ulong) thd->get_stmt_da()->current_statement_warn_count()); (ulong) thd->get_stmt_da()->current_statement_warn_count());
my_ok(thd, (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated, my_ok(thd, (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated,
id, buff); id, buff);
...@@ -1257,6 +1335,19 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, ...@@ -1257,6 +1335,19 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
thd->lex->allow_sum_func.clear_all(); thd->lex->allow_sum_func.clear_all();
if (table_list->has_period())
{
if (table_list->is_view_or_derived())
{
my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str);
DBUG_RETURN(true);
}
*conds= select_lex->period_setup_conds(thd, table_list, *conds);
if (!*conds)
DBUG_RETURN(true);
}
/* /*
We do not call DT_MERGE_FOR_INSERT because it has no sense for simple We do not call DT_MERGE_FOR_INSERT because it has no sense for simple
(not multi-) update (not multi-) update
...@@ -1276,6 +1367,16 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, ...@@ -1276,6 +1367,16 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
setup_ftfuncs(select_lex)) setup_ftfuncs(select_lex))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
if (table_list->has_period())
{
if (!table_list->period_conditions.start.item->const_item()
|| !table_list->period_conditions.end.item->const_item())
{
my_error(ER_NOT_CONSTANT_EXPRESSION, MYF(0), "FOR PORTION OF");
DBUG_RETURN(true);
}
}
select_lex->fix_prepare_information(thd, conds, &fake_conds); select_lex->fix_prepare_information(thd, conds, &fake_conds);
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
} }
...@@ -1589,7 +1690,7 @@ int mysql_multi_update_prepare(THD *thd) ...@@ -1589,7 +1690,7 @@ int mysql_multi_update_prepare(THD *thd)
} }
} }
if (check_fields(thd, *fields, update_view)) if (check_fields(thd, table_list, *fields, update_view))
{ {
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
......
...@@ -1929,6 +1929,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); ...@@ -1929,6 +1929,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
table_primary_ident table_primary_derived table_primary_ident table_primary_derived
derived_table_list table_reference_list_parens derived_table_list table_reference_list_parens
nested_table_reference_list join_table_parens nested_table_reference_list join_table_parens
update_table_list
%type <date_time_type> date_time_type; %type <date_time_type> date_time_type;
%type <interval> interval %type <interval> interval
...@@ -9444,12 +9445,9 @@ history_point: ...@@ -9444,12 +9445,9 @@ history_point:
$$= Vers_history_point($1, $2); $$= Vers_history_point($1, $2);
} }
; ;
opt_for_portion_of_time_clause:
/* empty */ for_portion_of_time_clause:
{ FOR_SYM PORTION_SYM OF_SYM remember_tok_start ident FROM
$$= false;
}
| FOR_SYM PORTION_SYM OF_SYM remember_tok_start ident FROM
bit_expr TO_SYM bit_expr bit_expr TO_SYM bit_expr
{ {
if (unlikely(0 == strcasecmp($5.str, "SYSTEM_TIME"))) if (unlikely(0 == strcasecmp($5.str, "SYSTEM_TIME")))
...@@ -9461,6 +9459,15 @@ opt_for_portion_of_time_clause: ...@@ -9461,6 +9459,15 @@ opt_for_portion_of_time_clause:
Vers_history_point(VERS_TIMESTAMP, $7), Vers_history_point(VERS_TIMESTAMP, $7),
Vers_history_point(VERS_TIMESTAMP, $9), Vers_history_point(VERS_TIMESTAMP, $9),
$5); $5);
}
opt_for_portion_of_time_clause:
/* empty */
{
$$= false;
}
| for_portion_of_time_clause
{
$$= true; $$= true;
} }
; ;
...@@ -13576,6 +13583,24 @@ opt_insert_update: ...@@ -13576,6 +13583,24 @@ opt_insert_update:
} }
; ;
update_table_list:
table_ident opt_use_partition for_portion_of_time_clause
opt_table_alias_clause opt_key_definition
{
SELECT_LEX *sel= Select;
sel->table_join_options= 0;
if (!($$= Select->add_table_to_list(thd, $1, $4,
Select->get_table_join_options(),
YYPS->m_lock_type,
YYPS->m_mdl_type,
Select->pop_index_hints(),
$2)))
MYSQL_YYABORT;
$$->period_conditions= Lex->period_conditions;
}
| join_table_list { $$= $1; }
;
/* Update rows in a table */ /* Update rows in a table */
update: update:
...@@ -13588,7 +13613,7 @@ update: ...@@ -13588,7 +13613,7 @@ update:
lex->sql_command= SQLCOM_UPDATE; lex->sql_command= SQLCOM_UPDATE;
lex->duplicates= DUP_ERROR; lex->duplicates= DUP_ERROR;
} }
opt_low_priority opt_ignore join_table_list opt_low_priority opt_ignore update_table_list
SET update_list SET update_list
{ {
LEX *lex= Lex; LEX *lex= Lex;
......
...@@ -3427,7 +3427,7 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, ...@@ -3427,7 +3427,7 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
if (prgflag & (READ_ALL + EXTRA_RECORD)) if (prgflag & (READ_ALL + EXTRA_RECORD))
{ {
records++; records++;
if (share->versioned) if (share->versioned || share->period.name)
records++; records++;
} }
...@@ -8137,7 +8137,8 @@ int TABLE::period_make_insert(Item *src, Field *dst) ...@@ -8137,7 +8137,8 @@ int TABLE::period_make_insert(Item *src, Field *dst)
} }
int TABLE::insert_portion_of_time(THD *thd, int TABLE::insert_portion_of_time(THD *thd,
const vers_select_conds_t &period_conds) const vers_select_conds_t &period_conds,
ha_rows *rows_inserted)
{ {
bool lcond= period_conds.field_start->val_datetime_packed(thd) bool lcond= period_conds.field_start->val_datetime_packed(thd)
< period_conds.start.item->val_datetime_packed(thd); < period_conds.start.item->val_datetime_packed(thd);
...@@ -8146,11 +8147,19 @@ int TABLE::insert_portion_of_time(THD *thd, ...@@ -8146,11 +8147,19 @@ int TABLE::insert_portion_of_time(THD *thd,
int res= 0; int res= 0;
if (lcond) if (lcond)
{
res= period_make_insert(period_conds.start.item, res= period_make_insert(period_conds.start.item,
field[s->period.end_fieldno]); field[s->period.end_fieldno]);
if (likely(!res))
++*rows_inserted;
}
if (likely(!res) && rcond) if (likely(!res) && rcond)
{
res= period_make_insert(period_conds.end.item, res= period_make_insert(period_conds.end.item,
field[s->period.start_fieldno]); field[s->period.start_fieldno]);
if (likely(!res))
++*rows_inserted;
}
return res; return res;
} }
......
...@@ -1578,7 +1578,8 @@ struct TABLE ...@@ -1578,7 +1578,8 @@ struct TABLE
int update_generated_fields(); int update_generated_fields();
int period_make_insert(Item *src, Field *dst); int period_make_insert(Item *src, Field *dst);
int insert_portion_of_time(THD *thd, const vers_select_conds_t &period_conds); int insert_portion_of_time(THD *thd, const vers_select_conds_t &period_conds,
ha_rows *rows_inserted);
int delete_row(); int delete_row();
void vers_update_fields(); void vers_update_fields();
void vers_update_end(); void vers_update_end();
......
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