Commit 06a4193c authored by Anel Husakovic's avatar Anel Husakovic

MDEV-28391: table_exists procedure fails when arguments contain escaped...

MDEV-28391: table_exists procedure fails when arguments contain escaped backticks as an quoted identifiers

- When arguments to the procedure contain quote in the name, procedure fails with parsing error.
  The reason was because additional quoting is done when testing TEMPORARY table with the same name.
- Reviewed by: <wlad@mariadb.com>
parent bc113b87
...@@ -42,3 +42,31 @@ ERROR 22001: Data too long for column 'in_db' at row 1 ...@@ -42,3 +42,31 @@ ERROR 22001: Data too long for column 'in_db' at row 1
CALL sys.table_exists('test', @identifier, @exists); CALL sys.table_exists('test', @identifier, @exists);
ERROR 22001: Data too long for column 'in_table' at row 1 ERROR 22001: Data too long for column 'in_table' at row 1
SET @identifier := NULL; 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`;
...@@ -46,3 +46,24 @@ CALL sys.table_exists(@identifier, 't1', @exists); ...@@ -46,3 +46,24 @@ CALL sys.table_exists(@identifier, 't1', @exists);
CALL sys.table_exists('test', @identifier, @exists); CALL sys.table_exists('test', @identifier, @exists);
SET @identifier := NULL; 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
...@@ -133,6 +133,8 @@ CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE table_exists ( ...@@ -133,6 +133,8 @@ CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE table_exists (
CONTAINS SQL CONTAINS SQL
BEGIN BEGIN
DECLARE v_error BOOLEAN DEFAULT FALSE; 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_table_type VARCHAR(16) DEFAULT '';
DECLARE v_system_db BOOLEAN DECLARE v_system_db BOOLEAN
DEFAULT LOWER(in_db) IN ('information_schema', 'performance_schema'); DEFAULT LOWER(in_db) IN ('information_schema', 'performance_schema');
...@@ -140,19 +142,28 @@ BEGIN ...@@ -140,19 +142,28 @@ BEGIN
DECLARE CONTINUE HANDLER FOR 1146 SET v_error = TRUE; DECLARE CONTINUE HANDLER FOR 1146 SET v_error = TRUE;
SET out_exists = ''; 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 -- 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 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 -- 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. -- 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 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; PREPARE stmt_create_table FROM @sys.tmp.table_exists.SQL;
EXECUTE stmt_create_table; EXECUTE stmt_create_table;
DEALLOCATE PREPARE 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. -- 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; PREPARE stmt_drop_table FROM @sys.tmp.table_exists.SQL;
EXECUTE stmt_drop_table; EXECUTE stmt_drop_table;
DEALLOCATE PREPARE stmt_drop_table; DEALLOCATE PREPARE stmt_drop_table;
...@@ -174,7 +185,10 @@ BEGIN ...@@ -174,7 +185,10 @@ BEGIN
-- If it does it's possible to SELECT from the table without causing an error. -- 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 it does not exist even a PREPARE using the table will fail.
IF v_system_db = FALSE THEN 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; PREPARE stmt_select FROM @sys.tmp.table_exists.SQL;
IF (NOT v_error) THEN IF (NOT v_error) THEN
DEALLOCATE PREPARE stmt_select; DEALLOCATE PREPARE stmt_select;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment