revision-id: 0d0cc6b0e903192600e8efdefa51129a485afec9 (mariadb-10.3.6-42-g0d0cc6b0e90)
parent(s): 459c701b0b472d6bbfd9d5271e244797a2498f8d
author: Oleksandr Byelkin
committer: Oleksandr Byelkin
timestamp: 2018-04-24 10:24:22 +0200
message:
fix by buildbot results
---
tests/mysql_client_test.c | 23 +++++++++++------------
1 file changed, 11 insertions(+), 12 deletions(-)
diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c
index 3188ea882bb..f24bb919906 100644
--- a/tests/mysql_client_test.c
+++ b/tests/mysql_client_test.c
@@ -20226,6 +20226,17 @@ static void test_proxy_header_ignore()
myquery(rc);
}
+static void test_proxy_header()
+{
+ test_proxy_header_tcp("192.0.2.1",3333);
+ test_proxy_header_tcp("2001:db8:85a3::8a2e:370:7334",2222);
+ test_proxy_header_tcp("::ffff:192.0.2.1",2222);
+ test_proxy_header_localhost();
+ test_proxy_header_ignore();
+}
+
+#endif
+
static void test_bulk_autoinc()
{
@@ -20279,18 +20290,6 @@ static void test_bulk_autoinc()
myquery(rc);
}
-
-static void test_proxy_header()
-{
- test_proxy_header_tcp("192.0.2.1",3333);
- test_proxy_header_tcp("2001:db8:85a3::8a2e:370:7334",2222);
- test_proxy_header_tcp("::ffff:192.0.2.1",2222);
- test_proxy_header_localhost();
- test_proxy_header_ignore();
-}
-
-#endif
-
static struct my_tests_st my_tests[]= {
{ "disable_query_logs", disable_query_logs },
{ "test_view_sp_list_fields", test_view_sp_list_fields },
1
0
[Commits] 65f79b36f98: MDEV-14820 System versioning is applied incorrectly to CTEs
by serg@mariadb.org 23 Apr '18
by serg@mariadb.org 23 Apr '18
23 Apr '18
revision-id: 65f79b36f9859333678938850d5ff78a59490dfc (10.4-12-g65f79b36f98)
parent(s): ceadd5485a56e272365e201e6c89429202abae3a
author: Sergei Golubchik
committer: Sergei Golubchik
timestamp: 2018-04-23 18:46:47 +0200
message:
MDEV-14820 System versioning is applied incorrectly to CTEs
Make sure that SELECT_LEX_UNIT::derived, behaves as documented
(points to the "TABLE_LIST representing this union in the
embedding select"). For recursive CTE this was not necessarily
the case, it could've pointed to the TABLE_LIST inside the CTE,
not in the embedding select.
To fix:
* don't update unit->derived in mysql_derived_prepare(), pass derived
as an argument to st_select_lex_unit::prepare()
* prefer to set unit->derived in TABLE_LIST::init_derived()
to the TABLE_LIST in the embedding select, not to the recursive
reference. Fail if there are many TABLE_LISTs in the embedding
select with conflicting FOR SYSTEM_TIME clauses.
cleanup:
* remove redundant THD* argument from st_select_lex_unit::prepare()
---
mysql-test/suite/versioning/disabled.def | 1 -
mysql-test/suite/versioning/r/cte.result | 225 ++++++++++++++++++++++++++++---
mysql-test/suite/versioning/t/cte.test | 152 +++++++++++++++++++--
sql/item_subselect.cc | 2 +-
sql/share/errmsg-utf8.txt | 4 +-
sql/sql_cte.cc | 2 +-
sql/sql_derived.cc | 4 +-
sql/sql_lex.h | 3 +-
sql/sql_prepare.cc | 4 +-
sql/sql_select.cc | 3 +-
sql/sql_union.cc | 58 ++++----
sql/sql_view.cc | 2 +-
sql/table.cc | 42 +++++-
sql/table.h | 2 +
14 files changed, 432 insertions(+), 72 deletions(-)
diff --git a/mysql-test/suite/versioning/disabled.def b/mysql-test/suite/versioning/disabled.def
index 11e45360f19..888298bbb09 100644
--- a/mysql-test/suite/versioning/disabled.def
+++ b/mysql-test/suite/versioning/disabled.def
@@ -9,4 +9,3 @@
# Do not use any TAB characters for whitespace.
#
##############################################################################
-cte: MDEV-14820
diff --git a/mysql-test/suite/versioning/r/cte.result b/mysql-test/suite/versioning/r/cte.result
index fda5e086be2..6ad09ede5a6 100644
--- a/mysql-test/suite/versioning/r/cte.result
+++ b/mysql-test/suite/versioning/r/cte.result
@@ -1,9 +1,8 @@
set default_storage_engine=innodb;
create or replace table dept (
-dept_id int(10) primary key,
+dept_id int(10) primary key,
name varchar(100)
-)
-with system versioning;
+) with system versioning;
create or replace table emp (
emp_id int(10) primary key,
dept_id int(10) not null,
@@ -18,16 +17,51 @@ constraint `mgr-fk`
foreign key (mgr) references emp (emp_id)
on delete restrict
on update restrict
-)
-with system versioning;
+) with system versioning;
insert into dept (dept_id, name) values (10, "accounting");
-insert into emp (emp_id, name, salary, dept_id, mgr) values
+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 max(sys_trx_start) into @ts_1 from emp;
+select row_start into @ts_1 from emp where name="jane";
update emp set mgr=30 where name ="john";
-select sys_trx_start into @ts_2 from emp 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 ALL `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1` 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 ALL `e` where `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1`)/* 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 4 test.e.mgr 2 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 ALL `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1` 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 ALL `e` join `ancestors` `a` where `a`.`emp_id` = `test`.`e`.`mgr` and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1`)/* 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
@@ -36,7 +70,7 @@ 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
+ 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
@@ -47,25 +81,186 @@ emp_id name mgr salary
1 bill NULL 1000
20 john 1 500
30 jane 1 750
-/* Expected 3 rows */
+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 4 test.e.mgr 2 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 ALL `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1` 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 ALL `e` join `ancestors` `a` where `a`.`emp_id` = `test`.`e`.`mgr` and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1`)/* 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 for system_time as of timestamp @ts_2 as e
+from emp as e
where name = 'bill'
- union
+ union
select e.emp_id, e.name, e.mgr, e.salary
-from emp for system_time as of timestamp @ts_2 as e,
+from emp as e,
ancestors as a
where e.mgr = a.emp_id
)
-select * from ancestors;
+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
-20 john 30 500
+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 <subquery4> ALL distinct_key NULL NULL NULL 4 100.00
+1 PRIMARY emp ALL PRIMARY NULL NULL NULL 4 75.00 Using where; Using join buffer (flat, BNL join)
+4 MATERIALIZED <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 4 test.e.mgr 2 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 ALL `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1` 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 ALL `e` join `ancestors` `a` where `a`.`emp_id` = `test`.`e`.`mgr` and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1`)/* select#1 */ select `test`.`emp`.`name` AS `name` from `test`.`emp` FOR SYSTEM_TIME ALL semi join (`ancestors`) where `test`.`emp`.`emp_id` = `ancestors`.`emp_id` and `test`.`emp`.`row_end` = TIMESTAMP'2038-01-19 04:14:07.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);
diff --git a/mysql-test/suite/versioning/t/cte.test b/mysql-test/suite/versioning/t/cte.test
index 9df0bb3dfba..68ca53dc045 100644
--- a/mysql-test/suite/versioning/t/cte.test
+++ b/mysql-test/suite/versioning/t/cte.test
@@ -1,10 +1,9 @@
-- source include/have_innodb.inc
set default_storage_engine=innodb;
create or replace table dept (
- dept_id int(10) primary key,
+ dept_id int(10) primary key,
name varchar(100)
-)
-with system versioning;
+) with system versioning;
create or replace table emp (
emp_id int(10) primary key,
@@ -20,21 +19,29 @@ create or replace table emp (
foreign key (mgr) references emp (emp_id)
on delete restrict
on update restrict
-)
-with system versioning;
+) with system versioning;
insert into dept (dept_id, name) values (10, "accounting");
-insert into emp (emp_id, name, salary, dept_id, mgr) values
+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 max(sys_trx_start) into @ts_1 from emp;
+select row_start into @ts_1 from emp where name="jane";
update emp set mgr=30 where name ="john";
-select sys_trx_start into @ts_2 from emp 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;
+
+select row_start into @ts_2 from emp where name="john";
+
+let $q=
/* All report to 'Bill' */
with recursive
ancestors
@@ -43,7 +50,7 @@ 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
+ 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
@@ -51,21 +58,138 @@ as
)
select * from ancestors;
-/* Expected 3 rows */
+eval explain extended $q;
+eval $q;
+
+let $q=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;
+
+eval explain extended $q;
+eval $q;
+
+let $q=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);
+
+eval explain extended $q;
+eval $q;
+
with recursive
ancestors
as
(
select e.emp_id, e.name, e.mgr, e.salary
- from emp for system_time as of timestamp @ts_2 as e
+ from emp as e
where name = 'bill'
- union
+ union
select e.emp_id, e.name, e.mgr, e.salary
- from emp for system_time as of timestamp @ts_2 as e,
+ from emp as e,
ancestors as a
where e.mgr = a.emp_id
)
-select * from ancestors;
+select * from ancestors for system_time as of @ts_2,
+ ancestors for system_time as of @ts_2 a2;
+
+--error ER_AMBIGUOUS_FOR_SYSTEM_TIME
+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 ER_AMBIGUOUS_FOR_SYSTEM_TIME
+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 ER_AMBIGUOUS_FOR_SYSTEM_TIME
+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 ER_AMBIGUOUS_FOR_SYSTEM_TIME
+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);
+
+--echo # SYSTEM_TIME to internal recursive instance is prohibited
+--error ER_VERS_NOT_VERSIONED
+with recursive cte as
+(
+ select * from emp
+ union all
+ select * from cte for system_time as of @ts_1
+)
+select * from cte;
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;
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index a5209ba5115..4b31e4b528a 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -3674,7 +3674,7 @@ int subselect_single_select_engine::prepare(THD *thd)
int subselect_union_engine::prepare(THD *thd_arg)
{
set_thd(thd_arg);
- return unit->prepare(thd, result, SELECT_NO_UNLOCK);
+ return unit->prepare(unit->derived, result, SELECT_NO_UNLOCK);
}
int subselect_uniquesubquery_engine::prepare(THD *)
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index 17192663381..e9a07bc8c59 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -7859,8 +7859,8 @@ ER_VERS_ALTER_ENGINE_PROHIBITED
ER_VERS_RANGE_PROHIBITED
eng "SYSTEM_TIME range selector is not allowed"
-ER_UNUSED_26
- eng "You should never see it"
+ER_CONFLICTING_FOR_SYSTEM_TIME
+ eng "Conflicting FOR SYSTEM_TIME clauses in WITH RECURSIVE"
ER_VERS_TABLE_MUST_HAVE_COLUMNS
eng "Table %`s must have at least one versioned column"
diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc
index a58a9254a82..0cdd664d05c 100644
--- a/sql/sql_cte.cc
+++ b/sql/sql_cte.cc
@@ -978,7 +978,7 @@ bool With_element::prepare_unreferenced(THD *thd)
thd->lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_DERIVED;
if (!spec->prepared &&
- (spec->prepare(thd, 0, 0) ||
+ (spec->prepare(spec->derived, 0, 0) ||
rename_columns_of_derived_unit(thd, spec) ||
check_duplicate_names(thd, first_sl->item_list, 1)))
rc= true;
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index ab66384c6cb..6c2242b6ced 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -747,8 +747,6 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
}
}
- unit->derived= derived;
-
/*
Above cascade call of prepare is important for PS protocol, but after it
is called we can check if we really need prepare for this derived
@@ -766,7 +764,7 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_DERIVED;
// st_select_lex_unit::prepare correctly work for single select
- if ((res= unit->prepare(thd, derived->derived_result, 0)))
+ if ((res= unit->prepare(derived, derived->derived_result, 0)))
goto exit;
if (derived->with &&
(res= derived->with->rename_columns_of_derived_unit(thd, unit)))
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 02c2ffb6a12..6b66670617c 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -770,7 +770,8 @@ class st_select_lex_unit: public st_select_lex_node {
bool is_excluded() { return prev == NULL; }
/* UNION methods */
- bool prepare(THD *thd, select_result *result, ulong additional_options);
+ bool prepare(TABLE_LIST *derived_arg, select_result *sel_result,
+ ulong additional_options);
bool optimize();
bool exec();
bool exec_recursive();
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 24f3cc66c6b..5e46a7192d7 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1528,7 +1528,7 @@ static int mysql_test_select(Prepared_statement *stmt,
It is not SELECT COMMAND for sure, so setup_tables will be called as
usual, and we pass 0 as setup_tables_done_option
*/
- if (unit->prepare(thd, 0, 0))
+ if (unit->prepare(unit->derived, 0, 0))
goto error;
if (!lex->describe && !thd->lex->analyze_stmt && !stmt->is_sql_prepare())
{
@@ -1699,7 +1699,7 @@ static bool select_like_stmt_test(Prepared_statement *stmt,
thd->lex->used_tables= 0; // Updated by setup_fields
/* Calls JOIN::prepare */
- DBUG_RETURN(lex->unit.prepare(thd, 0, setup_tables_done_option));
+ DBUG_RETURN(lex->unit.prepare(lex->unit.derived, 0, setup_tables_done_option));
}
/**
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index b8fd6bd3da9..45850328f14 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -25635,7 +25635,8 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
unit->fake_select_lex->type= unit_operation_text[unit->common_op()];
unit->fake_select_lex->options|= SELECT_DESCRIBE;
}
- if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK | SELECT_DESCRIBE)))
+ if (!(res= unit->prepare(unit->derived, result,
+ SELECT_NO_UNLOCK | SELECT_DESCRIBE)))
res= unit->exec();
}
else
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 446e33366f3..d0922347b77 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -36,7 +36,7 @@ bool mysql_union(THD *thd, LEX *lex, select_result *result,
{
DBUG_ENTER("mysql_union");
bool res;
- if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK |
+ if (!(res= unit->prepare(unit->derived, result, SELECT_NO_UNLOCK |
setup_tables_done_option)))
res= unit->exec();
res|= unit->cleanup();
@@ -810,10 +810,11 @@ bool st_select_lex_unit::join_union_item_types(THD *thd_arg,
}
-bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
+bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
+ select_result *sel_result,
ulong additional_options)
{
- SELECT_LEX *lex_select_save= thd_arg->lex->current_select;
+ SELECT_LEX *lex_select_save= thd->lex->current_select;
SELECT_LEX *sl, *first_sl= first_select();
bool is_recursive= with_element && with_element->is_recursive;
bool is_rec_result_table_created= false;
@@ -824,7 +825,6 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
bool instantiate_tmp_table= false;
bool single_tvc= !first_sl->next_select() && first_sl->tvc;
DBUG_ENTER("st_select_lex_unit::prepare");
- DBUG_ASSERT(thd == thd_arg);
DBUG_ASSERT(thd == current_thd);
describe= additional_options & SELECT_DESCRIBE;
@@ -876,7 +876,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
prepared= 1;
saved_error= FALSE;
- thd_arg->lex->current_select= sl= first_sl;
+ thd->lex->current_select= sl= first_sl;
found_rows_for_union= first_sl->options & OPTION_FOUND_ROWS;
is_union_select= is_unit_op() || fake_select_lex || single_tvc;
@@ -905,7 +905,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
while (last->next_select())
last= last->next_select();
if (!(tmp_result= union_result=
- new (thd_arg->mem_root) select_union_direct(thd_arg, sel_result,
+ new (thd->mem_root) select_union_direct(thd, sel_result,
last)))
goto err; /* purecov: inspected */
fake_select_lex= NULL;
@@ -914,11 +914,11 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
else
{
if (!is_recursive)
- union_result= new (thd_arg->mem_root) select_unit(thd_arg);
+ union_result= new (thd->mem_root) select_unit(thd);
else
{
with_element->rec_result=
- new (thd_arg->mem_root) select_union_recursive(thd_arg);
+ new (thd->mem_root) select_union_recursive(thd);
union_result= with_element->rec_result;
fake_select_lex= NULL;
}
@@ -936,10 +936,10 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
{
if (sl->tvc)
{
- if (sl->tvc->prepare(thd_arg, sl, tmp_result, this))
+ if (sl->tvc->prepare(thd, sl, tmp_result, this))
goto err;
}
- else if (prepare_join(thd_arg, first_sl, tmp_result, additional_options,
+ else if (prepare_join(thd, first_sl, tmp_result, additional_options,
is_union_select))
goto err;
types= first_sl->item_list;
@@ -950,10 +950,10 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
{
if (sl->tvc)
{
- if (sl->tvc->prepare(thd_arg, sl, tmp_result, this))
+ if (sl->tvc->prepare(thd, sl, tmp_result, this))
goto err;
}
- else if (prepare_join(thd_arg, sl, tmp_result, additional_options,
+ else if (prepare_join(thd, sl, tmp_result, additional_options,
is_union_select))
goto err;
@@ -973,7 +973,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
{
if (with_element)
{
- if (derived->with->rename_columns_of_derived_unit(thd, this))
+ if (derived_arg->with->rename_columns_of_derived_unit(thd, this))
goto err;
if (check_duplicate_names(thd, sl->item_list, 0))
goto err;
@@ -984,7 +984,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
if (first_sl->item_list.elements != sl->item_list.elements)
{
my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,
- ER_THD(thd_arg, ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),
+ ER_THD(thd, ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),
MYF(0));
goto err;
}
@@ -993,25 +993,25 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
{
if (!with_element->is_anchor(sl))
sl->uncacheable|= UNCACHEABLE_UNITED;
- if(!is_rec_result_table_created &&
- (!sl->next_select() ||
- sl->next_select() == with_element->first_recursive))
+ if (!is_rec_result_table_created &&
+ (!sl->next_select() ||
+ sl->next_select() == with_element->first_recursive))
{
ulonglong create_options;
- create_options= (first_sl->options | thd_arg->variables.option_bits |
+ create_options= (first_sl->options | thd->variables.option_bits |
TMP_TABLE_ALL_COLUMNS);
// Join data types for all non-recursive parts of a recursive UNION
if (join_union_item_types(thd, types, union_part_count + 1))
goto err;
if (union_result->create_result_table(thd, &types,
MY_TEST(union_distinct),
- create_options, &derived->alias,
- false,
+ create_options,
+ &derived_arg->alias, false,
instantiate_tmp_table, false,
0))
goto err;
- if (!derived->table)
- derived->table= derived->derived_result->table=
+ if (!derived_arg->table)
+ derived_arg->table= derived_arg->derived_result->table=
with_element->rec_result->rec_tables.head();
with_element->mark_as_with_prepared_anchor();
is_rec_result_table_created= true;
@@ -1082,7 +1082,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
}
- create_options= (first_sl->options | thd_arg->variables.option_bits |
+ create_options= (first_sl->options | thd->variables.option_bits |
TMP_TABLE_ALL_COLUMNS);
/*
Force the temporary table to be a MyISAM table if we're going to use
@@ -1110,7 +1110,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
Query_arena *arena, backup_arena;
arena= thd->activate_stmt_arena_if_needed(&backup_arena);
- intersect_mark= new (thd_arg->mem_root) Item_int(thd, 0);
+ intersect_mark= new (thd->mem_root) Item_int(thd, 0);
if (arena)
thd->restore_active_arena(arena, &backup_arena);
@@ -1154,7 +1154,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
result_table_list.maybe_null_exec= save_maybe_null;
}
- thd_arg->lex->current_select= lex_select_save;
+ thd->lex->current_select= lex_select_save;
if (!item_list.elements)
{
Query_arena *arena, backup_arena;
@@ -1194,7 +1194,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
*/
fake_select_lex->item_list= item_list;
- thd_arg->lex->current_select= fake_select_lex;
+ thd->lex->current_select= fake_select_lex;
/*
We need to add up n_sum_items in order to make the correct
@@ -1222,12 +1222,12 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
}
}
- thd_arg->lex->current_select= lex_select_save;
+ thd->lex->current_select= lex_select_save;
- DBUG_RETURN(saved_error || thd_arg->is_fatal_error);
+ DBUG_RETURN(saved_error || thd->is_fatal_error);
err:
- thd_arg->lex->current_select= lex_select_save;
+ thd->lex->current_select= lex_select_save;
(void) cleanup();
DBUG_RETURN(TRUE);
}
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index e910d48c75c..b5700fa5ee1 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -530,7 +530,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
/* prepare select to resolve all fields */
lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW;
- if (unit->prepare(thd, 0, 0))
+ if (unit->prepare(unit->derived, 0, 0))
{
/*
some errors from prepare are reported to user, if is not then
diff --git a/sql/table.cc b/sql/table.cc
index 577ed20a87e..75c7d69cfa7 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -8114,7 +8114,21 @@ bool TABLE_LIST::init_derived(THD *thd, bool init_view)
(first_table && first_table->is_multitable()))
set_multitable();
- unit->derived= this;
+ if (!unit->derived)
+ unit->derived= this;
+ else if (!is_with_table_recursive_reference())
+ {
+ if (unit->derived->is_with_table_recursive_reference())
+ unit->derived= this;
+ else if (vers_conditions.eq(unit->derived->vers_conditions))
+ vers_conditions.empty();
+ else
+ {
+ my_error(ER_CONFLICTING_FOR_SYSTEM_TIME, MYF(0));
+ return TRUE;
+ }
+ }
+
if (init_view && !view)
{
/* This is all what we can do for a derived table for now. */
@@ -8864,6 +8878,26 @@ void vers_select_conds_t::resolve_units(bool timestamps_only)
end.resolve_unit(timestamps_only);
}
+bool vers_select_conds_t::eq(const vers_select_conds_t &conds)
+{
+ if (type != conds.type)
+ return false;
+ switch (type) {
+ case SYSTEM_TIME_UNSPECIFIED:
+ case SYSTEM_TIME_ALL:
+ return true;
+ case SYSTEM_TIME_BEFORE:
+ DBUG_ASSERT(0);
+ case SYSTEM_TIME_AS_OF:
+ return start.eq(conds.start);
+ case SYSTEM_TIME_FROM_TO:
+ case SYSTEM_TIME_BETWEEN:
+ return start.eq(conds.start) && end.eq(conds.end);
+ }
+ DBUG_ASSERT(0);
+ return false;
+}
+
void Vers_history_point::resolve_unit(bool timestamps_only)
{
if (item && unit == VERS_UNDEFINED)
@@ -8885,6 +8919,12 @@ void Vers_history_point::fix_item()
item->decimals= 6;
}
+
+bool Vers_history_point::eq(const vers_history_point_t &point)
+{
+ return unit == point.unit && item->eq(point.item, false);
+}
+
void Vers_history_point::print(String *str, enum_query_type query_type,
const char *prefix, size_t plen)
{
diff --git a/sql/table.h b/sql/table.h
index ac382e5aa94..8f8929de066 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -1827,6 +1827,7 @@ class Vers_history_point : public vers_history_point_t
void empty() { unit= VERS_UNDEFINED; item= NULL; }
void print(String *str, enum_query_type, const char *prefix, size_t plen);
void resolve_unit(bool timestamps_only);
+ bool eq(const vers_history_point_t &point);
};
struct vers_select_conds_t
@@ -1876,6 +1877,7 @@ struct vers_select_conds_t
{
return !from_query && type != SYSTEM_TIME_UNSPECIFIED;
}
+ bool eq(const vers_select_conds_t &conds);
};
/*
1
0
[Commits] ccae16d: MDEV-12387 Push conditions into materialized subqueries
by galina.shalygina@mariadb.com 23 Apr '18
by galina.shalygina@mariadb.com 23 Apr '18
23 Apr '18
revision-id: ccae16dfc128bfb95421c98a7ce331c38fc747ce (mariadb-10.3.4-60-gccae16d)
parent(s): 283b3275742ca22cd1f46a21b1a794f1b52039a9
author: Galina Shalygina
committer: Galina Shalygina
timestamp: 2018-04-23 17:50:11 +0200
message:
MDEV-12387 Push conditions into materialized subqueries
The method join_equalities_after_optimize_cond() changed and renamed.
Some comments changed.
---
mysql-test/r/derived.result | 2 +-
sql/opt_subselect.cc | 401 ++++++++++++++++++++------------------------
sql/opt_subselect.h | 6 +-
sql/sql_select.cc | 7 +-
sql/sql_select.h | 6 +
5 files changed, 198 insertions(+), 224 deletions(-)
diff --git a/mysql-test/r/derived.result b/mysql-test/r/derived.result
index 32184c5..75b5391 100644
--- a/mysql-test/r/derived.result
+++ b/mysql-test/r/derived.result
@@ -632,7 +632,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
2 DERIVED t1 system NULL NULL NULL NULL 1 100.00
Warnings:
Note 1276 Field or reference 'sq.f2' of SELECT #3 was resolved in SELECT #1
-Note 1003 /* select#1 */ select 6 AS `f1` from <materialize> (/* select#4 */ select `test`.`t2`.`f3` from `test`.`t2` having `test`.`t2`.`f3` >= 8) semi join (`test`.`t2`) where `test`.`t2`.`f3` = 6 and `<subquery4>`.`f3` = 9
+Note 1003 /* select#1 */ select 6 AS `f1` from <materialize> (/* select#4 */ select `test`.`t2`.`f3` from `test`.`t2` having `test`.`t2`.`f3` >= 8) semi join (`test`.`t2`) where `<subquery4>`.`f3` = 9 and `test`.`t2`.`f3` = 6
DROP TABLE t2,t1;
#
# MDEV-9462: Out of memory using explain on 2 empty tables
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index eac779c..c3a392c 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -5429,257 +5429,220 @@ int select_value_catcher::send_data(List<Item> &items)
DBUG_RETURN(0);
}
-/**
- @brief
- Try to add an equality to some multiple equality
-
- @param thd the thread handle
- @param cond_equal the set of multiple equalities
- @param item the item that can be added
-
- @note
- To check this fact check_simple_equality is called
-
- @retval TRUE if the equality can be used to build multiple equalities
- @retval FALSE otherwise
-*/
-bool join_equalities_for_setup_jtbm_semi_joins(THD *thd,
- COND_EQUAL *cond_equal,
- Item *item)
-{
- if (!(item->type() == Item::FUNC_ITEM &&
- ((Item_func *)item)->functype() == Item_func::EQ_FUNC))
- return false;
-
- Item *left_item= ((Item_func *)item)->arguments()[0]->real_item();
- Item *right_item= ((Item_func *)item)->arguments()[1]->real_item();
-
- if (check_simple_equality(thd,
- Item::Context(Item::ANY_SUBST,
- ((Item_func_equal *)item)->compare_type_handler(),
- ((Item_func_equal *)item)->compare_collation()),
- left_item, right_item, cond_equal))
- return true;
-
- return false;
-}
-
/**
- @brief Push down equalities into the internal levels of the condition
- if needed
+ @brief
+ Conjugate conditions after optimize_cond() call
@param thd the thread handle
- @param level the current level number
- @param conds the current level condition
- @param cond_equal the equalities from the upper level that should
- be pushed down
+ @param cond the condition where to attach new conditions
+ @param cond_eq IN/OUT the multiple equalities of cond
+ @param new_conds IN/OUT the list of conditions needed to add
+ @param cond_value the returned value of the condition
@details
- During the setup_jtbm_semi_joins work new equalities can appear.
- These equalities are attached to the top level of the WHERE clause
- but are not attached to the inner levels.
- This procedure pushes equalities down to the inner levels if needed merging
- them with the exist equalities on the this level.
+ The method creates new condition through conjunction of cond and
+ the conditions from new_conds list.
+ The method is called after optimize_cond() for cond. The result
+ of the conjunction should be the same as if it was done before the
+ the optimize_cond() call.
+
+ @retval NULL if an error occurs
+ @retval otherwise the created condition
*/
-Item *search_for_missing_parts_of_equalities(THD *thd,
- uint level,
- Item *conds,
- COND_EQUAL *cond_equal)
-{
- if (conds->type() != Item::COND_ITEM)
- {
- /*
- If current level is top level — nothing to add
- */
- if (level<2)
- return conds;
-
- if (conds->type() == Item::FUNC_ITEM &&
- ((Item_func *)conds)->functype() != Item_func::MULT_EQUAL_FUNC)
- return conds;
- List_iterator<Item_equal> it(cond_equal->current_level);
- Item_equal *item;
- Item_equal *eq= (Item_equal *)conds;
-
- while ((item=it++))
- eq->merge_with_check(thd, item, true);
+Item *and_new_conditions_to_optimized_cond(THD *thd, Item *cond,
+ COND_EQUAL **cond_eq,
+ List<Item> &new_conds,
+ Item::cond_result *cond_value)
+{
+ COND_EQUAL new_cond_equal;
+ Item *item;
+ Item_equal *equality;
+ bool is_simplified_cond= false;
+ List_iterator<Item> li(new_conds);
+ List_iterator_fast<Item_equal> it(new_cond_equal.current_level);
- return eq;
- }
- else
+ /*
+ Creates multiple equalities 'new_cond_equal' from new_conds list
+ equalities. If multiple equality can't be created or the condition
+ from new_conds list isn't an equality the method leaves it in new_conds
+ list.
+
+ The equality can't be converted into the multiple equality if it
+ is a knowingly false or true equality.
+ For example, (3 = 1) equality.
+ */
+ while ((item=li++))
{
- List_iterator_fast<Item> li(*((Item_cond*) conds)->argument_list());
- Item *item;
- level++;
-
- if (((Item_cond*) conds)->functype() == Item_func::COND_AND_FUNC)
- cond_equal= &((Item_cond_and *) conds)->m_cond_equal;
-
- while ((item=li++))
- item= search_for_missing_parts_of_equalities(thd, level,
- item, cond_equal);
+ if (item->type() == Item::FUNC_ITEM &&
+ ((Item_func *) item)->functype() == Item_func::EQ_FUNC &&
+ check_simple_equality(thd,
+ Item::Context(Item::ANY_SUBST,
+ ((Item_func_equal *)item)->compare_type_handler(),
+ ((Item_func_equal *)item)->compare_collation()),
+ ((Item_func *)item)->arguments()[0]->real_item(),
+ ((Item_func *)item)->arguments()[1]->real_item(),
+ &new_cond_equal))
+ li.remove();
}
- return conds;
-}
-
-
-/**
- @brief
- Attach the equalities to the WHERE-clause condition
- @param join join where equalities should be attached
- @param eq_list the set of the equalities to add
-
- @details
- The method modifies the condition of the join (the condition of the
- WHERE clause) by adding new equalities from eq_list. It adds new
- equalities to the remain multiple equalities of the WHERE clause condition
- and attaches them to the WHERE clause condition.
-
- First all multiple equalities are disjoined from the WHERE clause condition
- to avoid repetitions.
- Multiple equalities for the on expression of join are merged with the
- equalities from eq_list. For example, MULT_EQ(t1.a, t1.b) and (t1.a = 2)
- will become MULT_EQ(2, t1.a, t1.b)
- Sometimes merge is not possible and in this case the equalities that can't
- be merged are saved to be attached to the condition later. This situation
- can appear after the optimize of the IN subquery predicate if it is
- transformed in the knowingly false equality. For example, (3 = 1) equality.
-
- Finally, a new condition is created. It consists of the old condition from
- which multiple equalities were disjoint, new multiple equalities and the
- equalities from eq_list that weren't merged with the multiple equalities.
-
- @retval TRUE if an error occurs
- @retval FALSE otherwise
-*/
-
-bool join_equalities_after_optimize_cond(JOIN *join,
- List<Item> &eq_list)
-{
- DBUG_ENTER("join_equalities_after_optimize_cond");
- Item *conds= join->conds;
- List<Item> *and_args= NULL;
- COND_EQUAL cond_equal;
- Item_equal *item_equal;
- List<Item_equal> *cond_equal_list=
- (List<Item_equal> *) &join->cond_equal->current_level;
- THD *thd= join->thd;
-
- if (conds && conds->type() == Item::COND_ITEM &&
- ((Item_cond*) conds)->functype() == Item_func::COND_AND_FUNC)
+ it.rewind();
+ if (cond && cond->type() == Item::COND_ITEM &&
+ ((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
{
- and_args= ((Item_cond*) conds)->argument_list();
- if (join->cond_equal && join->cond_equal->current_level.elements)
+ /*
+ cond is an AND-condition.
+ The method conjugates the AND-condition cond, created multiple
+ equalities 'new_cond_equal' and remain conditions from new_conds.
+
+ First, the method disjoins multiple equalities of cond and
+ merges 'new_cond_equal' multiple equalities with these equalities.
+ It checks if after the merge the multiple equalities are knowingly
+ true or false equalities.
+ It attaches to cond conditions from new_conds list and the result
+ of the merge of multiple equalities. The multiple equalities are
+ attached only to the upper level of cond AND-condition. So they
+ should be pushed down to the inner levels of cond AND-condition
+ if needed. It is done by propagate_new_equalities().
+ */
+ COND_EQUAL *cond_equal= &((Item_cond_and *) cond)->m_cond_equal;
+ List<Item_equal> *cond_equalities= &cond_equal->current_level;
+ List<Item> *and_args= ((Item_cond_and *)cond)->argument_list();
+ and_args->disjoin((List<Item> *) cond_equalities);
+ and_args->append(&new_conds);
+
+ while ((equality= it++))
{
- and_args->disjoin((List<Item> *) &join->cond_equal->current_level);
- cond_equal.current_level.append(cond_equal_list);
- join->cond_equal->current_level.empty();
+ equality->upper_levels= 0;
+ equality->merge_into_list(thd, cond_equalities, false, false);
}
+ List_iterator_fast<Item_equal> ei(*cond_equalities);
+ while ((equality= ei++))
+ {
+ if (equality->const_item() && !equality->val_int())
+ is_simplified_cond= true;
+ equality->fixed= 0;
+ if (equality->fix_fields(thd, NULL))
+ return NULL;
+ }
+
+ and_args->append((List<Item> *) cond_equalities);
+ *cond_eq= &((Item_cond_and *) cond)->m_cond_equal;
+
+ propagate_new_equalities(thd, cond, cond_equalities,
+ cond_equal->upper_levels,
+ &is_simplified_cond);
+ cond= cond->propagate_equal_fields(thd,
+ Item::Context_boolean(),
+ cond_equal);
}
- else if (join->cond_equal && join->cond_equal->current_level.elements)
+ else
{
/*
- If the condition of the WHERE clause is a multiple equality itself
- it is set to 0.
+ cond isn't AND-condition or is NULL.
+ There can be several cases:
+
+ 1. cond is a multiple equality.
+ In this case cond is merged with the multiple equalities of
+ 'new_cond_equal'.
+ The new condition is created with the conjunction of new_conds
+ list conditions and the result of merge of multiple equalities.
+ 2. cond isn't a multiple equality and isn't NULL
+ In this case new condition is created from cond, remain conditions
+ from new_conds list and created multiple equalities from
+ 'new_cond_equal'.
+ 3. cond is NULL
+ The new condition is created from the conditions from new_conds
+ list and multiple equalities from 'new_cond_equal'.
*/
- if (conds && conds->type() == Item::FUNC_ITEM &&
- ((Item_func*) conds)->functype() == Item_func::MULT_EQUAL_FUNC)
- conds= 0;
+ List<Item> new_conds_list; // List to store new condition elements
+ bool is_mult_eq= (cond && cond->type() == Item::FUNC_ITEM &&
+ ((Item_func*) cond)->functype() == Item_func::MULT_EQUAL_FUNC);
- cond_equal.current_level.append(cond_equal_list);
- join->cond_equal->current_level.empty();
- }
+ if (cond && !is_mult_eq)
+ new_conds_list.push_back(cond, thd->mem_root);
+ if (new_conds.elements > 0)
+ {
+ li.rewind();
+ while ((item=li++))
+ {
+ if (!item->fixed && item->fix_fields(thd, NULL))
+ return NULL;
+ if (item->const_item() && !item->val_int())
+ is_simplified_cond= true;
+ }
+ if (new_conds.elements > 1)
+ new_conds_list.append(&new_conds);
+ else
+ {
+ li.rewind();
+ item= li++;
+ new_conds_list.push_back(item, thd->mem_root);
+ }
+ }
- /*
- Merges the equalities from the equal_list with the multiple equalities
- of the condition of the WHERE clause. If the equality can't be merged it
- is left in the eq_list list so it can be later added to the WHERE clause.
- */
- List_iterator<Item> li(eq_list);
- Item *item;
- while ((item=li++))
- {
- if (join_equalities_for_setup_jtbm_semi_joins(thd, &cond_equal, item))
- li.remove();
- }
+ if (new_cond_equal.current_level.elements > 0)
+ {
+ if (is_mult_eq)
+ {
+ Item_equal *eq_cond= (Item_equal *)cond;
+ eq_cond->upper_levels= 0;
+ eq_cond->merge_into_list(thd, &new_cond_equal.current_level,
+ false, false);
- if (conds)
- conds= conds->propagate_equal_fields(thd,
- Item::Context_boolean(),
- &cond_equal);
+ while ((equality= it++))
+ {
+ if (equality->const_item() && !equality->val_int())
+ is_simplified_cond= true;
+ }
- /* Fix just created multiple equalities */
- List_iterator_fast<Item_equal> it(cond_equal.current_level);
- while ((item_equal= it++))
- {
- item_equal->set_link_equal_fields(true);
- item_equal->fixed= 0;
- if (item_equal->fix_fields(thd, NULL))
- DBUG_RETURN(TRUE);
- item_equal->update_used_tables();
- set_if_bigger(thd->lex->current_select->max_equal_elems,
- item_equal->n_field_items());
- }
+ if (new_cond_equal.current_level.elements +
+ new_conds_list.elements == 1)
+ {
+ it.rewind();
+ equality= it++;
+ equality->fixed= 0;
+ if (equality->fix_fields(thd, NULL))
+ return NULL;
+ }
+ *cond_eq= &new_cond_equal;
+ }
+ new_conds_list.append((List<Item> *)&new_cond_equal.current_level);
+ }
- /*
- Creates AND-condition for the WITH clause if at least one of these
- conditions is satisfied:
+ if (new_conds_list.elements > 1)
+ {
+ Item_cond_and *and_cond=
+ new (thd->mem_root) Item_cond_and(thd, new_conds_list);
- 1. there are several multiple inequalities
- 2. there remain several equalities in the equality list
- 3. in the {conds, equalities, cond_equal.current_level} set
- there are at least 2 non-empty elements.
- */
- uint mult_eq_cnt= cond_equal.current_level.elements;
- uint eq_cnt= eq_list.elements;
- if (!and_args &&
- ((mult_eq_cnt > 1) ||
- (eq_cnt > 1) ||
- (mult_eq_cnt && eq_cnt) ||
- (mult_eq_cnt && conds) ||
- (conds && eq_cnt)))
- {
- if (!conds)
- conds= new (thd->mem_root) Item_cond_and(thd);
+ and_cond->m_cond_equal.copy(new_cond_equal);
+ cond= (Item *)and_cond;
+ *cond_eq= &((Item_cond_and *)cond)->m_cond_equal;
+ }
else
{
- Item_cond_and *new_conds= new (thd->mem_root) Item_cond_and(thd);
- new_conds->argument_list()->push_back(conds);
- conds= new_conds;
+ List_iterator_fast<Item> iter(new_conds_list);
+ cond= iter++;
}
- and_args= ((Item_cond*) conds)->argument_list();
- }
-
- /* Attaches the remaining equalities from the eq_list to the WHERE clause */
- if (and_args)
- and_args->append(&eq_list);
- else
- conds= new (thd->mem_root) Item_cond_and(thd, eq_list);
- if (conds && !conds->fixed && conds->fix_fields(thd, NULL))
- DBUG_RETURN(TRUE);
+ if (!cond->fixed && cond->fix_fields(thd, NULL))
+ return NULL;
- /* Attaches the multiple equalities to the WHERE clause condition */
- ((Item_cond_and *)conds)->m_cond_equal.copy(cond_equal);
- cond_equal.current_level=
- ((Item_cond_and *)conds)->m_cond_equal.current_level;
- if (and_args)
- {
- and_args->append((List<Item> *)&cond_equal.current_level);
- conds= search_for_missing_parts_of_equalities(thd, 0, conds, &cond_equal);
- }
- else if (mult_eq_cnt == 1)
- {
- it.rewind();
- conds= it++;
+ if (new_cond_equal.current_level.elements > 0)
+ cond= cond->propagate_equal_fields(thd,
+ Item::Context_boolean(),
+ &new_cond_equal);
}
- join->conds= conds;
-
- DBUG_RETURN(FALSE);
+ /*
+ If it was found that some of the created condition parts are knowingly
+ true or false equalities method calls removes_eq_cond() to remove them
+ from the condition and set the cond_value to the appropriate value.
+ */
+ if (is_simplified_cond)
+ cond= cond->remove_eq_conds(thd, cond_value, true);
+ return cond;
}
diff --git a/sql/opt_subselect.h b/sql/opt_subselect.h
index e116fdf..0311182 100644
--- a/sql/opt_subselect.h
+++ b/sql/opt_subselect.h
@@ -26,8 +26,10 @@ int check_and_do_in_subquery_rewrites(JOIN *join);
bool convert_join_subqueries_to_semijoins(JOIN *join);
int pull_out_semijoin_tables(JOIN *join);
bool optimize_semijoin_nests(JOIN *join, table_map all_table_map);
-bool join_equalities_after_optimize_cond(JOIN *join,
- List<Item> &eq_list);
+Item *and_new_conditions_to_optimized_cond(THD *thd, Item *cond,
+ COND_EQUAL **cond_eq,
+ List<Item> &new_conds,
+ Item::cond_result *cond_value);
bool setup_degenerate_jtbm_semi_joins(JOIN *join,
List<TABLE_LIST> *join_list,
List<Item> &eq_list);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index e7bc68e..58f7a0e 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1791,9 +1791,12 @@ JOIN::optimize_inner()
if (eq_list.elements != 0)
{
- if (join_equalities_after_optimize_cond(this, eq_list))
+ conds= and_new_conditions_to_optimized_cond(thd, conds, &cond_equal,
+ eq_list, &cond_value);
+
+ if (!conds &&
+ cond_value != Item::COND_FALSE && cond_value != Item::COND_TRUE)
DBUG_RETURN(TRUE);
- conds= conds->remove_eq_conds(thd, &cond_value, true);
}
if (thd->lex->sql_command == SQLCOM_SELECT &&
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 05255e7..56b7874 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -1737,6 +1737,7 @@ class JOIN :public Sql_alloc
bool fix_all_splittings_in_plan();
bool transform_in_predicates_into_in_subq(THD *thd);
+ bool add_equalities_to_where_condition(THD *thd, List<Item> &eq_list);
private:
/**
Create a temporary table to be used for processing DISTINCT/ORDER
@@ -2448,4 +2449,9 @@ bool check_simple_equality(THD *thd, const Item::Context &ctx,
Item *left_item, Item *right_item,
COND_EQUAL *cond_equal);
+void propagate_new_equalities(THD *thd, Item *cond,
+ List<Item_equal> *new_equalities,
+ COND_EQUAL *inherited,
+ bool *is_simplifiable_cond);
+
#endif /* SQL_SELECT_INCLUDED */
1
0
revision-id: 4cf8bd79c59f23bc2c11804723143423da037738 (mariadb-10.3.5-75-g4cf8bd7)
parent(s): ae6355f56ea1496a2de2ea271f95c89e47705ef0
committer: Alexey Botchkov
timestamp: 2018-04-23 16:43:25 +0400
message:
MDEV-14024 PCRE2.
server code switched to the PCRE2 features.
---
CMakeLists.txt | 2 +-
client/CMakeLists.txt | 2 +-
client/mysqltest.cc | 2 +-
cmake/pcre.cmake | 22 +--
config.h.cmake | 1 +
extra/mariabackup/CMakeLists.txt | 4 +-
extra/mariabackup/xb_regex.h | 2 +-
libmysqld/CMakeLists.txt | 2 +-
libmysqld/examples/CMakeLists.txt | 2 +-
.../sys_vars/r/sysvars_server_notembedded.result | 2 +-
sql/CMakeLists.txt | 2 +-
sql/item_cmpfunc.cc | 168 +++++----------------
sql/item_cmpfunc.h | 29 ++--
sql/item_strfunc.cc | 14 --
sql/item_strfunc.h | 2 -
sql/mysqld.cc | 17 ---
sql/mysqld.h | 2 -
sql/sys_vars.cc | 16 +-
storage/mroonga/CMakeLists.txt | 4 +-
19 files changed, 81 insertions(+), 214 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0813cf2..b59fb23 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -324,7 +324,7 @@ IF(NOT HAVE_CXX_NEW)
ENDIF()
# Find header files from the bundled libraries
-# (yassl, readline, pcre, etc)
+# (yassl, readline, pcre2, etc)
# before the ones installed in the system
SET(CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE ON)
diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt
index e0d34b9..02579ca 100644
--- a/client/CMakeLists.txt
+++ b/client/CMakeLists.txt
@@ -45,7 +45,7 @@ ENDIF(UNIX)
MYSQL_ADD_EXECUTABLE(mysqltest mysqltest.cc COMPONENT Test)
SET_SOURCE_FILES_PROPERTIES(mysqltest.cc PROPERTIES COMPILE_FLAGS "-DTHREADS")
-TARGET_LINK_LIBRARIES(mysqltest ${CLIENT_LIB} pcre pcreposix)
+TARGET_LINK_LIBRARIES(mysqltest ${CLIENT_LIB} pcre2-8 pcre2-posix)
SET_TARGET_PROPERTIES(mysqltest PROPERTIES ENABLE_EXPORTS TRUE)
diff --git a/client/mysqltest.cc b/client/mysqltest.cc
index efc25f3..bcabcbb 100644
--- a/client/mysqltest.cc
+++ b/client/mysqltest.cc
@@ -45,7 +45,7 @@
#include <stdarg.h>
#include <violite.h>
#define PCRE_STATIC 1 /* Important on Windows */
-#include "pcreposix.h" /* pcreposix regex library */
+#include "pcre2posix.h" /* pcreposix regex library */
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
diff --git a/cmake/pcre.cmake b/cmake/pcre.cmake
index 4c11392..25ecbae 100644
--- a/cmake/pcre.cmake
+++ b/cmake/pcre.cmake
@@ -5,24 +5,16 @@ SET(WITH_PCRE "auto" CACHE STRING
MACRO (CHECK_PCRE)
IF(WITH_PCRE STREQUAL "system" OR WITH_PCRE STREQUAL "auto")
- CHECK_LIBRARY_EXISTS(pcre pcre_stack_guard "" HAVE_PCRE_STACK_GUARD)
- IF(NOT CMAKE_CROSSCOMPILING)
- SET(CMAKE_REQUIRED_LIBRARIES "pcre")
- CHECK_C_SOURCE_RUNS("
- #include <pcre.h>
- int main() {
- return -pcre_exec(NULL, NULL, NULL, -999, -999, 0, NULL, 0) < 256;
- }" PCRE_STACK_SIZE_OK)
- SET(CMAKE_REQUIRED_LIBRARIES)
- ENDIF()
+ CHECK_LIBRARY_EXISTS(pcre2-8 pcre2_match "" HAVE_PCRE2)
ENDIF()
- IF(NOT HAVE_PCRE_STACK_GUARD OR NOT PCRE_STACK_SIZE_OK OR
- WITH_PCRE STREQUAL "bundled")
+ IF(NOT HAVE_PCRE2 OR WITH_PCRE STREQUAL "bundled")
IF (WITH_PCRE STREQUAL "system")
- MESSAGE(FATAL_ERROR "system pcre is not found or unusable")
+ MESSAGE(FATAL_ERROR "system pcre2-8 library is not found or unusable")
ENDIF()
- SET(PCRE_INCLUDES ${CMAKE_BINARY_DIR}/pcre ${CMAKE_SOURCE_DIR}/pcre)
- ADD_SUBDIRECTORY(pcre)
+ SET(PCRE_INCLUDES ${CMAKE_BINARY_DIR}/pcre2 ${CMAKE_SOURCE_DIR}/pcre2
+ ${CMAKE_BINARY_DIR}/pcre2/src ${CMAKE_SOURCE_DIR}/pcre2/src)
+ SET(PCRE_BUILD_TESTS OFF CACHE BOOL "Build the test")
+ ADD_SUBDIRECTORY(pcre2)
ENDIF()
ENDMACRO()
diff --git a/config.h.cmake b/config.h.cmake
index 4d14b62..b039e39 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -552,6 +552,7 @@
#define PACKAGE_VERSION "@VERSION@"
#define VERSION "@VERSION@"
#define PROTOCOL_VERSION 10
+#define PCRE2_CODE_UNIT_WIDTH 8
#define MALLOC_LIBRARY "@MALLOC_LIBRARY@"
diff --git a/extra/mariabackup/CMakeLists.txt b/extra/mariabackup/CMakeLists.txt
index f92da3f..a787251 100644
--- a/extra/mariabackup/CMakeLists.txt
+++ b/extra/mariabackup/CMakeLists.txt
@@ -37,7 +37,7 @@ INCLUDE_DIRECTORIES(
)
IF(NOT HAVE_SYSTEM_REGEX)
- INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/pcre)
+ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/pcre2 ${CMAKE_SOURCE_DIR}/pcre2/src)
ENDIF()
IF(WITH_WSREP)
@@ -92,7 +92,7 @@ ADD_SUBDIRECTORY(crc)
TARGET_LINK_LIBRARIES(mariabackup sql crc)
IF(NOT HAVE_SYSTEM_REGEX)
- TARGET_LINK_LIBRARIES(mariabackup pcreposix)
+ TARGET_LINK_LIBRARIES(mariabackup pcre2-posix)
ENDIF()
diff --git a/extra/mariabackup/xb_regex.h b/extra/mariabackup/xb_regex.h
index 2e07e43..6277d04 100644
--- a/extra/mariabackup/xb_regex.h
+++ b/extra/mariabackup/xb_regex.h
@@ -25,7 +25,7 @@ my_regex is used on Windows and native calls are used on POSIX platforms. */
#ifdef HAVE_SYSTEM_REGEX
#include <regex.h>
#else
-#include <pcreposix.h>
+#include <pcre2posix.h>
#endif
typedef regex_t* xb_regex_t;
diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt
index 718e832..29ddc2a 100644
--- a/libmysqld/CMakeLists.txt
+++ b/libmysqld/CMakeLists.txt
@@ -145,7 +145,7 @@ ENDIF()
SET(LIBS
- dbug strings mysys mysys_ssl pcre vio
+ dbug strings mysys mysys_ssl pcre2-8 vio
${ZLIB_LIBRARY} ${SSL_LIBRARIES}
${LIBWRAP} ${LIBCRYPT} ${LIBDL}
${MYSQLD_STATIC_PLUGIN_LIBS}
diff --git a/libmysqld/examples/CMakeLists.txt b/libmysqld/examples/CMakeLists.txt
index d47638a..c2f7766 100644
--- a/libmysqld/examples/CMakeLists.txt
+++ b/libmysqld/examples/CMakeLists.txt
@@ -34,7 +34,7 @@ ENDIF(UNIX)
MYSQL_ADD_EXECUTABLE(mysqltest_embedded ../../client/mysqltest.cc
COMPONENT Test)
-TARGET_LINK_LIBRARIES(mysqltest_embedded mysqlserver pcre pcreposix)
+TARGET_LINK_LIBRARIES(mysqltest_embedded mysqlserver pcre2-8 pcre2-posix)
IF(CMAKE_GENERATOR MATCHES "Xcode")
# It does not seem possible to tell Xcode the resulting target might need
diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
index 67786cc..4d1d677 100644
--- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
+++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
@@ -695,7 +695,7 @@ VARIABLE_COMMENT Default flags for the regex library
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
-ENUM_VALUE_LIST DOTALL,DUPNAMES,EXTENDED,EXTRA,MULTILINE,UNGREEDY
+ENUM_VALUE_LIST DOTALL,DUPNAMES,EXTENDED,EXTENDED_MORE,EXTRA,MULTILINE,UNGREEDY
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME DEFAULT_STORAGE_ENGINE
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index c7c4df2..6c461a7 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -177,7 +177,7 @@ ADD_LIBRARY(sql STATIC ${SQL_SOURCE})
ADD_DEPENDENCIES(sql GenServerSource)
DTRACE_INSTRUMENT(sql)
TARGET_LINK_LIBRARIES(sql ${MYSQLD_STATIC_PLUGIN_LIBS}
- mysys mysys_ssl dbug strings vio pcre
+ mysys mysys_ssl dbug strings vio pcre2-8
${LIBWRAP} ${LIBCRYPT} ${LIBDL} ${CMAKE_THREAD_LIBS_INIT}
${WSREP_LIB}
${SSL_LIBRARIES}
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 89aa307..2b3afed 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -5481,15 +5481,6 @@ int Regexp_processor_pcre::default_regex_flags()
return default_regex_flags_pcre(current_thd);
}
-void Regexp_processor_pcre::set_recursion_limit(THD *thd)
-{
- long stack_used;
- DBUG_ASSERT(thd == current_thd);
- stack_used= available_stack_size(thd->thread_stack, &stack_used);
- m_pcre_extra.match_limit_recursion=
- (ulong)((my_thread_stack_size - STACK_MIN_SIZE - stack_used)/my_pcre_frame_size);
-}
-
/**
Convert string to lib_charset, if needed.
@@ -5523,8 +5514,8 @@ String *Regexp_processor_pcre::convert_if_needed(String *str, String *converter)
bool Regexp_processor_pcre::compile(String *pattern, bool send_error)
{
- const char *pcreErrorStr;
- int pcreErrorOffset;
+ int pcreErrorNumber;
+ PCRE2_SIZE pcreErrorOffset;
if (is_compiled())
{
@@ -5537,19 +5528,32 @@ bool Regexp_processor_pcre::compile(String *pattern, bool send_error)
if (!(pattern= convert_if_needed(pattern, &pattern_converter)))
return true;
- m_pcre= pcre_compile(pattern->c_ptr_safe(), m_library_flags,
- &pcreErrorStr, &pcreErrorOffset, NULL);
+ m_pcre= pcre2_compile((PCRE2_SPTR8) pattern->ptr(), pattern->length(),
+ m_library_flags,
+ &pcreErrorNumber, &pcreErrorOffset, NULL);
if (m_pcre == NULL)
{
if (send_error)
{
char buff[MAX_FIELD_WIDTH];
- my_snprintf(buff, sizeof(buff), "%s at offset %d", pcreErrorStr, pcreErrorOffset);
+ int lmsg= pcre2_get_error_message(pcreErrorNumber,
+ (PCRE2_UCHAR8 *)buff, sizeof(buff));
+ if (lmsg >= 0)
+ my_snprintf(buff+lmsg, sizeof(buff)-lmsg,
+ " at offset %d", pcreErrorOffset);
my_error(ER_REGEXP_ERROR, MYF(0), buff);
}
return true;
}
+
+ m_pcre_match_data= pcre2_match_data_create_from_pattern(m_pcre, NULL);
+ if (m_pcre_match_data == NULL)
+ {
+ my_error(ER_OUT_OF_RESOURCES, MYF(0));
+ return true;
+ }
+
return false;
}
@@ -5570,124 +5574,43 @@ bool Regexp_processor_pcre::compile(Item *item, bool send_error)
*/
void Regexp_processor_pcre::pcre_exec_warn(int rc) const
{
- char buf[64];
- const char *errmsg= NULL;
+ PCRE2_UCHAR8 buf[128];
THD *thd= current_thd;
-
- /*
- Make a descriptive message only for those pcre_exec() error codes
- that can actually happen in MariaDB.
- */
- switch (rc)
- {
- case PCRE_ERROR_NULL:
- errmsg= "pcre_exec: null argument passed";
- break;
- case PCRE_ERROR_BADOPTION:
- errmsg= "pcre_exec: bad option";
- break;
- case PCRE_ERROR_BADMAGIC:
- errmsg= "pcre_exec: bad magic - not a compiled regex";
- break;
- case PCRE_ERROR_UNKNOWN_OPCODE:
- errmsg= "pcre_exec: error in compiled regex";
- break;
- case PCRE_ERROR_NOMEMORY:
- errmsg= "pcre_exec: Out of memory";
- break;
- case PCRE_ERROR_NOSUBSTRING:
- errmsg= "pcre_exec: no substring";
- break;
- case PCRE_ERROR_MATCHLIMIT:
- errmsg= "pcre_exec: match limit exceeded";
- break;
- case PCRE_ERROR_CALLOUT:
- errmsg= "pcre_exec: callout error";
- break;
- case PCRE_ERROR_BADUTF8:
- errmsg= "pcre_exec: Invalid utf8 byte sequence in the subject string";
- break;
- case PCRE_ERROR_BADUTF8_OFFSET:
- errmsg= "pcre_exec: Started at invalid location within utf8 byte sequence";
- break;
- case PCRE_ERROR_PARTIAL:
- errmsg= "pcre_exec: partial match";
- break;
- case PCRE_ERROR_INTERNAL:
- errmsg= "pcre_exec: internal error";
- break;
- case PCRE_ERROR_BADCOUNT:
- errmsg= "pcre_exec: ovesize is negative";
- break;
- case PCRE_ERROR_RECURSIONLIMIT:
- my_snprintf(buf, sizeof(buf), "pcre_exec: recursion limit of %ld exceeded",
- m_pcre_extra.match_limit_recursion);
- errmsg= buf;
- break;
- case PCRE_ERROR_BADNEWLINE:
- errmsg= "pcre_exec: bad newline options";
- break;
- case PCRE_ERROR_BADOFFSET:
- errmsg= "pcre_exec: start offset negative or greater than string length";
- break;
- case PCRE_ERROR_SHORTUTF8:
- errmsg= "pcre_exec: ended in middle of utf8 sequence";
- break;
- case PCRE_ERROR_JIT_STACKLIMIT:
- errmsg= "pcre_exec: insufficient stack memory for JIT compile";
- break;
- case PCRE_ERROR_RECURSELOOP:
- errmsg= "pcre_exec: Recursion loop detected";
- break;
- case PCRE_ERROR_BADMODE:
- errmsg= "pcre_exec: compiled pattern passed to wrong bit library function";
- break;
- case PCRE_ERROR_BADENDIANNESS:
- errmsg= "pcre_exec: compiled pattern passed to wrong endianness processor";
- break;
- case PCRE_ERROR_JIT_BADOPTION:
- errmsg= "pcre_exec: bad jit option";
- break;
- case PCRE_ERROR_BADLENGTH:
- errmsg= "pcre_exec: negative length";
- break;
- default:
- /*
- As other error codes should normally not happen,
- we just report the error code without textual description
- of the code.
- */
- my_snprintf(buf, sizeof(buf), "pcre_exec: Internal error (%d)", rc);
- errmsg= buf;
- }
+ int errlen= pcre2_get_error_message(rc, buf, sizeof(buf));
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_REGEXP_ERROR, ER_THD(thd, ER_REGEXP_ERROR), errmsg);
+ ER_REGEXP_ERROR, ER_THD(thd, ER_REGEXP_ERROR),
+ (errlen > 0) ? (const char *) buf : "Unknown PCRE error.");
}
/**
Call pcre_exec() and send a warning if pcre_exec() returned with an error.
*/
-int Regexp_processor_pcre::pcre_exec_with_warn(const pcre *code,
- const pcre_extra *extra,
+int Regexp_processor_pcre::pcre_exec_with_warn(const pcre2_code *code,
+ pcre2_match_data *data,
const char *subject,
int length, int startoffset,
- int options, int *ovector,
- int ovecsize)
+ uint options)
{
- int rc= pcre_exec(code, extra, subject, length,
- startoffset, options, ovector, ovecsize);
+ int rc= pcre2_match(code, (PCRE2_SPTR8) subject, (PCRE2_SIZE) length,
+ (PCRE2_SIZE) startoffset, options, data, NULL);
DBUG_EXECUTE_IF("pcre_exec_error_123", rc= -123;);
- if (rc < PCRE_ERROR_NOMATCH)
+ if (rc < PCRE2_ERROR_NOMATCH)
+ {
pcre_exec_warn(rc);
+ m_SubStrVec= NULL;
+ }
+ else
+ m_SubStrVec= pcre2_get_ovector_pointer(data);
+
return rc;
}
bool Regexp_processor_pcre::exec(const char *str, size_t length, size_t offset)
{
- m_pcre_exec_rc= pcre_exec_with_warn(m_pcre, &m_pcre_extra, str, (int)length, (int)offset, 0,
- m_SubStrVec, array_elements(m_SubStrVec));
+ m_pcre_exec_rc= pcre_exec_with_warn(m_pcre, m_pcre_match_data,
+ str, (int)length, (int)offset, 0);
return false;
}
@@ -5697,10 +5620,8 @@ bool Regexp_processor_pcre::exec(String *str, int offset,
{
if (!(str= convert_if_needed(str, &subject_converter)))
return true;
- m_pcre_exec_rc= pcre_exec_with_warn(m_pcre, &m_pcre_extra,
- str->c_ptr_safe(), str->length(),
- offset, 0,
- m_SubStrVec, array_elements(m_SubStrVec));
+ m_pcre_exec_rc= pcre_exec_with_warn(m_pcre, m_pcre_match_data,
+ str->ptr(), str->length(), offset, 0);
if (m_pcre_exec_rc > 0)
{
uint i;
@@ -5750,12 +5671,6 @@ void Regexp_processor_pcre::fix_owner(Item_func *owner,
}
-bool Item_func_regex::fix_fields(THD *thd, Item **ref)
-{
- re.set_recursion_limit(thd);
- return Item_bool_func::fix_fields(thd, ref);
-}
-
void
Item_func_regex::fix_length_and_dec()
{
@@ -5782,13 +5697,6 @@ longlong Item_func_regex::val_int()
}
-bool Item_func_regexp_instr::fix_fields(THD *thd, Item **ref)
-{
- re.set_recursion_limit(thd);
- return Item_int_func::fix_fields(thd, ref);
-}
-
-
void
Item_func_regexp_instr::fix_length_and_dec()
{
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 3d11a22..797c54a 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -25,7 +25,7 @@
#include "item_func.h" /* Item_int_func, Item_bool_func */
#define PCRE_STATIC 1 /* Important on Windows */
-#include "pcre.h" /* pcre header file */
+#include "pcre2.h" /* pcre header file */
#include "item.h"
extern Item_result item_cmp_type(Item_result a,Item_result b);
@@ -2728,8 +2728,8 @@ class Item_func_like :public Item_bool_func2
class Regexp_processor_pcre
{
- pcre *m_pcre;
- pcre_extra m_pcre_extra;
+ pcre2_code *m_pcre;
+ pcre2_match_data *m_pcre_match_data;
bool m_conversion_is_needed;
bool m_is_const;
int m_library_flags;
@@ -2737,34 +2737,33 @@ class Regexp_processor_pcre
CHARSET_INFO *m_library_charset;
String m_prev_pattern;
int m_pcre_exec_rc;
- int m_SubStrVec[30];
+ PCRE2_SIZE *m_SubStrVec;
void pcre_exec_warn(int rc) const;
- int pcre_exec_with_warn(const pcre *code, const pcre_extra *extra,
+ int pcre_exec_with_warn(const pcre2_code *code,
+ pcre2_match_data *data,
const char *subject, int length, int startoffset,
- int options, int *ovector, int ovecsize);
+ uint options);
public:
String *convert_if_needed(String *src, String *converter);
String subject_converter;
String pattern_converter;
String replace_converter;
Regexp_processor_pcre() :
- m_pcre(NULL), m_conversion_is_needed(true), m_is_const(0),
+ m_pcre(NULL), m_pcre_match_data(NULL),
+ m_conversion_is_needed(true), m_is_const(0),
m_library_flags(0),
m_data_charset(&my_charset_utf8_general_ci),
m_library_charset(&my_charset_utf8_general_ci)
{
- m_pcre_extra.flags= PCRE_EXTRA_MATCH_LIMIT_RECURSION;
- m_pcre_extra.match_limit_recursion= 100L;
}
int default_regex_flags();
- void set_recursion_limit(THD *);
void init(CHARSET_INFO *data_charset, int extra_flags)
{
m_library_flags= default_regex_flags() | extra_flags |
(data_charset != &my_charset_bin ?
- (PCRE_UTF8 | PCRE_UCP) : 0) |
+ (PCRE2_UTF | PCRE2_UCP) : 0) |
((data_charset->state &
- (MY_CS_BINSORT | MY_CS_CSSORT)) ? 0 : PCRE_CASELESS);
+ (MY_CS_BINSORT | MY_CS_CSSORT)) ? 0 : PCRE2_CASELESS);
// Convert text data to utf-8.
m_library_charset= data_charset == &my_charset_bin ?
@@ -2800,11 +2799,13 @@ class Regexp_processor_pcre
void reset()
{
m_pcre= NULL;
+ m_pcre_match_data= NULL;
m_prev_pattern.length(0);
}
void cleanup()
{
- pcre_free(m_pcre);
+ pcre2_match_data_free(m_pcre_match_data);
+ pcre2_code_free(m_pcre);
reset();
}
bool is_compiled() const { return m_pcre != NULL; }
@@ -2829,7 +2830,6 @@ class Item_func_regex :public Item_bool_func
DBUG_VOID_RETURN;
}
longlong val_int();
- bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec();
const char *func_name() const { return "regexp"; }
enum precedence precedence() const { return CMP_PRECEDENCE; }
@@ -2879,7 +2879,6 @@ class Item_func_regexp_instr :public Item_long_func
DBUG_VOID_RETURN;
}
longlong val_int();
- bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec();
const char *func_name() const { return "regexp_instr"; }
Item *get_copy(THD *thd)
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index c6b0ae7..0a1480e 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1276,13 +1276,6 @@ void Item_func_replace::fix_length_and_dec()
/*********************************************************************/
-bool Item_func_regexp_replace::fix_fields(THD *thd, Item **ref)
-{
- re.set_recursion_limit(thd);
- return Item_str_func::fix_fields(thd, ref);
-}
-
-
void Item_func_regexp_replace::fix_length_and_dec()
{
if (agg_arg_charsets_for_string_result_with_comparison(collation, args, 3))
@@ -1418,13 +1411,6 @@ String *Item_func_regexp_replace::val_str(String *str)
}
-bool Item_func_regexp_substr::fix_fields(THD *thd, Item **ref)
-{
- re.set_recursion_limit(thd);
- return Item_str_func::fix_fields(thd, ref);
-}
-
-
void Item_func_regexp_substr::fix_length_and_dec()
{
if (agg_arg_charsets_for_string_result_with_comparison(collation, args, 2))
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 4e1514c..3606151 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -376,7 +376,6 @@ class Item_func_regexp_replace :public Item_str_func
DBUG_VOID_RETURN;
}
String *val_str(String *str);
- bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec();
const char *func_name() const { return "regexp_replace"; }
Item *get_copy(THD *thd) { return 0;}
@@ -398,7 +397,6 @@ class Item_func_regexp_substr :public Item_str_func
DBUG_VOID_RETURN;
}
String *val_str(String *str);
- bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec();
const char *func_name() const { return "regexp_substr"; }
Item *get_copy(THD *thd) { return 0; }
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index fe2b9c8..b735123 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -111,7 +111,6 @@
#include "sp_rcontext.h"
#include "sp_cache.h"
#include "sql_reload.h" // reload_acl_and_cache
-#include "pcre.h"
#ifdef HAVE_POLL_H
#include <poll.h>
@@ -3758,21 +3757,6 @@ static void init_libstrings()
#endif
}
-ulonglong my_pcre_frame_size;
-
-static void init_pcre()
-{
- pcre_malloc= pcre_stack_malloc= my_str_malloc_mysqld;
- pcre_free= pcre_stack_free= my_free;
- pcre_stack_guard= check_enough_stack_size_slow;
- /* See http://pcre.org/original/doc/html/pcrestack.html */
- my_pcre_frame_size= -pcre_exec(NULL, NULL, NULL, -999, -999, 0, NULL, 0);
- // pcre can underestimate its stack usage. Use a safe value, as in the manual
- set_if_bigger(my_pcre_frame_size, 500);
- my_pcre_frame_size += 16; // Again, safety margin, see the manual
-}
-
-
/**
Initialize one of the global date/time format variables.
@@ -4560,7 +4544,6 @@ static int init_common_variables()
if (item_create_init())
return 1;
item_init();
- init_pcre();
/*
Process a comma-separated character set list and choose
the first available character set. This is mostly for
diff --git a/sql/mysqld.h b/sql/mysqld.h
index 670e136..183757b 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -574,8 +574,6 @@ extern pthread_t signal_thread;
extern struct st_VioSSLFd * ssl_acceptor_fd;
#endif /* HAVE_OPENSSL */
-extern ulonglong my_pcre_frame_size;
-
/*
The following variables were under INNODB_COMPABILITY_HOOKS
*/
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 524ce97..f2c9205 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -5672,19 +5672,21 @@ static const char *default_regex_flags_names[]=
"DOTALL", // (?s) . matches anything including NL
"DUPNAMES", // (?J) Allow duplicate names for subpatterns
"EXTENDED", // (?x) Ignore white space and # comments
- "EXTRA", // (?X) extra features (e.g. error on unknown escape character)
+ "EXTENDED_MORE",//(?xx) Ignore white space and # comments inside cheracter
+ "EXTRA", // means nothing since PCRE2
"MULTILINE", // (?m) ^ and $ match newlines within data
"UNGREEDY", // (?U) Invert greediness of quantifiers
0
};
static const int default_regex_flags_to_pcre[]=
{
- PCRE_DOTALL,
- PCRE_DUPNAMES,
- PCRE_EXTENDED,
- PCRE_EXTRA,
- PCRE_MULTILINE,
- PCRE_UNGREEDY,
+ PCRE2_DOTALL,
+ PCRE2_DUPNAMES,
+ PCRE2_EXTENDED,
+ PCRE2_EXTENDED_MORE,
+ 0, /* EXTRA flag not available since PCRE2 */
+ PCRE2_MULTILINE,
+ PCRE2_UNGREEDY,
0
};
int default_regex_flags_pcre(const THD *thd)
diff --git a/storage/mroonga/CMakeLists.txt b/storage/mroonga/CMakeLists.txt
index 5d8e8c1..57d12a1 100644
--- a/storage/mroonga/CMakeLists.txt
+++ b/storage/mroonga/CMakeLists.txt
@@ -189,8 +189,8 @@ else()
set(MYSQL_VARIANT "MySQL")
endif()
-if(EXISTS "${MYSQL_SOURCE_DIR}/pcre")
- set(MYSQL_REGEX_INCLUDE_DIR "${MYSQL_SOURCE_DIR}/pcre")
+if(EXISTS "${MYSQL_SOURCE_DIR}/pcre2")
+ set(MYSQL_REGEX_INCLUDE_DIR "${MYSQL_SOURCE_DIR}/pcre2/src")
else()
set(MYSQL_REGEX_INCLUDE_DIR "${MYSQL_SOURCE_DIR}/regex")
endif()
1
0
revision-id: 4cf8bd79c59f23bc2c11804723143423da037738 (mariadb-10.3.5-75-g4cf8bd7)
parent(s): ae6355f56ea1496a2de2ea271f95c89e47705ef0
committer: Alexey Botchkov
timestamp: 2018-04-23 16:43:25 +0400
message:
MDEV-14024 PCRE2.
server code switched to the PCRE2 features.
---
CMakeLists.txt | 2 +-
client/CMakeLists.txt | 2 +-
client/mysqltest.cc | 2 +-
cmake/pcre.cmake | 22 +--
config.h.cmake | 1 +
extra/mariabackup/CMakeLists.txt | 4 +-
extra/mariabackup/xb_regex.h | 2 +-
libmysqld/CMakeLists.txt | 2 +-
libmysqld/examples/CMakeLists.txt | 2 +-
.../sys_vars/r/sysvars_server_notembedded.result | 2 +-
sql/CMakeLists.txt | 2 +-
sql/item_cmpfunc.cc | 168 +++++----------------
sql/item_cmpfunc.h | 29 ++--
sql/item_strfunc.cc | 14 --
sql/item_strfunc.h | 2 -
sql/mysqld.cc | 17 ---
sql/mysqld.h | 2 -
sql/sys_vars.cc | 16 +-
storage/mroonga/CMakeLists.txt | 4 +-
19 files changed, 81 insertions(+), 214 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0813cf2..b59fb23 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -324,7 +324,7 @@ IF(NOT HAVE_CXX_NEW)
ENDIF()
# Find header files from the bundled libraries
-# (yassl, readline, pcre, etc)
+# (yassl, readline, pcre2, etc)
# before the ones installed in the system
SET(CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE ON)
diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt
index e0d34b9..02579ca 100644
--- a/client/CMakeLists.txt
+++ b/client/CMakeLists.txt
@@ -45,7 +45,7 @@ ENDIF(UNIX)
MYSQL_ADD_EXECUTABLE(mysqltest mysqltest.cc COMPONENT Test)
SET_SOURCE_FILES_PROPERTIES(mysqltest.cc PROPERTIES COMPILE_FLAGS "-DTHREADS")
-TARGET_LINK_LIBRARIES(mysqltest ${CLIENT_LIB} pcre pcreposix)
+TARGET_LINK_LIBRARIES(mysqltest ${CLIENT_LIB} pcre2-8 pcre2-posix)
SET_TARGET_PROPERTIES(mysqltest PROPERTIES ENABLE_EXPORTS TRUE)
diff --git a/client/mysqltest.cc b/client/mysqltest.cc
index efc25f3..bcabcbb 100644
--- a/client/mysqltest.cc
+++ b/client/mysqltest.cc
@@ -45,7 +45,7 @@
#include <stdarg.h>
#include <violite.h>
#define PCRE_STATIC 1 /* Important on Windows */
-#include "pcreposix.h" /* pcreposix regex library */
+#include "pcre2posix.h" /* pcreposix regex library */
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
diff --git a/cmake/pcre.cmake b/cmake/pcre.cmake
index 4c11392..25ecbae 100644
--- a/cmake/pcre.cmake
+++ b/cmake/pcre.cmake
@@ -5,24 +5,16 @@ SET(WITH_PCRE "auto" CACHE STRING
MACRO (CHECK_PCRE)
IF(WITH_PCRE STREQUAL "system" OR WITH_PCRE STREQUAL "auto")
- CHECK_LIBRARY_EXISTS(pcre pcre_stack_guard "" HAVE_PCRE_STACK_GUARD)
- IF(NOT CMAKE_CROSSCOMPILING)
- SET(CMAKE_REQUIRED_LIBRARIES "pcre")
- CHECK_C_SOURCE_RUNS("
- #include <pcre.h>
- int main() {
- return -pcre_exec(NULL, NULL, NULL, -999, -999, 0, NULL, 0) < 256;
- }" PCRE_STACK_SIZE_OK)
- SET(CMAKE_REQUIRED_LIBRARIES)
- ENDIF()
+ CHECK_LIBRARY_EXISTS(pcre2-8 pcre2_match "" HAVE_PCRE2)
ENDIF()
- IF(NOT HAVE_PCRE_STACK_GUARD OR NOT PCRE_STACK_SIZE_OK OR
- WITH_PCRE STREQUAL "bundled")
+ IF(NOT HAVE_PCRE2 OR WITH_PCRE STREQUAL "bundled")
IF (WITH_PCRE STREQUAL "system")
- MESSAGE(FATAL_ERROR "system pcre is not found or unusable")
+ MESSAGE(FATAL_ERROR "system pcre2-8 library is not found or unusable")
ENDIF()
- SET(PCRE_INCLUDES ${CMAKE_BINARY_DIR}/pcre ${CMAKE_SOURCE_DIR}/pcre)
- ADD_SUBDIRECTORY(pcre)
+ SET(PCRE_INCLUDES ${CMAKE_BINARY_DIR}/pcre2 ${CMAKE_SOURCE_DIR}/pcre2
+ ${CMAKE_BINARY_DIR}/pcre2/src ${CMAKE_SOURCE_DIR}/pcre2/src)
+ SET(PCRE_BUILD_TESTS OFF CACHE BOOL "Build the test")
+ ADD_SUBDIRECTORY(pcre2)
ENDIF()
ENDMACRO()
diff --git a/config.h.cmake b/config.h.cmake
index 4d14b62..b039e39 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -552,6 +552,7 @@
#define PACKAGE_VERSION "@VERSION@"
#define VERSION "@VERSION@"
#define PROTOCOL_VERSION 10
+#define PCRE2_CODE_UNIT_WIDTH 8
#define MALLOC_LIBRARY "@MALLOC_LIBRARY@"
diff --git a/extra/mariabackup/CMakeLists.txt b/extra/mariabackup/CMakeLists.txt
index f92da3f..a787251 100644
--- a/extra/mariabackup/CMakeLists.txt
+++ b/extra/mariabackup/CMakeLists.txt
@@ -37,7 +37,7 @@ INCLUDE_DIRECTORIES(
)
IF(NOT HAVE_SYSTEM_REGEX)
- INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/pcre)
+ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/pcre2 ${CMAKE_SOURCE_DIR}/pcre2/src)
ENDIF()
IF(WITH_WSREP)
@@ -92,7 +92,7 @@ ADD_SUBDIRECTORY(crc)
TARGET_LINK_LIBRARIES(mariabackup sql crc)
IF(NOT HAVE_SYSTEM_REGEX)
- TARGET_LINK_LIBRARIES(mariabackup pcreposix)
+ TARGET_LINK_LIBRARIES(mariabackup pcre2-posix)
ENDIF()
diff --git a/extra/mariabackup/xb_regex.h b/extra/mariabackup/xb_regex.h
index 2e07e43..6277d04 100644
--- a/extra/mariabackup/xb_regex.h
+++ b/extra/mariabackup/xb_regex.h
@@ -25,7 +25,7 @@ my_regex is used on Windows and native calls are used on POSIX platforms. */
#ifdef HAVE_SYSTEM_REGEX
#include <regex.h>
#else
-#include <pcreposix.h>
+#include <pcre2posix.h>
#endif
typedef regex_t* xb_regex_t;
diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt
index 718e832..29ddc2a 100644
--- a/libmysqld/CMakeLists.txt
+++ b/libmysqld/CMakeLists.txt
@@ -145,7 +145,7 @@ ENDIF()
SET(LIBS
- dbug strings mysys mysys_ssl pcre vio
+ dbug strings mysys mysys_ssl pcre2-8 vio
${ZLIB_LIBRARY} ${SSL_LIBRARIES}
${LIBWRAP} ${LIBCRYPT} ${LIBDL}
${MYSQLD_STATIC_PLUGIN_LIBS}
diff --git a/libmysqld/examples/CMakeLists.txt b/libmysqld/examples/CMakeLists.txt
index d47638a..c2f7766 100644
--- a/libmysqld/examples/CMakeLists.txt
+++ b/libmysqld/examples/CMakeLists.txt
@@ -34,7 +34,7 @@ ENDIF(UNIX)
MYSQL_ADD_EXECUTABLE(mysqltest_embedded ../../client/mysqltest.cc
COMPONENT Test)
-TARGET_LINK_LIBRARIES(mysqltest_embedded mysqlserver pcre pcreposix)
+TARGET_LINK_LIBRARIES(mysqltest_embedded mysqlserver pcre2-8 pcre2-posix)
IF(CMAKE_GENERATOR MATCHES "Xcode")
# It does not seem possible to tell Xcode the resulting target might need
diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
index 67786cc..4d1d677 100644
--- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
+++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
@@ -695,7 +695,7 @@ VARIABLE_COMMENT Default flags for the regex library
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
-ENUM_VALUE_LIST DOTALL,DUPNAMES,EXTENDED,EXTRA,MULTILINE,UNGREEDY
+ENUM_VALUE_LIST DOTALL,DUPNAMES,EXTENDED,EXTENDED_MORE,EXTRA,MULTILINE,UNGREEDY
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME DEFAULT_STORAGE_ENGINE
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index c7c4df2..6c461a7 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -177,7 +177,7 @@ ADD_LIBRARY(sql STATIC ${SQL_SOURCE})
ADD_DEPENDENCIES(sql GenServerSource)
DTRACE_INSTRUMENT(sql)
TARGET_LINK_LIBRARIES(sql ${MYSQLD_STATIC_PLUGIN_LIBS}
- mysys mysys_ssl dbug strings vio pcre
+ mysys mysys_ssl dbug strings vio pcre2-8
${LIBWRAP} ${LIBCRYPT} ${LIBDL} ${CMAKE_THREAD_LIBS_INIT}
${WSREP_LIB}
${SSL_LIBRARIES}
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 89aa307..2b3afed 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -5481,15 +5481,6 @@ int Regexp_processor_pcre::default_regex_flags()
return default_regex_flags_pcre(current_thd);
}
-void Regexp_processor_pcre::set_recursion_limit(THD *thd)
-{
- long stack_used;
- DBUG_ASSERT(thd == current_thd);
- stack_used= available_stack_size(thd->thread_stack, &stack_used);
- m_pcre_extra.match_limit_recursion=
- (ulong)((my_thread_stack_size - STACK_MIN_SIZE - stack_used)/my_pcre_frame_size);
-}
-
/**
Convert string to lib_charset, if needed.
@@ -5523,8 +5514,8 @@ String *Regexp_processor_pcre::convert_if_needed(String *str, String *converter)
bool Regexp_processor_pcre::compile(String *pattern, bool send_error)
{
- const char *pcreErrorStr;
- int pcreErrorOffset;
+ int pcreErrorNumber;
+ PCRE2_SIZE pcreErrorOffset;
if (is_compiled())
{
@@ -5537,19 +5528,32 @@ bool Regexp_processor_pcre::compile(String *pattern, bool send_error)
if (!(pattern= convert_if_needed(pattern, &pattern_converter)))
return true;
- m_pcre= pcre_compile(pattern->c_ptr_safe(), m_library_flags,
- &pcreErrorStr, &pcreErrorOffset, NULL);
+ m_pcre= pcre2_compile((PCRE2_SPTR8) pattern->ptr(), pattern->length(),
+ m_library_flags,
+ &pcreErrorNumber, &pcreErrorOffset, NULL);
if (m_pcre == NULL)
{
if (send_error)
{
char buff[MAX_FIELD_WIDTH];
- my_snprintf(buff, sizeof(buff), "%s at offset %d", pcreErrorStr, pcreErrorOffset);
+ int lmsg= pcre2_get_error_message(pcreErrorNumber,
+ (PCRE2_UCHAR8 *)buff, sizeof(buff));
+ if (lmsg >= 0)
+ my_snprintf(buff+lmsg, sizeof(buff)-lmsg,
+ " at offset %d", pcreErrorOffset);
my_error(ER_REGEXP_ERROR, MYF(0), buff);
}
return true;
}
+
+ m_pcre_match_data= pcre2_match_data_create_from_pattern(m_pcre, NULL);
+ if (m_pcre_match_data == NULL)
+ {
+ my_error(ER_OUT_OF_RESOURCES, MYF(0));
+ return true;
+ }
+
return false;
}
@@ -5570,124 +5574,43 @@ bool Regexp_processor_pcre::compile(Item *item, bool send_error)
*/
void Regexp_processor_pcre::pcre_exec_warn(int rc) const
{
- char buf[64];
- const char *errmsg= NULL;
+ PCRE2_UCHAR8 buf[128];
THD *thd= current_thd;
-
- /*
- Make a descriptive message only for those pcre_exec() error codes
- that can actually happen in MariaDB.
- */
- switch (rc)
- {
- case PCRE_ERROR_NULL:
- errmsg= "pcre_exec: null argument passed";
- break;
- case PCRE_ERROR_BADOPTION:
- errmsg= "pcre_exec: bad option";
- break;
- case PCRE_ERROR_BADMAGIC:
- errmsg= "pcre_exec: bad magic - not a compiled regex";
- break;
- case PCRE_ERROR_UNKNOWN_OPCODE:
- errmsg= "pcre_exec: error in compiled regex";
- break;
- case PCRE_ERROR_NOMEMORY:
- errmsg= "pcre_exec: Out of memory";
- break;
- case PCRE_ERROR_NOSUBSTRING:
- errmsg= "pcre_exec: no substring";
- break;
- case PCRE_ERROR_MATCHLIMIT:
- errmsg= "pcre_exec: match limit exceeded";
- break;
- case PCRE_ERROR_CALLOUT:
- errmsg= "pcre_exec: callout error";
- break;
- case PCRE_ERROR_BADUTF8:
- errmsg= "pcre_exec: Invalid utf8 byte sequence in the subject string";
- break;
- case PCRE_ERROR_BADUTF8_OFFSET:
- errmsg= "pcre_exec: Started at invalid location within utf8 byte sequence";
- break;
- case PCRE_ERROR_PARTIAL:
- errmsg= "pcre_exec: partial match";
- break;
- case PCRE_ERROR_INTERNAL:
- errmsg= "pcre_exec: internal error";
- break;
- case PCRE_ERROR_BADCOUNT:
- errmsg= "pcre_exec: ovesize is negative";
- break;
- case PCRE_ERROR_RECURSIONLIMIT:
- my_snprintf(buf, sizeof(buf), "pcre_exec: recursion limit of %ld exceeded",
- m_pcre_extra.match_limit_recursion);
- errmsg= buf;
- break;
- case PCRE_ERROR_BADNEWLINE:
- errmsg= "pcre_exec: bad newline options";
- break;
- case PCRE_ERROR_BADOFFSET:
- errmsg= "pcre_exec: start offset negative or greater than string length";
- break;
- case PCRE_ERROR_SHORTUTF8:
- errmsg= "pcre_exec: ended in middle of utf8 sequence";
- break;
- case PCRE_ERROR_JIT_STACKLIMIT:
- errmsg= "pcre_exec: insufficient stack memory for JIT compile";
- break;
- case PCRE_ERROR_RECURSELOOP:
- errmsg= "pcre_exec: Recursion loop detected";
- break;
- case PCRE_ERROR_BADMODE:
- errmsg= "pcre_exec: compiled pattern passed to wrong bit library function";
- break;
- case PCRE_ERROR_BADENDIANNESS:
- errmsg= "pcre_exec: compiled pattern passed to wrong endianness processor";
- break;
- case PCRE_ERROR_JIT_BADOPTION:
- errmsg= "pcre_exec: bad jit option";
- break;
- case PCRE_ERROR_BADLENGTH:
- errmsg= "pcre_exec: negative length";
- break;
- default:
- /*
- As other error codes should normally not happen,
- we just report the error code without textual description
- of the code.
- */
- my_snprintf(buf, sizeof(buf), "pcre_exec: Internal error (%d)", rc);
- errmsg= buf;
- }
+ int errlen= pcre2_get_error_message(rc, buf, sizeof(buf));
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_REGEXP_ERROR, ER_THD(thd, ER_REGEXP_ERROR), errmsg);
+ ER_REGEXP_ERROR, ER_THD(thd, ER_REGEXP_ERROR),
+ (errlen > 0) ? (const char *) buf : "Unknown PCRE error.");
}
/**
Call pcre_exec() and send a warning if pcre_exec() returned with an error.
*/
-int Regexp_processor_pcre::pcre_exec_with_warn(const pcre *code,
- const pcre_extra *extra,
+int Regexp_processor_pcre::pcre_exec_with_warn(const pcre2_code *code,
+ pcre2_match_data *data,
const char *subject,
int length, int startoffset,
- int options, int *ovector,
- int ovecsize)
+ uint options)
{
- int rc= pcre_exec(code, extra, subject, length,
- startoffset, options, ovector, ovecsize);
+ int rc= pcre2_match(code, (PCRE2_SPTR8) subject, (PCRE2_SIZE) length,
+ (PCRE2_SIZE) startoffset, options, data, NULL);
DBUG_EXECUTE_IF("pcre_exec_error_123", rc= -123;);
- if (rc < PCRE_ERROR_NOMATCH)
+ if (rc < PCRE2_ERROR_NOMATCH)
+ {
pcre_exec_warn(rc);
+ m_SubStrVec= NULL;
+ }
+ else
+ m_SubStrVec= pcre2_get_ovector_pointer(data);
+
return rc;
}
bool Regexp_processor_pcre::exec(const char *str, size_t length, size_t offset)
{
- m_pcre_exec_rc= pcre_exec_with_warn(m_pcre, &m_pcre_extra, str, (int)length, (int)offset, 0,
- m_SubStrVec, array_elements(m_SubStrVec));
+ m_pcre_exec_rc= pcre_exec_with_warn(m_pcre, m_pcre_match_data,
+ str, (int)length, (int)offset, 0);
return false;
}
@@ -5697,10 +5620,8 @@ bool Regexp_processor_pcre::exec(String *str, int offset,
{
if (!(str= convert_if_needed(str, &subject_converter)))
return true;
- m_pcre_exec_rc= pcre_exec_with_warn(m_pcre, &m_pcre_extra,
- str->c_ptr_safe(), str->length(),
- offset, 0,
- m_SubStrVec, array_elements(m_SubStrVec));
+ m_pcre_exec_rc= pcre_exec_with_warn(m_pcre, m_pcre_match_data,
+ str->ptr(), str->length(), offset, 0);
if (m_pcre_exec_rc > 0)
{
uint i;
@@ -5750,12 +5671,6 @@ void Regexp_processor_pcre::fix_owner(Item_func *owner,
}
-bool Item_func_regex::fix_fields(THD *thd, Item **ref)
-{
- re.set_recursion_limit(thd);
- return Item_bool_func::fix_fields(thd, ref);
-}
-
void
Item_func_regex::fix_length_and_dec()
{
@@ -5782,13 +5697,6 @@ longlong Item_func_regex::val_int()
}
-bool Item_func_regexp_instr::fix_fields(THD *thd, Item **ref)
-{
- re.set_recursion_limit(thd);
- return Item_int_func::fix_fields(thd, ref);
-}
-
-
void
Item_func_regexp_instr::fix_length_and_dec()
{
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 3d11a22..797c54a 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -25,7 +25,7 @@
#include "item_func.h" /* Item_int_func, Item_bool_func */
#define PCRE_STATIC 1 /* Important on Windows */
-#include "pcre.h" /* pcre header file */
+#include "pcre2.h" /* pcre header file */
#include "item.h"
extern Item_result item_cmp_type(Item_result a,Item_result b);
@@ -2728,8 +2728,8 @@ class Item_func_like :public Item_bool_func2
class Regexp_processor_pcre
{
- pcre *m_pcre;
- pcre_extra m_pcre_extra;
+ pcre2_code *m_pcre;
+ pcre2_match_data *m_pcre_match_data;
bool m_conversion_is_needed;
bool m_is_const;
int m_library_flags;
@@ -2737,34 +2737,33 @@ class Regexp_processor_pcre
CHARSET_INFO *m_library_charset;
String m_prev_pattern;
int m_pcre_exec_rc;
- int m_SubStrVec[30];
+ PCRE2_SIZE *m_SubStrVec;
void pcre_exec_warn(int rc) const;
- int pcre_exec_with_warn(const pcre *code, const pcre_extra *extra,
+ int pcre_exec_with_warn(const pcre2_code *code,
+ pcre2_match_data *data,
const char *subject, int length, int startoffset,
- int options, int *ovector, int ovecsize);
+ uint options);
public:
String *convert_if_needed(String *src, String *converter);
String subject_converter;
String pattern_converter;
String replace_converter;
Regexp_processor_pcre() :
- m_pcre(NULL), m_conversion_is_needed(true), m_is_const(0),
+ m_pcre(NULL), m_pcre_match_data(NULL),
+ m_conversion_is_needed(true), m_is_const(0),
m_library_flags(0),
m_data_charset(&my_charset_utf8_general_ci),
m_library_charset(&my_charset_utf8_general_ci)
{
- m_pcre_extra.flags= PCRE_EXTRA_MATCH_LIMIT_RECURSION;
- m_pcre_extra.match_limit_recursion= 100L;
}
int default_regex_flags();
- void set_recursion_limit(THD *);
void init(CHARSET_INFO *data_charset, int extra_flags)
{
m_library_flags= default_regex_flags() | extra_flags |
(data_charset != &my_charset_bin ?
- (PCRE_UTF8 | PCRE_UCP) : 0) |
+ (PCRE2_UTF | PCRE2_UCP) : 0) |
((data_charset->state &
- (MY_CS_BINSORT | MY_CS_CSSORT)) ? 0 : PCRE_CASELESS);
+ (MY_CS_BINSORT | MY_CS_CSSORT)) ? 0 : PCRE2_CASELESS);
// Convert text data to utf-8.
m_library_charset= data_charset == &my_charset_bin ?
@@ -2800,11 +2799,13 @@ class Regexp_processor_pcre
void reset()
{
m_pcre= NULL;
+ m_pcre_match_data= NULL;
m_prev_pattern.length(0);
}
void cleanup()
{
- pcre_free(m_pcre);
+ pcre2_match_data_free(m_pcre_match_data);
+ pcre2_code_free(m_pcre);
reset();
}
bool is_compiled() const { return m_pcre != NULL; }
@@ -2829,7 +2830,6 @@ class Item_func_regex :public Item_bool_func
DBUG_VOID_RETURN;
}
longlong val_int();
- bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec();
const char *func_name() const { return "regexp"; }
enum precedence precedence() const { return CMP_PRECEDENCE; }
@@ -2879,7 +2879,6 @@ class Item_func_regexp_instr :public Item_long_func
DBUG_VOID_RETURN;
}
longlong val_int();
- bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec();
const char *func_name() const { return "regexp_instr"; }
Item *get_copy(THD *thd)
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index c6b0ae7..0a1480e 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1276,13 +1276,6 @@ void Item_func_replace::fix_length_and_dec()
/*********************************************************************/
-bool Item_func_regexp_replace::fix_fields(THD *thd, Item **ref)
-{
- re.set_recursion_limit(thd);
- return Item_str_func::fix_fields(thd, ref);
-}
-
-
void Item_func_regexp_replace::fix_length_and_dec()
{
if (agg_arg_charsets_for_string_result_with_comparison(collation, args, 3))
@@ -1418,13 +1411,6 @@ String *Item_func_regexp_replace::val_str(String *str)
}
-bool Item_func_regexp_substr::fix_fields(THD *thd, Item **ref)
-{
- re.set_recursion_limit(thd);
- return Item_str_func::fix_fields(thd, ref);
-}
-
-
void Item_func_regexp_substr::fix_length_and_dec()
{
if (agg_arg_charsets_for_string_result_with_comparison(collation, args, 2))
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 4e1514c..3606151 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -376,7 +376,6 @@ class Item_func_regexp_replace :public Item_str_func
DBUG_VOID_RETURN;
}
String *val_str(String *str);
- bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec();
const char *func_name() const { return "regexp_replace"; }
Item *get_copy(THD *thd) { return 0;}
@@ -398,7 +397,6 @@ class Item_func_regexp_substr :public Item_str_func
DBUG_VOID_RETURN;
}
String *val_str(String *str);
- bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec();
const char *func_name() const { return "regexp_substr"; }
Item *get_copy(THD *thd) { return 0; }
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index fe2b9c8..b735123 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -111,7 +111,6 @@
#include "sp_rcontext.h"
#include "sp_cache.h"
#include "sql_reload.h" // reload_acl_and_cache
-#include "pcre.h"
#ifdef HAVE_POLL_H
#include <poll.h>
@@ -3758,21 +3757,6 @@ static void init_libstrings()
#endif
}
-ulonglong my_pcre_frame_size;
-
-static void init_pcre()
-{
- pcre_malloc= pcre_stack_malloc= my_str_malloc_mysqld;
- pcre_free= pcre_stack_free= my_free;
- pcre_stack_guard= check_enough_stack_size_slow;
- /* See http://pcre.org/original/doc/html/pcrestack.html */
- my_pcre_frame_size= -pcre_exec(NULL, NULL, NULL, -999, -999, 0, NULL, 0);
- // pcre can underestimate its stack usage. Use a safe value, as in the manual
- set_if_bigger(my_pcre_frame_size, 500);
- my_pcre_frame_size += 16; // Again, safety margin, see the manual
-}
-
-
/**
Initialize one of the global date/time format variables.
@@ -4560,7 +4544,6 @@ static int init_common_variables()
if (item_create_init())
return 1;
item_init();
- init_pcre();
/*
Process a comma-separated character set list and choose
the first available character set. This is mostly for
diff --git a/sql/mysqld.h b/sql/mysqld.h
index 670e136..183757b 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -574,8 +574,6 @@ extern pthread_t signal_thread;
extern struct st_VioSSLFd * ssl_acceptor_fd;
#endif /* HAVE_OPENSSL */
-extern ulonglong my_pcre_frame_size;
-
/*
The following variables were under INNODB_COMPABILITY_HOOKS
*/
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 524ce97..f2c9205 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -5672,19 +5672,21 @@ static const char *default_regex_flags_names[]=
"DOTALL", // (?s) . matches anything including NL
"DUPNAMES", // (?J) Allow duplicate names for subpatterns
"EXTENDED", // (?x) Ignore white space and # comments
- "EXTRA", // (?X) extra features (e.g. error on unknown escape character)
+ "EXTENDED_MORE",//(?xx) Ignore white space and # comments inside cheracter
+ "EXTRA", // means nothing since PCRE2
"MULTILINE", // (?m) ^ and $ match newlines within data
"UNGREEDY", // (?U) Invert greediness of quantifiers
0
};
static const int default_regex_flags_to_pcre[]=
{
- PCRE_DOTALL,
- PCRE_DUPNAMES,
- PCRE_EXTENDED,
- PCRE_EXTRA,
- PCRE_MULTILINE,
- PCRE_UNGREEDY,
+ PCRE2_DOTALL,
+ PCRE2_DUPNAMES,
+ PCRE2_EXTENDED,
+ PCRE2_EXTENDED_MORE,
+ 0, /* EXTRA flag not available since PCRE2 */
+ PCRE2_MULTILINE,
+ PCRE2_UNGREEDY,
0
};
int default_regex_flags_pcre(const THD *thd)
diff --git a/storage/mroonga/CMakeLists.txt b/storage/mroonga/CMakeLists.txt
index 5d8e8c1..57d12a1 100644
--- a/storage/mroonga/CMakeLists.txt
+++ b/storage/mroonga/CMakeLists.txt
@@ -189,8 +189,8 @@ else()
set(MYSQL_VARIANT "MySQL")
endif()
-if(EXISTS "${MYSQL_SOURCE_DIR}/pcre")
- set(MYSQL_REGEX_INCLUDE_DIR "${MYSQL_SOURCE_DIR}/pcre")
+if(EXISTS "${MYSQL_SOURCE_DIR}/pcre2")
+ set(MYSQL_REGEX_INCLUDE_DIR "${MYSQL_SOURCE_DIR}/pcre2/src")
else()
set(MYSQL_REGEX_INCLUDE_DIR "${MYSQL_SOURCE_DIR}/regex")
endif()
1
0
[Commits] bf34851c549: MDEV-15079: Parameter array operation inserts wrong values in autoincrement field if indicator was specified
by Oleksandr Byelkin 23 Apr '18
by Oleksandr Byelkin 23 Apr '18
23 Apr '18
revision-id: bf34851c549859551549baee2e3e93abef3c39fb (mariadb-10.3.6-36-gbf34851c549)
parent(s): c6ba758d1d41c11466b8f9b61b4546efc95aa689
author: Oleksandr Byelkin
committer: Oleksandr Byelkin
timestamp: 2018-04-23 12:09:10 +0200
message:
MDEV-15079: Parameter array operation inserts wrong values in autoincrement field if indicator was specified
test added (bug is fixed)
---
tests/mysql_client_test.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c
index 5a275c8fcbf..3188ea882bb 100644
--- a/tests/mysql_client_test.c
+++ b/tests/mysql_client_test.c
@@ -20227,6 +20227,59 @@ static void test_proxy_header_ignore()
}
+static void test_bulk_autoinc()
+{
+ int rc;
+ MYSQL_STMT *stmt;
+ MYSQL_BIND bind[1];
+ MYSQL_ROW row;
+ char indicator[]= {0, STMT_INDICATOR_NULL, 0/*STMT_INDICATOR_IGNORE*/};
+ my_bool error[1];
+ int i, id[]= {2, 3, 777}, count= sizeof(id)/sizeof(id[0]);
+ MYSQL_RES *result;
+
+ rc= mysql_query(mysql, "DROP TABLE IF EXISTS ai_field_value");
+ myquery(rc);
+ rc= mysql_query(mysql, "CREATE TABLE ai_field_value (id int not null primary key auto_increment)");
+ myquery(rc);
+ stmt= mysql_stmt_init(mysql);
+ rc= mysql_stmt_prepare(stmt, "INSERT INTO ai_field_value(id) values(?)", -1);
+ check_execute(stmt, rc);
+
+ memset(bind, 0, sizeof(bind));
+ bind[0].buffer_type = MYSQL_TYPE_LONG;
+ bind[0].buffer = (void *)id;
+ bind[0].buffer_length = 0;
+ bind[0].is_null = NULL;
+ bind[0].length = NULL;
+ bind[0].error = error;
+ bind[0].u.indicator= indicator;
+
+ mysql_stmt_attr_set(stmt, STMT_ATTR_ARRAY_SIZE, (void*)&count);
+ rc= mysql_stmt_bind_param(stmt, bind);
+ check_execute(stmt, rc);
+
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+
+ mysql_stmt_close(stmt);
+
+ rc= mysql_query(mysql, "SELECT id FROM ai_field_value");
+ myquery(rc);
+
+ result= mysql_store_result(mysql);
+ mytest(result);
+
+ i= 0;
+ while ((row= mysql_fetch_row(result)))
+ {
+ DIE_IF(atoi(row[0]) != id[i++]);
+ }
+ rc= mysql_query(mysql, "DROP TABLE ai_field_value");
+ myquery(rc);
+}
+
+
static void test_proxy_header()
{
test_proxy_header_tcp("192.0.2.1",3333);
@@ -20524,6 +20577,7 @@ static struct my_tests_st my_tests[]= {
#ifndef EMBEDDED_LIBRARY
{ "test_proxy_header", test_proxy_header},
#endif
+ { "test_bulk_autoinc", test_bulk_autoinc},
{ 0, 0 }
};
1
0
[Commits] a20e1ce85ec: MDEV-13232: Assertion `(&(&share->intern_lock)->m_mutex)->count > 0 && pthread_equal(pthread_self(), (&(&share->intern_lock)->m_mutex)->thread)' failed in _ma_state_info_write
by Oleksandr Byelkin 23 Apr '18
by Oleksandr Byelkin 23 Apr '18
23 Apr '18
revision-id: a20e1ce85ec56616fa048e9ba39c25c65b098fce (mariadb-10.3.6-36-ga20e1ce85ec)
parent(s): c6ba758d1d41c11466b8f9b61b4546efc95aa689
author: Oleksandr Byelkin
committer: Oleksandr Byelkin
timestamp: 2018-04-23 10:35:33 +0200
message:
MDEV-13232: Assertion `(&(&share->intern_lock)->m_mutex)->count > 0 && pthread_equal(pthread_self(), (&(&share->intern_lock)->m_mutex)->thread)' failed in _ma_state_info_write
Limit length of result of "negative" operation to something reasonable
---
mysql-test/main/union.result | 14 ++++++++++++++
mysql-test/main/union.test | 15 +++++++++++++++
sql/item_func.cc | 3 +++
3 files changed, 32 insertions(+)
diff --git a/mysql-test/main/union.result b/mysql-test/main/union.result
index 4e5f9312e03..39cd68ae851 100644
--- a/mysql-test/main/union.result
+++ b/mysql-test/main/union.result
@@ -2500,5 +2500,19 @@ t2 CREATE TABLE `t2` (
DROP TABLE t2;
DROP TABLE t1;
#
+# MDEV-13232: Assertion `(&(&share->intern_lock)->m_mutex)->count > 0 &&
+# pthread_equal(pthread_self(), (&(&share->intern_lock)->m_mutex)->
+# thread)' failed in _ma_state_info_write
+#
+CREATE TABLE t1 (c1 CHAR(8));
+INSERT INTO t1 VALUES ('10'),('-10');
+CREATE TABLE t2 (c2 CHAR);
+SET @a= CAST('10' AS CHAR);
+SELECT c1 FROM t1 UNION SELECT - @a FROM t2;
+c1
+10
+-10
+drop table t1,t2;
+#
# End of 10.3 tests
#
diff --git a/mysql-test/main/union.test b/mysql-test/main/union.test
index f86cae87524..b9b38271f83 100644
--- a/mysql-test/main/union.test
+++ b/mysql-test/main/union.test
@@ -1745,6 +1745,21 @@ SHOW CREATE TABLE t2;
DROP TABLE t2;
DROP TABLE t1;
+--echo #
+--echo # MDEV-13232: Assertion `(&(&share->intern_lock)->m_mutex)->count > 0 &&
+--echo # pthread_equal(pthread_self(), (&(&share->intern_lock)->m_mutex)->
+--echo # thread)' failed in _ma_state_info_write
+--echo #
+
+CREATE TABLE t1 (c1 CHAR(8));
+INSERT INTO t1 VALUES ('10'),('-10');
+
+CREATE TABLE t2 (c2 CHAR);
+SET @a= CAST('10' AS CHAR);
+
+SELECT c1 FROM t1 UNION SELECT - @a FROM t2;
+
+drop table t1,t2;
--echo #
--echo # End of 10.3 tests
diff --git a/sql/item_func.cc b/sql/item_func.cc
index e2740272385..ae6c61e83f4 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -1935,6 +1935,9 @@ void Item_func_neg::fix_length_and_dec_double()
set_handler(&type_handler_double);
decimals= args[0]->decimals; // Preserve NOT_FIXED_DEC
max_length= args[0]->max_length + 1;
+ // Limit length with something reasonable
+ uint32 mlen= type_handler()->max_display_length(this);
+ set_if_smaller(max_length, mlen);
unsigned_flag= false;
}
2
1
[Commits] a20e1ce85ec: MDEV-13232: Assertion `(&(&share->intern_lock)->m_mutex)->count > 0 && pthread_equal(pthread_self(), (&(&share->intern_lock)->m_mutex)->thread)' failed in _ma_state_info_write
by Oleksandr Byelkin 23 Apr '18
by Oleksandr Byelkin 23 Apr '18
23 Apr '18
revision-id: a20e1ce85ec56616fa048e9ba39c25c65b098fce (mariadb-10.3.6-36-ga20e1ce85ec)
parent(s): c6ba758d1d41c11466b8f9b61b4546efc95aa689
author: Oleksandr Byelkin
committer: Oleksandr Byelkin
timestamp: 2018-04-23 10:35:33 +0200
message:
MDEV-13232: Assertion `(&(&share->intern_lock)->m_mutex)->count > 0 && pthread_equal(pthread_self(), (&(&share->intern_lock)->m_mutex)->thread)' failed in _ma_state_info_write
Limit length of result of "negative" operation to something reasonable
---
mysql-test/main/union.result | 14 ++++++++++++++
mysql-test/main/union.test | 15 +++++++++++++++
sql/item_func.cc | 3 +++
3 files changed, 32 insertions(+)
diff --git a/mysql-test/main/union.result b/mysql-test/main/union.result
index 4e5f9312e03..39cd68ae851 100644
--- a/mysql-test/main/union.result
+++ b/mysql-test/main/union.result
@@ -2500,5 +2500,19 @@ t2 CREATE TABLE `t2` (
DROP TABLE t2;
DROP TABLE t1;
#
+# MDEV-13232: Assertion `(&(&share->intern_lock)->m_mutex)->count > 0 &&
+# pthread_equal(pthread_self(), (&(&share->intern_lock)->m_mutex)->
+# thread)' failed in _ma_state_info_write
+#
+CREATE TABLE t1 (c1 CHAR(8));
+INSERT INTO t1 VALUES ('10'),('-10');
+CREATE TABLE t2 (c2 CHAR);
+SET @a= CAST('10' AS CHAR);
+SELECT c1 FROM t1 UNION SELECT - @a FROM t2;
+c1
+10
+-10
+drop table t1,t2;
+#
# End of 10.3 tests
#
diff --git a/mysql-test/main/union.test b/mysql-test/main/union.test
index f86cae87524..b9b38271f83 100644
--- a/mysql-test/main/union.test
+++ b/mysql-test/main/union.test
@@ -1745,6 +1745,21 @@ SHOW CREATE TABLE t2;
DROP TABLE t2;
DROP TABLE t1;
+--echo #
+--echo # MDEV-13232: Assertion `(&(&share->intern_lock)->m_mutex)->count > 0 &&
+--echo # pthread_equal(pthread_self(), (&(&share->intern_lock)->m_mutex)->
+--echo # thread)' failed in _ma_state_info_write
+--echo #
+
+CREATE TABLE t1 (c1 CHAR(8));
+INSERT INTO t1 VALUES ('10'),('-10');
+
+CREATE TABLE t2 (c2 CHAR);
+SET @a= CAST('10' AS CHAR);
+
+SELECT c1 FROM t1 UNION SELECT - @a FROM t2;
+
+drop table t1,t2;
--echo #
--echo # End of 10.3 tests
diff --git a/sql/item_func.cc b/sql/item_func.cc
index e2740272385..ae6c61e83f4 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -1935,6 +1935,9 @@ void Item_func_neg::fix_length_and_dec_double()
set_handler(&type_handler_double);
decimals= args[0]->decimals; // Preserve NOT_FIXED_DEC
max_length= args[0]->max_length + 1;
+ // Limit length with something reasonable
+ uint32 mlen= type_handler()->max_display_length(this);
+ set_if_smaller(max_length, mlen);
unsigned_flag= false;
}
1
0
22 Apr '18
revision-id: ce222a71bf75b2125cc588371a3debb3e4a22d7f (mariadb-10.3.6-34-gce222a7)
parent(s): 9f84451d87ba1924539b7d2ab69619b71d0155b9
committer: Alexey Botchkov
timestamp: 2018-04-22 16:01:18 +0400
message:
MDEV-15915 Add Feature_json status variable.
---
mysql-test/main/status.test | 7 +++++++
sql/item_create.cc | 26 ++++++++++++++++++++++++++
sql/mysqld.cc | 1 +
sql/sql_class.h | 1 +
4 files changed, 35 insertions(+)
diff --git a/mysql-test/main/status.test b/mysql-test/main/status.test
index 92fba9a..221a24a 100644
--- a/mysql-test/main/status.test
+++ b/mysql-test/main/status.test
@@ -430,6 +430,13 @@ FLUSH STATUS;
SHOW STATUS LIKE 'Threads_running';
SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME='THREADS_RUNNING';
+--echo #
+--echo # MDEV-15915 Add Feature_json status variable.
+--echo #
+SHOW STATUS LIKE 'Feature_json';
+select json_valid('123');
+SHOW STATUS LIKE 'Feature_json';
+
# Restore global concurrent_insert value. Keep in the end of the test file.
--connection default
set @@global.concurrent_insert= @old_concurrent_insert;
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 901dfa0..8b8476b 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -5118,6 +5118,7 @@ Create_func_json_exists Create_func_json_exists::s_singleton;
Item*
Create_func_json_exists::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
+ status_var_increment(current_thd->status_var.feature_json);
return new (thd->mem_root) Item_func_json_exists(thd, arg1, arg2);
}
@@ -5143,6 +5144,7 @@ Create_func_json_detailed::create_native(THD *thd, LEX_CSTRING *name,
func= new (thd->mem_root) Item_func_json_format(thd, *item_list);
}
+ status_var_increment(current_thd->status_var.feature_json);
return func;
}
@@ -5152,6 +5154,7 @@ Create_func_json_loose Create_func_json_loose::s_singleton;
Item*
Create_func_json_loose::create_1_arg(THD *thd, Item *arg1)
{
+ status_var_increment(current_thd->status_var.feature_json);
return new (thd->mem_root) Item_func_json_format(thd, arg1,
Item_func_json_format::LOOSE);
}
@@ -5162,6 +5165,7 @@ Create_func_json_compact Create_func_json_compact::s_singleton;
Item*
Create_func_json_compact::create_1_arg(THD *thd, Item *arg1)
{
+ status_var_increment(current_thd->status_var.feature_json);
return new (thd->mem_root) Item_func_json_format(thd, arg1,
Item_func_json_format::COMPACT);
}
@@ -5172,6 +5176,7 @@ Create_func_json_valid Create_func_json_valid::s_singleton;
Item*
Create_func_json_valid::create_1_arg(THD *thd, Item *arg1)
{
+ status_var_increment(current_thd->status_var.feature_json);
return new (thd->mem_root) Item_func_json_valid(thd, arg1);
}
@@ -5181,6 +5186,7 @@ Create_func_json_type Create_func_json_type::s_singleton;
Item*
Create_func_json_type::create_1_arg(THD *thd, Item *arg1)
{
+ status_var_increment(current_thd->status_var.feature_json);
return new (thd->mem_root) Item_func_json_type(thd, arg1);
}
@@ -5190,6 +5196,7 @@ Create_func_json_depth Create_func_json_depth::s_singleton;
Item*
Create_func_json_depth::create_1_arg(THD *thd, Item *arg1)
{
+ status_var_increment(current_thd->status_var.feature_json);
return new (thd->mem_root) Item_func_json_depth(thd, arg1);
}
@@ -5199,6 +5206,7 @@ Create_func_json_value Create_func_json_value::s_singleton;
Item*
Create_func_json_value::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
+ status_var_increment(current_thd->status_var.feature_json);
return new (thd->mem_root) Item_func_json_value(thd, arg1, arg2);
}
@@ -5208,6 +5216,7 @@ Create_func_json_query Create_func_json_query::s_singleton;
Item*
Create_func_json_query::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
+ status_var_increment(current_thd->status_var.feature_json);
return new (thd->mem_root) Item_func_json_query(thd, arg1, arg2);
}
@@ -5217,6 +5226,7 @@ Create_func_json_quote Create_func_json_quote::s_singleton;
Item*
Create_func_json_quote::create_1_arg(THD *thd, Item *arg1)
{
+ status_var_increment(current_thd->status_var.feature_json);
return new (thd->mem_root) Item_func_json_quote(thd, arg1);
}
@@ -5226,6 +5236,7 @@ Create_func_json_unquote Create_func_json_unquote::s_singleton;
Item*
Create_func_json_unquote::create_1_arg(THD *thd, Item *arg1)
{
+ status_var_increment(current_thd->status_var.feature_json);
return new (thd->mem_root) Item_func_json_unquote(thd, arg1);
}
@@ -5256,6 +5267,7 @@ Create_func_json_array::create_native(THD *thd, LEX_CSTRING *name,
func= new (thd->mem_root) Item_func_json_array(thd);
}
+ status_var_increment(current_thd->status_var.feature_json);
return func;
}
@@ -5281,6 +5293,7 @@ Create_func_json_array_append::create_native(THD *thd, LEX_CSTRING *name,
func= new (thd->mem_root) Item_func_json_array_append(thd, *item_list);
}
+ status_var_increment(current_thd->status_var.feature_json);
return func;
}
@@ -5306,6 +5319,7 @@ Create_func_json_array_insert::create_native(THD *thd, LEX_CSTRING *name,
func= new (thd->mem_root) Item_func_json_array_insert(thd, *item_list);
}
+ status_var_increment(current_thd->status_var.feature_json);
return func;
}
@@ -5332,6 +5346,7 @@ Create_func_json_insert::create_native(THD *thd, LEX_CSTRING *name,
thd, *item_list);
}
+ status_var_increment(current_thd->status_var.feature_json);
return func;
}
@@ -5358,6 +5373,7 @@ Create_func_json_set::create_native(THD *thd, LEX_CSTRING *name,
thd, *item_list);
}
+ status_var_increment(current_thd->status_var.feature_json);
return func;
}
@@ -5384,6 +5400,7 @@ Create_func_json_replace::create_native(THD *thd, LEX_CSTRING *name,
thd, *item_list);
}
+ status_var_increment(current_thd->status_var.feature_json);
return func;
}
@@ -5409,6 +5426,7 @@ Create_func_json_remove::create_native(THD *thd, LEX_CSTRING *name,
func= new (thd->mem_root) Item_func_json_remove(thd, *item_list);
}
+ status_var_increment(current_thd->status_var.feature_json);
return func;
}
@@ -5441,6 +5459,7 @@ Create_func_json_object::create_native(THD *thd, LEX_CSTRING *name,
func= new (thd->mem_root) Item_func_json_object(thd);
}
+ status_var_increment(current_thd->status_var.feature_json);
return func;
}
@@ -5465,6 +5484,7 @@ Create_func_json_length::create_native(THD *thd, LEX_CSTRING *name,
func= new (thd->mem_root) Item_func_json_length(thd, *item_list);
}
+ status_var_increment(current_thd->status_var.feature_json);
return func;
}
@@ -5489,6 +5509,7 @@ Create_func_json_merge::create_native(THD *thd, LEX_CSTRING *name,
func= new (thd->mem_root) Item_func_json_merge(thd, *item_list);
}
+ status_var_increment(current_thd->status_var.feature_json);
return func;
}
@@ -5514,6 +5535,7 @@ Create_func_json_contains::create_native(THD *thd, LEX_CSTRING *name,
my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
}
+ status_var_increment(current_thd->status_var.feature_json);
return func;
}
@@ -5539,6 +5561,7 @@ Create_func_json_keys::create_native(THD *thd, LEX_CSTRING *name,
func= new (thd->mem_root) Item_func_json_keys(thd, *item_list);
}
+ status_var_increment(current_thd->status_var.feature_json);
return func;
}
@@ -5564,6 +5587,7 @@ Create_func_json_contains_path::create_native(THD *thd, LEX_CSTRING *name,
func= new (thd->mem_root) Item_func_json_contains_path(thd, *item_list);
}
+ status_var_increment(current_thd->status_var.feature_json);
return func;
}
@@ -5589,6 +5613,7 @@ Create_func_json_extract::create_native(THD *thd, LEX_CSTRING *name,
func= new (thd->mem_root) Item_func_json_extract(thd, *item_list);
}
+ status_var_increment(current_thd->status_var.feature_json);
return func;
}
@@ -5614,6 +5639,7 @@ Create_func_json_search::create_native(THD *thd, LEX_CSTRING *name,
func= new (thd->mem_root) Item_func_json_search(thd, *item_list);
}
+ status_var_increment(current_thd->status_var.feature_json);
return func;
}
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 6e1a599..ae14c80 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -8553,6 +8553,7 @@ SHOW_VAR status_vars[]= {
{"Feature_fulltext", (char*) offsetof(STATUS_VAR, feature_fulltext), SHOW_LONG_STATUS},
{"Feature_gis", (char*) offsetof(STATUS_VAR, feature_gis), SHOW_LONG_STATUS},
{"Feature_invisible_columns", (char*) offsetof(STATUS_VAR, feature_invisible_columns), SHOW_LONG_STATUS},
+ {"Feature_json", (char*) offsetof(STATUS_VAR, feature_json), SHOW_LONG_STATUS},
{"Feature_locale", (char*) offsetof(STATUS_VAR, feature_locale), SHOW_LONG_STATUS},
{"Feature_subquery", (char*) offsetof(STATUS_VAR, feature_subquery), SHOW_LONG_STATUS},
{"Feature_timezone", (char*) offsetof(STATUS_VAR, feature_timezone), SHOW_LONG_STATUS},
diff --git a/sql/sql_class.h b/sql/sql_class.h
index a7c33cb..56d63f3 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -820,6 +820,7 @@ typedef struct system_status_var
ulong feature_fulltext; /* +1 when MATCH is used */
ulong feature_gis; /* +1 opening a table with GIS features */
ulong feature_invisible_columns; /* +1 opening a table with invisible column */
+ ulong feature_json; /* +1 when JSON function appears in the statement */
ulong feature_locale; /* +1 when LOCALE is set */
ulong feature_subquery; /* +1 when subqueries are used */
ulong feature_timezone; /* +1 when XPATH is used */
1
0
22 Apr '18
revision-id: 65169418c5128fb8398ac356d93262ae9549a98c (mariadb-10.3.6-29-g6516941)
parent(s): c058117c6c857ecb41960bd705104adc42348645
author: Igor Babaev
committer: Igor Babaev
timestamp: 2018-04-21 17:20:20 -0700
message:
MDEV-15940 Crash when using CURSOR with VALUES()
The function st_select_lex_unit::get_column_types() should
take into account that a unit may contain only a table
value constructor and nothing more.
---
mysql-test/main/table_value_constr.result | 21 +++++++++++++++++++++
mysql-test/main/table_value_constr.test | 24 ++++++++++++++++++++++++
sql/sql_union.cc | 2 +-
3 files changed, 46 insertions(+), 1 deletion(-)
diff --git a/mysql-test/main/table_value_constr.result b/mysql-test/main/table_value_constr.result
index 39caba3..5a904cb 100644
--- a/mysql-test/main/table_value_constr.result
+++ b/mysql-test/main/table_value_constr.result
@@ -2071,3 +2071,24 @@ ERROR HY000: Field reference 'b' can't be used in table value constructor
select * from (values (1), (t1.b), (2)) as new_tvc;
ERROR HY000: Field reference 't1.b' can't be used in table value constructor
drop table t1;
+#
+# MDEV-MDEV-15940: cursor over TVC
+#
+BEGIN NOT ATOMIC
+DECLARE v INT;
+DECLARE cur CURSOR FOR VALUES(7);
+OPEN cur;
+FETCH cur INTO v;
+SELECT v;
+END;
+|
+v
+7
+BEGIN NOT ATOMIC
+DECLARE v INT DEFAULT 0;
+FOR a IN (VALUES (7)) DO SET v = v + 1; END FOR;
+SELECT v;
+END;
+|
+v
+1
diff --git a/mysql-test/main/table_value_constr.test b/mysql-test/main/table_value_constr.test
index 578f894..84f196b 100644
--- a/mysql-test/main/table_value_constr.test
+++ b/mysql-test/main/table_value_constr.test
@@ -1044,3 +1044,27 @@ select * from (values (1), (b), (2)) as new_tvc;
select * from (values (1), (t1.b), (2)) as new_tvc;
drop table t1;
+
+--echo #
+--echo # MDEV-MDEV-15940: cursor over TVC
+--echo #
+
+DELIMITER |;
+
+BEGIN NOT ATOMIC
+ DECLARE v INT;
+ DECLARE cur CURSOR FOR VALUES(7);
+ OPEN cur;
+ FETCH cur INTO v;
+ SELECT v;
+END;
+|
+
+BEGIN NOT ATOMIC
+DECLARE v INT DEFAULT 0;
+FOR a IN (VALUES (7)) DO SET v = v + 1; END FOR;
+SELECT v;
+END;
+|
+
+DELIMITER ;|
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 4cc7de8..432ad85 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -1874,7 +1874,7 @@ bool st_select_lex_unit::change_result(select_result_interceptor *new_result,
List<Item> *st_select_lex_unit::get_column_types(bool for_cursor)
{
SELECT_LEX *sl= first_select();
- bool is_procedure= MY_TEST(sl->join->procedure);
+ bool is_procedure= !sl->tvc && sl->join->procedure ;
if (is_procedure)
{
1
0