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

它一定很简单,但我正在做我的第一步到Postgres函数,我找不到任何工作…

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

就像是:

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; 

有没有可能做到这一点?

每当将用户input转换为代码时,您都必须防范SQL注入 。 这包括来自系统目录或来自直接用户input的表和列名称。 这样你也可以防止使用非标准标识符的简单例外。 基本上有三种内置的方法:

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格式说明符一起使用。

单独的表名可能是不明确的。 您可能必须提供模式名称,以避免意外更改错误的表格。 有关:

  • 在触发器函数中插入dynamic表名
  • search_path如何影响标识符parsing和“当前模式”

另外: 使用单个ALTER TABLE命令添加多个列更便宜。

regclass

您也可以使用regclasstypes转换为已注册的类( regclass )来处理现有表名的特殊情况。 可选模式限定。 这对于主叫用户无效且可见的表名称立即失败。 第一个查询用一个regclassregclass

 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而不是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()更清晰。

相关答案:

  • 表名称作为PostgreSQL函数参数
  • Postgres函数与准备的查询

区分大小写!

请注意,未加引号的标识符在这里不会转换为小写。 在SQL中用作标识符时Postgres自动转换为小写 。 但是在这里,我们为dynamicSQL传递string 。 当像已经certificate的那样转义时,CaMel-case标识符(如UserS )将通过双引号( "UserS" )保存,就像其他非标准名称,如"name with space" "SELECT"等。因此,名称区分大小写上下文。

我的build议是专门使用合法的小写字母标识符,而不用担心。

另外: 值的单引号,标识符的双引号 。