我想在Postgres函数中传递一个表名作为参数.我试过这个密码:

CREATE OR REPLACE FUNCTION some_f(param character varying) RETURNS integer 
AS $$
    BEGIN
    IF EXISTS (select * from quote_ident($1) where quote_ident($1).id=1) THEN
     return 1;
    END IF;
    return 0;
    END;
$$ LANGUAGE plpgsql;

select some_f('table_name');

我得到了这个:

ERROR:  syntax error at or near "."
LINE 4: ...elect * from quote_ident($1) where quote_ident($1).id=1)...
                                                             ^

********** Error **********

ERROR: syntax error at or near "."

下面是我改成select * from quote_ident($1) tab where tab.id=1时的错误:

ERROR:  column tab.id does not exist
LINE 1: ...T EXISTS (select * from quote_ident($1) tab where tab.id...

quote_ident($1)可能有效,因为没有where quote_ident($1).id=1部分,我得到1,这意味着有些东西被选中了.为什么前quote_ident($1)个可以同时工作,而第二个不能同时工作?这怎么解决呢?

推荐答案

这可以进一步简化和改进:

CREATE OR REPLACE FUNCTION some_f(_tbl regclass, OUT result integer)
    LANGUAGE plpgsql AS
$func$
BEGIN
   EXECUTE format('SELECT (EXISTS (SELECT FROM %s WHERE id = 1))::int', _tbl)
   INTO result;
END
$func$;

使用模式限定名调用(见下文):

SELECT some_f('myschema.mytable');  -- would fail with quote_ident()

或者:

SELECT some_f('"my very uncommon table name"');

要点

使用100 parameter简化函数.您可以直接将动态SQL的结果 Select 到其中并完成.不需要额外的变量和代码.

100正是你想要的.如果行存在,则得到true,否则得到false.有多种方法可以做到这一点,EXISTS通常是最有效的.

你似乎想要返回integer,所以我将boolean的结果从EXISTS转换为integer,这就产生了你所拥有的结果.我会退回boolean美元.

我使用对象标识符类型regclass作为_tbl的输入类型.这是quote_ident(_tbl)format('%I', _tbl)所能做到的,但更好,因为:

  • …它同样可以防止SQL injection次.

  • ..如果表名无效/不存在/对当前用户不可见,它会立即失败,而且会更加优雅.(regclass参数仅适用于existing个表.)

  • ..它适用于模式限定的表名,普通的quote_ident(_tbl)format(%I)会失败,因为它们无法解决歧义.必须分别传递和转义模式名和表名.

显然,它只适用于existing张桌子.

我仍然使用format(),因为它简化了语法(并演示了如何使用它),但使用%s而不是%I.通常,查询更复杂,因此format()帮助更多.对于一个简单的例子,我们也可以连接:

EXECUTE 'SELECT (EXISTS (SELECT FROM ' || _tbl || ' WHERE id = 1))::int'

FROM列表中只有一个表时,不需要对id列进行表限定.在这个例子中不可能有歧义.(动态)EXECUTE中的SQL命令具有separate scope,函数变量或参数在那里不可见,这与函数体中的普通SQL命令相反.

这就是为什么要正确地为动态SQL转义用户输入:

db<>fiddle here demonstrating SQL injection
Old sqlfiddle

Postgresql相关问答推荐

列不明确

Postgres 11没有强制执行外键约束?

如何返回old_ids和重复行的映射';来自PostgreSQL函数的s new_id

如何计算每月的出版物数量?

Postgres 查询计划器不会使用更便宜的复合索引

Postgres 低估了导致错误查询计划的行数

使用包含重复元素的数组 Select 重复值

安装 pg gem 失败,mkmf.rb 找不到 ruby​​ 的头文件(Mac OSX 10.6.5)

使用 Django + Postgres 的加密策略?

在 to_tsquery 中转义特殊字符

无法向 postgresql 数据库授予用户权限(对于 rails 应用程序)

如何在构建时链接 docker 容器?

在远程机器上Restore dump

如何将1 天 01:30:00等间隔转换为25:30:00?

当记录包含 json 或字符串的混合时,如何防止 Postgres 中的invalid input syntax for type json

错误:CASE types character varying and numeric cannot be matched

Postgres UPDATE with ORDER BY,怎么做?

如何使用 Node.js 和 Postgresql 找到最后一个插入 ID?

错误:表tablename上的更新或删除违反外键约束

安装了 Postgres.app 但它不起作用