我尝试使用下面的存储过程在MySQL的动态表中插入数据,但是使用以下命令调用它时出现错误:
Node *constructTreeHelper(FILE *infile, int *index) {
double lwire, rwire;
int sink;
double cap;
Node *node;
// Base case
if (*index <= 0) {
// This test seems redundant with the file contents */
return NULL;
}
// this fscanf will fail on the byte byte if it is not a '('
if (fscanf(infile, " (%le %le)", &lwire, &rwire) == 2) {
// If the node is not a leaf node
node = createNode(0, 0, lwire, rwire);
*index -= 1;
node->right = constructTreeHelper(infile, index);
node->left = constructTreeHelper(infile, index);
} else if (fscanf(infile, "%d(%le)\n", &sink, &cap) == 2) {
// If the node is a leaf node
node = createNode(sink, cap, 0, 0);
*index -= 1;
} else {
// invalid format or end of file */
node = NULL;
}
return node;
}
错误
CALL insert_data ('table_x', 'NULL', 'A', 'B', 'C', 'D', 'E ')
程序
Column unknown' 0 'in the list of fields.
答案 0 :(得分:1)
如果您发现具有相同列的多个表,则可能是设计不良的架构。设计良好的架构不需要您要的内容。我鼓励您问另一个问题,关于如何设计架构以完全避免问题。
将未过滤的字符串连接在一起容易受到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 ')
^^^^
绑定参数将保留非字符串的类型,例如整数和null。我还将注意到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;
我鼓励您改为考虑重新设计架构。