mirror of
https://github.com/MariaDB/server.git
synced 2025-02-12 00:15:35 +01:00
dfdedd46e4
This patch extends the timestamp from 2038-01-19 03:14:07.999999 to 2106-02-07 06:28:15.999999 for 64 bit hardware and OS where 'long' is 64 bits. This is true for 64 bit Linux but not for Windows. This is done by treating the 32 bit stored int as unsigned instead of signed. This is safe as MariaDB has never accepted dates before the epoch (1970). The benefit of this approach that for normal timestamp the storage is compatible with earlier version. However for tables using system versioning we before stored a timestamp with the year 2038 as the 'max timestamp', which is used to detect current values. This patch stores the new 2106 year max value as the max timestamp. This means that old tables using system versioning needs to be updated with mariadb-upgrade when moving them to 11.4. That will be done in a separate commit.
316 lines
13 KiB
Text
316 lines
13 KiB
Text
SET @saved_stats_persistent = @@GLOBAL.innodb_stats_persistent;
|
|
SET GLOBAL innodb_stats_persistent = OFF;
|
|
set time_zone="+00:00";
|
|
set default_storage_engine=innodb;
|
|
create or replace table dept (
|
|
dept_id int(10) primary key,
|
|
name varchar(100)
|
|
) with system versioning;
|
|
create or replace table emp (
|
|
emp_id int(10) primary key,
|
|
dept_id int(10) not null,
|
|
name varchar(100) not null,
|
|
mgr int(10),
|
|
salary int(10) not null,
|
|
constraint `dept-emp-fk`
|
|
foreign key (dept_id) references dept (dept_id)
|
|
on delete cascade
|
|
on update restrict,
|
|
constraint `mgr-fk`
|
|
foreign key (mgr) references emp (emp_id)
|
|
on delete restrict
|
|
on update restrict
|
|
) with system versioning;
|
|
insert into dept (dept_id, name) values (10, "accounting");
|
|
insert into emp (emp_id, name, salary, dept_id, mgr) values
|
|
(1, "bill", 1000, 10, null),
|
|
(20, "john", 500, 10, 1),
|
|
(30, "jane", 750, 10,1 );
|
|
select row_start into @ts_1 from emp where name="jane";
|
|
update emp set mgr=30 where name ="john";
|
|
explain extended
|
|
with ancestors as (
|
|
select e.emp_id, e.name, e.mgr, e.salary from emp as e where name = 'bill'
|
|
union
|
|
select e.emp_id, e.name, e.mgr, e.salary from emp as e
|
|
) select * from ancestors for system_time as of @ts_1;
|
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
|
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 8 100.00
|
|
2 DERIVED e ALL NULL NULL NULL NULL 4 100.00 Using where
|
|
3 UNION e ALL NULL NULL NULL NULL 4 100.00 Using where
|
|
NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL NULL
|
|
Warnings:
|
|
Note 1003 with ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`e`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`e`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu')/* select#1 */ select `ancestors`.`emp_id` AS `emp_id`,`ancestors`.`name` AS `name`,`ancestors`.`mgr` AS `mgr`,`ancestors`.`salary` AS `salary` from `ancestors`
|
|
select row_start into @ts_2 from emp where name="john";
|
|
explain extended /* All report to 'Bill' */
|
|
with recursive
|
|
ancestors
|
|
as
|
|
(
|
|
select e.emp_id, e.name, e.mgr, e.salary
|
|
from emp for system_time as of timestamp @ts_1 as e
|
|
where name = 'bill'
|
|
union
|
|
select e.emp_id, e.name, e.mgr, e.salary
|
|
from emp for system_time as of timestamp @ts_1 as e,
|
|
ancestors as a
|
|
where e.mgr = a.emp_id
|
|
)
|
|
select * from ancestors;
|
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
|
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 4 100.00
|
|
2 DERIVED e ALL NULL NULL NULL NULL 4 100.00 Using where
|
|
3 RECURSIVE UNION e ALL mgr-fk NULL NULL NULL 4 100.00 Using where
|
|
3 RECURSIVE UNION <derived2> ref key0 key0 5 test.e.mgr 1 100.00
|
|
NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL NULL
|
|
Warnings:
|
|
Note 1003 with recursive ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`e`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` join `ancestors` `a` where `a`.`emp_id` = `test`.`e`.`mgr` and `test`.`e`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`e`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu')/* select#1 */ select `ancestors`.`emp_id` AS `emp_id`,`ancestors`.`name` AS `name`,`ancestors`.`mgr` AS `mgr`,`ancestors`.`salary` AS `salary` from `ancestors`
|
|
/* All report to 'Bill' */
|
|
with recursive
|
|
ancestors
|
|
as
|
|
(
|
|
select e.emp_id, e.name, e.mgr, e.salary
|
|
from emp for system_time as of timestamp @ts_1 as e
|
|
where name = 'bill'
|
|
union
|
|
select e.emp_id, e.name, e.mgr, e.salary
|
|
from emp for system_time as of timestamp @ts_1 as e,
|
|
ancestors as a
|
|
where e.mgr = a.emp_id
|
|
)
|
|
select * from ancestors;
|
|
emp_id name mgr salary
|
|
1 bill NULL 1000
|
|
20 john 1 500
|
|
30 jane 1 750
|
|
explain extended with recursive
|
|
ancestors
|
|
as
|
|
(
|
|
select e.emp_id, e.name, e.mgr, e.salary
|
|
from emp as e
|
|
where name = 'bill'
|
|
union
|
|
select e.emp_id, e.name, e.mgr, e.salary
|
|
from emp as e,
|
|
ancestors as a
|
|
where e.mgr = a.emp_id
|
|
)
|
|
select * from ancestors for system_time as of timestamp @ts_1;
|
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
|
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 4 100.00
|
|
2 DERIVED e ALL NULL NULL NULL NULL 4 100.00 Using where
|
|
3 RECURSIVE UNION e ALL mgr-fk NULL NULL NULL 4 100.00 Using where
|
|
3 RECURSIVE UNION <derived2> ref key0 key0 5 test.e.mgr 1 100.00
|
|
NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL NULL
|
|
Warnings:
|
|
Note 1003 with recursive ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`e`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` join `ancestors` `a` where `a`.`emp_id` = `test`.`e`.`mgr` and `test`.`e`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`e`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu')/* select#1 */ select `ancestors`.`emp_id` AS `emp_id`,`ancestors`.`name` AS `name`,`ancestors`.`mgr` AS `mgr`,`ancestors`.`salary` AS `salary` from `ancestors`
|
|
with recursive
|
|
ancestors
|
|
as
|
|
(
|
|
select e.emp_id, e.name, e.mgr, e.salary
|
|
from emp as e
|
|
where name = 'bill'
|
|
union
|
|
select e.emp_id, e.name, e.mgr, e.salary
|
|
from emp as e,
|
|
ancestors as a
|
|
where e.mgr = a.emp_id
|
|
)
|
|
select * from ancestors for system_time as of timestamp @ts_1;
|
|
emp_id name mgr salary
|
|
1 bill NULL 1000
|
|
20 john 1 500
|
|
30 jane 1 750
|
|
explain extended with recursive
|
|
ancestors
|
|
as
|
|
(
|
|
select e.emp_id, e.name, e.mgr, e.salary
|
|
from emp as e
|
|
where name = 'bill'
|
|
union
|
|
select e.emp_id, e.name, e.mgr, e.salary
|
|
from emp as e,
|
|
ancestors as a
|
|
where e.mgr = a.emp_id
|
|
)
|
|
select name from emp where emp_id in (select emp_id from ancestors for system_time as of timestamp @ts_1);
|
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
|
1 PRIMARY emp ALL PRIMARY NULL NULL NULL 4 100.00 Using where
|
|
1 PRIMARY <derived2> ref key0 key0 5 test.emp.emp_id 1 100.00 FirstMatch(emp)
|
|
2 DERIVED e ALL NULL NULL NULL NULL 4 100.00 Using where
|
|
3 RECURSIVE UNION e ALL mgr-fk NULL NULL NULL 4 100.00 Using where
|
|
3 RECURSIVE UNION <derived2> ref key0 key0 5 test.e.mgr 1 100.00
|
|
NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL NULL
|
|
Warnings:
|
|
Note 1003 with recursive ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`e`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` join `ancestors` `a` where `a`.`emp_id` = `test`.`e`.`mgr` and `test`.`e`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`e`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu')/* select#1 */ select `test`.`emp`.`name` AS `name` from `test`.`emp` semi join (`ancestors`) where `ancestors`.`emp_id` = `test`.`emp`.`emp_id` and `test`.`emp`.`row_end` = TIMESTAMP'2106-02-07 06:28:15.999999'
|
|
with recursive
|
|
ancestors
|
|
as
|
|
(
|
|
select e.emp_id, e.name, e.mgr, e.salary
|
|
from emp as e
|
|
where name = 'bill'
|
|
union
|
|
select e.emp_id, e.name, e.mgr, e.salary
|
|
from emp as e,
|
|
ancestors as a
|
|
where e.mgr = a.emp_id
|
|
)
|
|
select name from emp where emp_id in (select emp_id from ancestors for system_time as of timestamp @ts_1);
|
|
name
|
|
bill
|
|
john
|
|
jane
|
|
with recursive
|
|
ancestors
|
|
as
|
|
(
|
|
select e.emp_id, e.name, e.mgr, e.salary
|
|
from emp as e
|
|
where name = 'bill'
|
|
union
|
|
select e.emp_id, e.name, e.mgr, e.salary
|
|
from emp as e,
|
|
ancestors as a
|
|
where e.mgr = a.emp_id
|
|
)
|
|
select * from ancestors for system_time as of @ts_2,
|
|
ancestors for system_time as of @ts_2 a2;
|
|
emp_id name mgr salary emp_id name mgr salary
|
|
1 bill NULL 1000 1 bill NULL 1000
|
|
30 jane 1 750 1 bill NULL 1000
|
|
20 john 30 500 1 bill NULL 1000
|
|
1 bill NULL 1000 30 jane 1 750
|
|
30 jane 1 750 30 jane 1 750
|
|
20 john 30 500 30 jane 1 750
|
|
1 bill NULL 1000 20 john 30 500
|
|
30 jane 1 750 20 john 30 500
|
|
20 john 30 500 20 john 30 500
|
|
with recursive
|
|
ancestors
|
|
as
|
|
(
|
|
select e.emp_id, e.name, e.mgr, e.salary
|
|
from emp as e
|
|
where name = 'bill'
|
|
union
|
|
select e.emp_id, e.name, e.mgr, e.salary
|
|
from emp as e,
|
|
ancestors as a
|
|
where e.mgr = a.emp_id
|
|
)
|
|
select * from ancestors for system_time as of @ts_2,
|
|
ancestors for system_time as of now() a2;
|
|
ERROR HY000: Conflicting FOR SYSTEM_TIME clauses in WITH RECURSIVE
|
|
with recursive
|
|
ancestors
|
|
as
|
|
(
|
|
select e.emp_id, e.name, e.mgr, e.salary
|
|
from emp as e
|
|
where name = 'bill'
|
|
union
|
|
select e.emp_id, e.name, e.mgr, e.salary
|
|
from emp as e,
|
|
ancestors as a
|
|
where e.mgr = a.emp_id
|
|
)
|
|
select * from ancestors,
|
|
ancestors for system_time as of @ts_2 a2;
|
|
ERROR HY000: Conflicting FOR SYSTEM_TIME clauses in WITH RECURSIVE
|
|
with recursive
|
|
ancestors
|
|
as
|
|
(
|
|
select e.emp_id, e.name, e.mgr, e.salary
|
|
from emp as e
|
|
where name = 'bill'
|
|
union
|
|
select e.emp_id, e.name, e.mgr, e.salary
|
|
from emp as e,
|
|
ancestors as a
|
|
where e.mgr = a.emp_id
|
|
)
|
|
select * from ancestors for system_time as of @ts_2,
|
|
ancestors a2;
|
|
ERROR HY000: Conflicting FOR SYSTEM_TIME clauses in WITH RECURSIVE
|
|
with recursive
|
|
ancestors
|
|
as
|
|
(
|
|
select e.emp_id, e.name, e.mgr, e.salary
|
|
from emp as e
|
|
where name = 'bill'
|
|
union
|
|
select e.emp_id, e.name, e.mgr, e.salary
|
|
from emp as e,
|
|
ancestors as a
|
|
where e.mgr = a.emp_id
|
|
)
|
|
select * from ancestors for system_time as of @ts_2
|
|
where emp_id in (select * from ancestors);
|
|
ERROR HY000: Conflicting FOR SYSTEM_TIME clauses in WITH RECURSIVE
|
|
# SYSTEM_TIME to internal recursive instance is prohibited
|
|
with recursive cte as
|
|
(
|
|
select * from emp
|
|
union all
|
|
select * from cte for system_time as of @ts_1
|
|
)
|
|
select * from cte;
|
|
ERROR HY000: Table `cte` is not system-versioned
|
|
create or replace table emp ( emp_id int, name varchar(127), mgr int) with system versioning;
|
|
create or replace table addr ( emp_id int, address varchar(100)) with system versioning;
|
|
insert emp values (1, 'bill', 0), (2, 'bill', 1), (3, 'kate', 1);
|
|
insert addr values (1, 'Moscow'), (2, 'New York'), (3, 'London');
|
|
set @ts=now(6);
|
|
delete from emp;
|
|
delete from addr;
|
|
with recursive
|
|
ancestors
|
|
as
|
|
(
|
|
select e.emp_id, e.name, e.mgr
|
|
from emp for system_time as of timestamp @ts as e
|
|
where name = 'bill'
|
|
union
|
|
select ee.emp_id, ee.name, ee.mgr
|
|
from emp for system_time as of timestamp @ts as ee, ancestors as a
|
|
where ee.mgr = a.emp_id
|
|
)
|
|
select * from ancestors;
|
|
emp_id name mgr
|
|
1 bill 0
|
|
2 bill 1
|
|
3 kate 1
|
|
insert emp values (4, 'john', 1);
|
|
insert addr values (4, 'Paris');
|
|
with ancestors as (select * from emp natural join addr) select * from ancestors;
|
|
emp_id name mgr address
|
|
4 john 1 Paris
|
|
with ancestors as (select * from emp natural join addr) select * from ancestors for system_time all;
|
|
emp_id name mgr address
|
|
1 bill 0 Moscow
|
|
2 bill 1 New York
|
|
3 kate 1 London
|
|
4 john 1 Paris
|
|
with ancestors as (select * from (select * from emp natural join addr) for system_time all as t) select * from ancestors;
|
|
emp_id name mgr address
|
|
1 bill 0 Moscow
|
|
2 bill 1 New York
|
|
3 kate 1 London
|
|
4 john 1 Paris
|
|
select * from (select * from emp natural join addr) for system_time all as t;
|
|
emp_id name mgr address
|
|
1 bill 0 Moscow
|
|
2 bill 1 New York
|
|
3 kate 1 London
|
|
4 john 1 Paris
|
|
drop table emp;
|
|
drop table dept;
|
|
drop table addr;
|
|
SET GLOBAL innodb_stats_persistent = @saved_stats_persistent;
|