mysql prepare statement-是否可以参数化列名或函数名?

w8biq8rn  于 2021-06-18  发布在  Mysql
关注(0)|答案(1)|浏览(388)

假设我想写一个过程,允许我在某个列上调用某个函数,例如:

call foo('min','age') -> SELECT min(age) FROM table;

我希望我的过程不受sql注入的影响,因此,我愿意使用准备好的语句并参数化输入

SET @var = "SELECT ?(?) FROM table;"
PREPARE x FROM @var;
EXECUTE x USING a, b;

其中a和b分别是输入参数、函数和列。
然而,这似乎是不可能的-每当我想执行这个语句时,innodb总是抛出一个错误。
是可以这样解决,还是我需要诉诸白名单?
编辑:完整代码:

create procedure test(in func varchar(20), in col varchar(20))
  begin
    set @f = func;
    set @c = col;
    set @sql = "select ?(?) from table;";
    prepare x from @sql;
    execute x using @f, @c;
  end;

打电话:

call test('min','age');

完全错误:
[42000][1064]您的sql语法有错误;检查与mysql服务器版本相对应的手册,以获得在第1行的“(?)from table”附近使用的正确语法

vc9ivgsu

vc9ivgsu1#

不能参数化列/表/函数名/别名。作为, PREPARE 语句只允许sql查询的“值”部分用作参数。函数/表/列名/别名用于确定sql语句的有效性;因此在运行时执行期间不能更改。在执行时更改它可能会改变sql语句是否有效。
你可以把它看作是编译代码;因此,编译器必须知道创建有效可执行文件所需的所有函数/类名等(是的,我们可以创建动态类,但这很少见)。另一方面,我们可以更改程序的输入“值”,但通常不能更改对输入数据执行的操作。
此外,mysql服务器在执行查询之前,会将参数视为文本,并在其周围应用引号。
现在,在您的例子中,您仍然可以使用函数名作为存储过程的参数,并使用它生成查询字符串。但不能将其用作查询本身的参数。

delimiter $$
create procedure test(in func varchar(20), in col varchar(20))
  begin

    set @c = col;

    -- use concat function to generate the query string using func parameter
    set @sql = concat('select ', func, '(?) from table');

    -- prepare the statement
    prepare stmt from @sql;

    -- execute
    execute x using @c;

    -- don't forget to deallocate the prepared statement
    deallocate prepare stmt;
  end$$
delimiter ;

相关问题