diff --git a/mysql-test/suite/sysschema/r/pr_table_exists.result b/mysql-test/suite/sysschema/r/pr_table_exists.result index 65d7c20c61d..88917418f67 100644 --- a/mysql-test/suite/sysschema/r/pr_table_exists.result +++ b/mysql-test/suite/sysschema/r/pr_table_exists.result @@ -42,3 +42,31 @@ ERROR 22001: Data too long for column 'in_db' at row 1 CALL sys.table_exists('test', @identifier, @exists); ERROR 22001: Data too long for column 'in_table' at row 1 SET @identifier := NULL; +# +# MDEV-28391: table_exists procedure fails with +# Incorrect table name with backtick identifiers +# +CREATE TABLE `ab``c` (t1_id int PRIMARY KEY, t1_val varchar(10)); +CALL sys.table_exists('test', 'ab`c', @tbl_type); +SELECT @tbl_type; +@tbl_type +BASE TABLE +DROP TABLE `ab``c`; +CREATE TEMPORARY TABLE `ab``c` (t1_id int PRIMARY KEY, t1_val varchar(10)); +CALL sys.table_exists('test', 'ab`c', @tbl_type); +SELECT @tbl_type; +@tbl_type +TEMPORARY +DROP TABLE `ab``c`; +CREATE TABLE `ab``c` (t1_id int PRIMARY KEY, t1_val varchar(10)); +CREATE TEMPORARY TABLE `ab``c` (t1_id int PRIMARY KEY, t1_val varchar(10)); +CALL sys.table_exists('test', 'ab`c', @tbl_type); +SELECT @tbl_type; +@tbl_type +TEMPORARY +# We cannot send quoted identifer to the procedure, no table will be found +CALL sys.table_exists('test', '`ab``c`', @tbl_type); +SELECT @tbl_type; +@tbl_type + +DROP TABLE `ab``c`; diff --git a/mysql-test/suite/sysschema/t/pr_table_exists.test b/mysql-test/suite/sysschema/t/pr_table_exists.test index d0c538843b1..83e1dc0b9d9 100644 --- a/mysql-test/suite/sysschema/t/pr_table_exists.test +++ b/mysql-test/suite/sysschema/t/pr_table_exists.test @@ -46,3 +46,24 @@ CALL sys.table_exists(@identifier, 't1', @exists); CALL sys.table_exists('test', @identifier, @exists); SET @identifier := NULL; + +--echo # +--echo # MDEV-28391: table_exists procedure fails with +--echo # Incorrect table name with backtick identifiers +--echo # +CREATE TABLE `ab``c` (t1_id int PRIMARY KEY, t1_val varchar(10)); +CALL sys.table_exists('test', 'ab`c', @tbl_type); +SELECT @tbl_type; +DROP TABLE `ab``c`; +CREATE TEMPORARY TABLE `ab``c` (t1_id int PRIMARY KEY, t1_val varchar(10)); +CALL sys.table_exists('test', 'ab`c', @tbl_type); +SELECT @tbl_type; +DROP TABLE `ab``c`; +CREATE TABLE `ab``c` (t1_id int PRIMARY KEY, t1_val varchar(10)); +CREATE TEMPORARY TABLE `ab``c` (t1_id int PRIMARY KEY, t1_val varchar(10)); +CALL sys.table_exists('test', 'ab`c', @tbl_type); +SELECT @tbl_type; +--echo # We cannot send quoted identifer to the procedure, no table will be found +CALL sys.table_exists('test', '`ab``c`', @tbl_type); +SELECT @tbl_type; +DROP TABLE `ab``c`; \ No newline at end of file diff --git a/scripts/sys_schema/procedures/table_exists.sql b/scripts/sys_schema/procedures/table_exists.sql index 8a17e0e19f4..0f7640329e7 100644 --- a/scripts/sys_schema/procedures/table_exists.sql +++ b/scripts/sys_schema/procedures/table_exists.sql @@ -133,6 +133,8 @@ CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE table_exists ( CONTAINS SQL BEGIN DECLARE v_error BOOLEAN DEFAULT FALSE; + DECLARE db_quoted VARCHAR(64); + DECLARE table_quoted VARCHAR(64); DECLARE v_table_type VARCHAR(16) DEFAULT ''; DECLARE v_system_db BOOLEAN DEFAULT LOWER(in_db) IN ('information_schema', 'performance_schema'); @@ -140,19 +142,28 @@ BEGIN DECLARE CONTINUE HANDLER FOR 1146 SET v_error = TRUE; SET out_exists = ''; + SET db_quoted = sys.quote_identifier(in_db); + SET table_quoted = sys.quote_identifier(in_table); -- Verify whether the table name exists as a normal table IF (EXISTS(SELECT 1 FROM information_schema.TABLES WHERE TABLE_SCHEMA = in_db AND TABLE_NAME = in_table)) THEN -- Unfortunately the only way to determine whether there is also a temporary table is to try to create -- a temporary table with the same name. If it succeeds the table didn't exist as a temporary table. IF v_system_db = FALSE THEN - SET @sys.tmp.table_exists.SQL = CONCAT('CREATE TEMPORARY TABLE `', in_db, '`.`', in_table, '` (id INT PRIMARY KEY)'); + SET @sys.tmp.table_exists.SQL = CONCAT('CREATE TEMPORARY TABLE ', + db_quoted, + '.', + table_quoted, + '(id INT PRIMARY KEY)'); PREPARE stmt_create_table FROM @sys.tmp.table_exists.SQL; EXECUTE stmt_create_table; DEALLOCATE PREPARE stmt_create_table; -- The temporary table was created, i.e. it didn't exist. Remove it again so we don't leave garbage around. - SET @sys.tmp.table_exists.SQL = CONCAT('DROP TEMPORARY TABLE `', in_db, '`.`', in_table, '`'); + SET @sys.tmp.table_exists.SQL = CONCAT('DROP TEMPORARY TABLE ', + db_quoted, + '.', + table_quoted); PREPARE stmt_drop_table FROM @sys.tmp.table_exists.SQL; EXECUTE stmt_drop_table; DEALLOCATE PREPARE stmt_drop_table; @@ -174,7 +185,10 @@ BEGIN -- If it does it's possible to SELECT from the table without causing an error. -- If it does not exist even a PREPARE using the table will fail. IF v_system_db = FALSE THEN - SET @sys.tmp.table_exists.SQL = CONCAT('SELECT COUNT(*) FROM `', in_db, '`.`', in_table, '`'); + SET @sys.tmp.table_exists.SQL = CONCAT('SELECT COUNT(*) FROM ', + db_quoted, + '.', + table_quoted); PREPARE stmt_select FROM @sys.tmp.table_exists.SQL; IF (NOT v_error) THEN DEALLOCATE PREPARE stmt_select;