每当您将用户输入转换为代码时,您都必须防御SQL 注入。这包括来自系统目录或直接用户输入的表名和列名。这样,您还可以防止使用非标准标识符的琐碎异常。基本上有三种内置方法:
第一个查询,已清理:
CREATE OR REPLACE FUNCTION foo(_t text)
RETURNS void
LANGUAGE plpgsql AS
$func$
BEGIN
EXECUTE format('
ALTER TABLE %I ADD COLUMN c1 varchar(20)
, ADD COLUMN c2 varchar(20)', _t);
END
$func$;
format()
需要 Postgres 9.1 或更高版本。与%I
格式说明符一起使用。
单独的表名可能不明确。您可能必须提供模式名称以避免意外更改错误的表。有关的:
另外:使用单个命令添加多个列ALTER TABLE
更便宜。
对于现有表名regclass
的特殊情况,您还可以使用对已注册类 ( ) 的强制转换。可选的模式限定。对于调用用户无效且不可见的表名,这将立即且正常地失败。第一个查询使用强制转换为:regclass
CREATE OR REPLACE FUNCTION foo(_t regclass)
RETURNS void
LANGUAGE plpgsql AS
$func$
BEGIN
EXECUTE 'ALTER TABLE ' || _t || ' ADD COLUMN c1 varchar(20)
, ADD COLUMN c2 varchar(20)';
END
$func$;
称呼:
SELECT foo('table_name');
或者:
SELECT foo('my_schema.table_name'::regclass);
旁白:考虑使用 justtext
而不是varchar(20)
.
清理了第二个查询:
CREATE OR REPLACE FUNCTION foo(_t regclass, _c text)
RETURNS void
LANGUAGE plpgsql AS
$func$
BEGIN
EXECUTE 'UPDATE ' || _t -- sanitized with regclass
|| ' SET ' || quote_ident(_c) || ' = ''This is a test''';
END
$func$;
对于多个连接/插值,format()
更清洁......
相关答案:
区分大小写!
请注意,此处未加引号的标识符不会转换为小写。在 SQL [Postgres 自动转换为小写] [7] 中用作标识符时。但是这里我们为动态 SQL 传递字符串。当按照演示转义时,CaMel 大小写标识符(如UserS
)将通过双引号 ( "UserS"
) 保留,就像其他非标准名称(如"name with space"
"SELECT"
etc)一样。因此,名称在此上下文中区分大小写。
我的长期建议是专门使用合法的小写标识符,永远不要担心这一点。
另外:单引号用于值,双引号用于标识符。看: