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
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`;
......@@ -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
......@@ -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;
......
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