MDEV-29155 CREATE OR REPLACE with self-referencing CHECK hangs

forever, cannot be killed

mysql_rm_table_no_locks() does TDC_RT_REMOVE_ALL which waits while
share is closed. The table normally is open only as OPEN_STUB, this is
what parser does for CREATE TABLE. But for SELECT the table is opened
not as a stub. If it is the same table name we anyway have two
TABLE_LIST objects: stub and not stub. So for "not stub"
TDC_RT_REMOVE_ALL sees open count and decides to wait until it is
closed. And it hangs because that was opened in the same thread.

The fix disables subqueries in CHECK expression at parser
level. Thanks to Sergei Golubchik <serg@mariadb.org> for the patch.
This commit is contained in:
Aleksey Midenkov
2025-05-28 11:28:17 +03:00
parent 0b2434d2e9
commit fe6a5c2200
5 changed files with 71 additions and 4 deletions

View File

@ -139,7 +139,7 @@ drop table t1;
create or replace table t1( c1 int auto_increment primary key, check( c1 > 0 or c1 is null ) );
ERROR HY000: Function or expression 'AUTO_INCREMENT' cannot be used in the CHECK clause of `c1`
create table t1 (a int check (@b in (select user from mysql.user)));
ERROR HY000: Function or expression 'select ...' cannot be used in the CHECK clause of `a`
ERROR 42000: CHECK does not support subqueries or stored functions
create table t1 (a int check (a > @b));
ERROR HY000: Function or expression '@b' cannot be used in the CHECK clause of `a`
create table t1 (a int check (a = 1));

View File

@ -87,7 +87,7 @@ create or replace table t1( c1 int auto_increment primary key, check( c1 > 0 or
#
# MDEV-12421 Check constraint with query crashes server and renders DB unusable
#
--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED
--error ER_SUBQUERIES_NOT_SUPPORTED
create table t1 (a int check (@b in (select user from mysql.user)));
--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED
create table t1 (a int check (a > @b));

View File

@ -55,3 +55,34 @@ ERROR HY000: Function or expression 'b' cannot be used in the GENERATED ALWAYS A
#
# End of 10.3 tests
#
#
# MDEV-29155 CREATE OR REPLACE with self-referencing CHECK hangs forever, cannot be killed
#
create table t1 (a int);
create table t2 (b int)
# create or replace table t (b int);
create table t3 (c int, check(exists(select a from t1) or exists(select b from t2)));
ERROR 42000: CHECK does not support subqueries or stored functions
create table t3 (c int, check(exists(select c from t3)));
ERROR 42000: CHECK does not support subqueries or stored functions
create table t3 (d int);
create or replace table t3 (c int, check(exists(select a from t1) or exists(select b from t2)));
ERROR 42000: CHECK does not support subqueries or stored functions
drop table t3;
create table t3 (d int);
create or replace table t3 (c int, check(exists(select c from t3)));
ERROR 42000: CHECK does not support subqueries or stored functions
drop table t3;
create table t3 (c int);
alter table t3 add check(exists(select a from t1) or exists(select b from t2));
ERROR 42000: CHECK does not support subqueries or stored functions
alter table t3 add check(exists(select c from t3));
ERROR 42000: CHECK does not support subqueries or stored functions
create table t3 (c int default (select a from t1));
ERROR HY000: Function or expression 'select ...' cannot be used in the DEFAULT clause of `c`
create table t3 (c int, d int generated always as (select a from t1 limit 1));
ERROR HY000: Function or expression 'select ...' cannot be used in the GENERATED ALWAYS AS clause of `d`
drop tables t1, t2, t3;
#
# End of 10.4 tests
#

View File

@ -64,3 +64,36 @@ create table t1 (a int auto_increment primary key,
--echo #
--echo # End of 10.3 tests
--echo #
--echo #
--echo # MDEV-29155 CREATE OR REPLACE with self-referencing CHECK hangs forever, cannot be killed
--echo #
create table t1 (a int);
create table t2 (b int)
# create or replace table t (b int);
--error ER_SUBQUERIES_NOT_SUPPORTED
create table t3 (c int, check(exists(select a from t1) or exists(select b from t2)));
--error ER_SUBQUERIES_NOT_SUPPORTED
create table t3 (c int, check(exists(select c from t3)));
create table t3 (d int);
--error ER_SUBQUERIES_NOT_SUPPORTED
create or replace table t3 (c int, check(exists(select a from t1) or exists(select b from t2)));
drop table t3;
create table t3 (d int);
--error ER_SUBQUERIES_NOT_SUPPORTED
create or replace table t3 (c int, check(exists(select c from t3)));
drop table t3;
create table t3 (c int);
--error ER_SUBQUERIES_NOT_SUPPORTED
alter table t3 add check(exists(select a from t1) or exists(select b from t2));
--error ER_SUBQUERIES_NOT_SUPPORTED
alter table t3 add check(exists(select c from t3));
--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED
create table t3 (c int default (select a from t1));
--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED
create table t3 (c int, d int generated always as (select a from t1 limit 1));
drop tables t1, t2, t3;
--echo #
--echo # End of 10.4 tests
--echo #

View File

@ -6126,9 +6126,12 @@ opt_check_constraint:
;
check_constraint:
CHECK_SYM '(' expr ')'
CHECK_SYM '('
{ Lex->clause_that_disallows_subselect= "CHECK"; }
expr ')'
{
Virtual_column_info *v= add_virtual_expression(thd, $3);
Virtual_column_info *v= add_virtual_expression(thd, $4);
Lex->clause_that_disallows_subselect= NULL;
if (unlikely(!v))
MYSQL_YYABORT;
$$= v;