在plpgsql函数中将表和列名定义为参数?

时间:2013-08-22 15:02:58

标签: function postgresql variables plpgsql dynamic-sql

一定很简单,但我正在迈出Postgres功能的第一步,我找不到任何有用的东西......

我想创建一个修改表和/或列的函数,但我找不到在我的函数中将表和列指定为参数的正确方法。

类似的东西:

CREATE OR REPLACE FUNCTION foo(t table)
RETURNS void AS $$
BEGIN
   alter table t add column c1 varchar(20);
   alter table t add column c2 varchar(20);
   alter table t add column c3 varchar(20);
   alter table t add column c4 varchar(20);
END;
$$ LANGUAGE PLPGSQL;

select foo(some_table)

在另一种情况下,我想要一个改变特定表中某个列的函数:

CREATE OR REPLACE FUNCTION foo(t table, c column)
RETURNS void AS $$
BEGIN
   UPDATE t SET c = "This is a test";
END;
$$ LANGUAGE PLPGSQL;

有可能吗?

1 个答案:

答案 0 :(得分:29)

每当您将用户输入转换为代码时,您必须防御SQL injection。这包括来自系统目录或来自直接用户输入的表名和列名。这样,您还可以防止使用非标准标识符的普通异常。基本上有 三个 内置方法:

1。 format()

第一个查询,已消毒:

CREATE OR REPLACE FUNCTION foo(_t text)
  RETURNS void AS
$func$
BEGIN
   EXECUTE format('
   ALTER TABLE %I ADD COLUMN c1 varchar(20)
                , ADD COLUMN c2 varchar(20)', _t);
END
$func$  LANGUAGE plpgsql;

format()需要Postgres 9.1或更高版本。将其与 %I 格式说明符一起使用。

仅表格名称可能不明确。您可能必须提供架构名称以避免意外更改错误的表。相关:

除此之外:添加multiple columns with a single ALTER TABLE command更便宜。

2。 regclass

对于 现有 表名的特殊情况,您还可以对已注册的类(regclass)使用强制转换。可选择模式限定。对于对调用用户无效且可见的表名,这会立即且优雅地失败。第一个查询通过强制转换为regclass

进行清理
CREATE OR REPLACE FUNCTION foo(_t regclass)
  RETURNS void AS
$func$
BEGIN
   EXECUTE 'ALTER TABLE '|| _t ||' ADD COLUMN c1 varchar(20)
                                 , ADD COLUMN c2 varchar(20)';
END
$func$  LANGUAGE plpgsql;

呼叫:

SELECT foo('table_name');

或者:

SELECT foo('my_schema.table_name'::regclass);

除此之外:考虑只使用text instead of varchar(20)

3。 quote_ident()

第二个查询已消毒:

CREATE OR REPLACE FUNCTION foo(_t regclass, _c text)
  RETURNS void AS
$func$
BEGIN
   EXECUTE 'UPDATE '|| _t ||'   -- sanitized with regclass
            SET '|| quote_ident(_c) ||' = ''This is a test''';
END
$func$  LANGUAGE plpgsql;

对于多个连接/插值,format()更清晰......

相关答案:


区分大小写!

请注意,此处未加引号的标识符强制转换为小写。在SQL Postgres casts to lower case automatically中用作标识符时。但是在这里我们传递动态SQL的 strings 。如图所示进行转义时,CaMel案例标识符(如UserS)将通过双引号("UserS")保留,就像其他非标准名称一样,如"name with space" "SELECT"等。因此,在这种情况下,名称区分大小写。

我的常设建议是专门使用合法的小写标识符,从不担心。

除此之外:single quotes for values, double quotes for identifiers