Как вставить данные в динамическую таблицу в MySQL? - PullRequest
0 голосов
/ 03 марта 2019

Я пытался использовать хранимую процедуру ниже для вставки данных в динамическую таблицу в MySQL, но я получаю сообщение об ошибке при вызове следующей команды:

CALL insert_data ('table_x', 'NULL', 'A', 'B', 'C', 'D', 'E ')

Ошибка

Column unknown' 0 'in the list of fields.

Процедура

DELIMITER $$
CREATE PROCEDURE insertar_datos (name VARCHAR(25), N INT, AP 
VARCHAR(15),
AM VARCHAR(15), Nom VARCHAR(30), DNI VARCHAR(8), Direc VARCHAR(30))
BEGIN
    SET @tableName = Name;
    SET @NName= N;
    SET @APName = AP;
    SET @AMName = AM;
    SET @NomName = Nom;
    SET @DNIName = DNI;
    SET @DirecName = Direc;
    SET @q = CONCAT('
        INSERT INTO `' , @tableName, '` VALUES(
            `',@NName,'`,
            `',@APName,'`,
            `',@AMName,'`,
            `',@NomName,'`,
            `',@DNIName,'`,
            `',@DirecName,'`
        )
    ');
    PREPARE stmt FROM @q;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
END $$
DELIMITER;    

1 Ответ

0 голосов
/ 03 марта 2019

Если вы обнаружите, что у вас несколько таблиц с одинаковыми столбцами, у вас, вероятно, плохая схема.То, что вы спрашиваете, не обязательно с хорошо разработанной схемой.Я рекомендую вам задать еще один вопрос о том, как спроектировать схему, чтобы полностью избежать вашей проблемы.


Объединение нефильтрованных строк вместе уязвимо для атаки SQL-инъекцией .Вместо этого, когда это возможно, используйте параметры связывания и передайте значения. Это гарантирует, что они правильно экранированы и заключены в кавычки и не будут неверно истолкованы ни случайно, ни злонамеренно.

SET @q = 'INSERT INTO `' , @tableName, '` VALUES(?,?,?,?,?,?)';
PREPARE stmt FROM @q;
EXECUTE stmt USING @NName, @APName, @AMName, @NomName, @DNIName, @DirectName

Это также решает другие ваши проблемы,не все является строкой.

CALL insert_data ('table_x', 'NULL', 'A', 'B', 'C', 'D', 'E ')
                              ^^^^

Параметры привязки сохранят тип не-строк, таких как целые и нулевые значения.Также отмечу, что N - это целое число, но вы используете его как имя, которое обычно означает строку.Так что это может быть проблемой.


Теперь о том противном имени таблицы.Мы не можем передать это как параметр связывания.Вы хотите убедиться, что он не может выпрыгнуть из своих кавычек, поэтому `необходимо экранировать.Вы также не хотите, чтобы кто-либо мог перейти к другой базе данных, поэтому . также должен быть экранирован.Или, что еще лучше, выдаст ошибку .Мы не можем использовать quote(), потому что это для значений столбцов с другими правилами цитирования.Нам придется написать нашу собственную.

DELIMITER $$
drop procedure if exists check_table_name;
CREATE PROCEDURE check_table_name (
    table_name varchar(255)
)
begin
    if( locate("`", table_name) ) then
        signal sqlstate '45000'
            set message_text = 'illegal ` in table name';
    elseif( locate(".", table_name) ) then
        signal sqlstate '45000'
            set message_text = 'illegal . in table name';
    end if;
end $$
DELIMITER ;

Теперь мы называем это именем таблицы перед ее использованием.

call check_table_name(@tableName);
SET @q = concat('INSERT INTO `' , @tableName, '` VALUES(?,?,?,?,?,?)');
PREPARE stmt FROM @q;
EXECUTE stmt USING @NName, @APName, @AMName, @NomName, @DNIName, @DirecName;
DEALLOCATE PREPARE stmt;

И если это будет непослушным, мы получим ошибку.

mysql> call insertar_datos("foo`haha, I broke your quoting`bar", 23, 'A', 'B', 'C', 'D', 'E ');
ERROR 1644 (45000): illegal ` in table name

Но опять же Я настоятельно не рекомендую этот подход .В любое время, когда вы объединяете строки, чтобы составить операторы SQL, вы подвержены риску ошибок и недостатков безопасности.Я не уверен, что check_table_name объясняет все проблемы.

Если вы должны использовать этот подход, рассмотрите вместо этого использование фиксированного набора разрешенных имен.

if name in ("foo", "bar", "baz", "table_x") then
    set @tableName = name;
else
    signal sqlstate '45000'
        set message_text = 'unknown name';
end if;

Я призываю васвместо этого рассмотрите возможность изменения схемы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...