PostgreSQL 函数中的 psql 变量是不是有任何转义语法?
Posted
技术标签:
【中文标题】PostgreSQL 函数中的 psql 变量是不是有任何转义语法?【英文标题】:Are there any escaping syntax for psql variable inside PostgreSQL functions?PostgreSQL 函数中的 psql 变量是否有任何转义语法? 【发布时间】:2011-03-16 15:21:33 【问题描述】:我编写 PSQL 脚本并使用变量(对于 psql --variable key=value 命令行语法)。
这对于像 select * from :key 这样的***范围非常有效,但我使用脚本创建函数并且需要在其中的变量值。
所以,语法像
create function foo() returns void as
$$
declare
begin
grant select on my_table to group :user;
end;
$$
language plpgsql;
在 :user 处失败。
据我了解 psql 变量是一个普通的宏替换功能,但它不处理函数体。 这种情况是否有任何转义语法?用 $$ 包围 :user 可以解决替换问题,但 psql 在 $$ 处失败。
除了独立的宏处理(sed、awk 等)之外,还有其他方法吗?
【问题讨论】:
你能让函数 foo 接受一个参数并使用它吗? 【参考方案1】:PSQL SET
变量不会插入美元引用的字符串中。我不确定这一点,但我认为在那里打开SET
变量插值没有任何逃避或其他诡计。
有人可能会认为您可以将未引用的:user
插入两个以美元引用的 PL/pgSQL 段之间以获得所需的效果。但这似乎不起作用......我认为语法需要单个字符串而不是连接字符串的表达式。可能是误会了。
无论如何,这并不重要。还有另一种方法(如 Pasco 所述):编写存储过程以接受 PL/pgSQL 参数。这就是它的样子。
CREATE OR REPLACE FUNCTION foo("user" TEXT) RETURNS void AS
$$
BEGIN
EXECUTE 'GRANT SELECT ON my_table TO GROUP ' || quote_ident(user);
END;
$$ LANGUAGE plpgsql;
关于此功能的说明:
EXECUTE
在每次调用时使用我们的过程参数生成一个适当的GRANT
。名为“Executing Dynamic Commands”的 PG 手册部分详细解释了EXECUTE
。
过程参数user
的声明必须用双引号引起来。双引号强制将其解释为标识符。
一旦定义了这样的函数,就可以使用插值的 PSQL 变量来调用它。这是一个大纲。
-
运行
psql --variable user="'whoever'" --file=myscript.sql
。用户名周围需要单引号!
在 myscript.sql 中,定义类似上面的函数。
在 myscript.sql 中,输入 select foo(:user);
。这就是我们依赖那些在user
值中添加的单引号的地方。
虽然这似乎可行,但它让我觉得相当松鼠。我认为SET
变量用于运行时配置。在SET
中携带数据似乎很奇怪。
编辑:这是不使用SET
变量的具体原因。来自手册页:“这些分配是在启动的早期阶段完成的,因此为内部目的保留的变量可能会在以后被覆盖。”如果 Postgres 决定使用名为 user
的变量(或任何你选择的变量),它可能会用你从未想过的东西覆盖你的脚本参数。事实上,psql 已经为自己使用了USER
——这只是因为SET
是区分大小写的。这几乎从一开始就破坏了一切!
【讨论】:
你应该使用 EXECUTE 'GRANT SELECT ON my_table TO GROUP ' ||报价标识(用户);我相信。 @rfusca 是的,消毒它不会有什么坏处!【参考方案2】:你可以使用 Dan LaRocque 所描述的方法让它变得有点像 hack'ishly 的工作(而不是敲击 Dan)——但是 psql 并不是你做这种工作的真正朋友(假设这种工作是脚本和不是一次性的东西)。如果您有一个函数,请将其重写为采用如下参数:
create function foo(v_user text) returns void as
$$
begin
execute 'grant select on my_table to group '||quote_ident(v_user);
end;
$$
language plpgsql;
(quote_ident() 使您不必保证双引号,它可以处理所有这些。)
然后使用具有 Postgres 驱动程序的真正脚本语言(如 Perl、Python、Ruby 等)来使用参数调用您的函数。
Psql 有它的位置,我只是不确定是不是它。
【讨论】:
我同意像这样使用 psqlSET
可能存在维护风险。当我写我的答案时,我也分享了你的疑虑。最后有一小段给出了一个具体的原因为什么它是有风险的。
@Dan LaRocque:是的,这就是为什么我觉得没有必要重申这一点,以及为什么我什至赞成你的回答。 :)【参考方案3】:
实际上,在更现代的psql
版本中有一种方法。
由于函数体 has to be a string constant 和 psql
does not perform variable interpolation within string constants 我们不得不在单独的第一步中组装函数体:
select format($gexec$
create function foo() returns void as
$$
begin
grant select on my_table to group %I;
end;
$$
language plpgsql;
$gexec$, :'user') \gexec
结尾的\gexec
命令
【讨论】:
以上是关于PostgreSQL 函数中的 psql 变量是不是有任何转义语法?的主要内容,如果未能解决你的问题,请参考以下文章
PostgreSQL。日志文件中的慢查询在 psql 中很快