如果发现自己拥有多个具有相同列的表,那么可能会有一个设计不良的模式。对于一个设计良好的模式,您所要求的不是必需的。我鼓励你问一个关于如何设计你的模式来避免你的问题的另一个问题。
将未筛选的字符串连接在一起容易受到
SQL Injection attack
是的。相反,只要有可能,使用绑定参数并将值传递到。这样可以确保它们被正确地转义和引用,不会被意外或恶意地曲解。
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
是一个整数,但您使用它作为通常表示字符串的名称。所以这可能是个问题。
关于那个讨厌的表名。我们不能把它作为一个绑定参数来传递。你要确保它不能跳出引号,所以必须转义。你也不希望任何人能跳转到另一个数据库,所以
.
也必须逃走。或者更好,
raise an error
是的。我们不能用
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;
我建议您考虑重新设计您的模式。