Postgresql 函数 - 使用文本类型的 VARIADIC 参数
Postgresql Functions - Using VARIADIC arguments of text type
我正在尝试编写一个函数来从 Redshift 获取架构中的对象列表。我已经创建了一个从 RDS PostgreSQL 到 Redshift 的数据库链接。查询在单独调用时工作得很好,但在带有参数的函数中编写时不起作用。我想传递多个参数(模式名称),因此我使用了 VARIADIC 参数。该函数如下所示 -
CREATE FUNCTION f_fetch_tables(VARIADIC list text[])
RETURNS VOID
AS $$
DECLARE
begin_time TIMESTAMP;
expire_time TIMESTAMP;
BEGIN
/* To fetch the list of all objects from Redshift */
EXECUTE 'drop table if exists tmp_rs_obj_list;
create table tmp_rs_obj_list as
SELECT * FROM dblink(''rs_link'',$REDSHIFT$ select * from (select schemaname,
tablename from pg_tables UNION select schemaname, viewname from pg_views) where schemaname
not in (array_to_string(,'','')) $REDSHIFT$) AS t1 (schema_nm varchar(30), obj_nm varchar(100))' using list;
END;
$$
LANGUAGE plpgsql
;
该函数编译良好并成功创建,但我无法找到调用它的方法 -
到目前为止使用了这些调用,没有任何运气 -
select f_fetch_tables('{public,pg_catalog}')
错误:没有参数 $1
其中:名为 "unnamed" 的 dblink 连接发生错误:无法
执行查询。
select * 来自 f_fetch_tables(VARIADIC '{public,pg_catalog}')
错误:没有参数 $1
其中:名为 "unnamed" 的 dblink 连接发生错误:无法执行查询。
任何建议都会很有帮助。
谢谢,
卡姆莱什
此问题与可变参数无关 - 如果您也使用普通参数,您将获得相同的行为。它与动态 SQL 有关 - EXECUTE
命令从 PLpgSQL 执行的查询具有自己的参数环境。所以你不能使用函数环境中的变量或参数引用。
此代码无效:
CREATE OR REPLACE FUNCTION fx(a int)
RETURNS void AS $$
BEGIN
EXECUTE 'SELECT * FROM foo WHERE foo.a = ';
END;
$$ LANGUAGE plpgsql;
在这种情况下,没有向执行的查询传递任何参数。 </code> 无效。当您将一些参数传递给动态 SQL.</p> 时,您应该使用 <code>USING
子句
这段代码应该可以工作:
CREATE OR REPLACE FUNCTION fx(a int)
RETURNS void AS $$
BEGIN
EXECUTE 'SELECT * FROM foo WHERE foo.a = ' USING a;
END;
$$ LANGUAGE plpgsql;
但这并不能解决你的问题,因为你使用的是 USING
子句。但是您仅在级别 EXECUTE
命令上使用 USING 子句 - 而不是在 dblink
级别 - 它不受支持。 dblink
API 与 EXECUTE
命令的 USING
子句没有任何相似之处。因此,在将其发送到 dblink API.
之前,您必须使用解压缩(预评估)参数构建本机 SQL 字符串
您正在使用两个级别的动态 SQL
EXECUTE
dblink
dblink
不支持查询参数化 - 所以你不应该在那里使用参数占位符.. $x.
在这种情况下,最好将输入数组序列化为顶级 plpgsql 级别的字符串,并像动态 SQL 参数一样传递此字符串。
DECLARE serialized_params text;
BEGIN
serialized_params = (SELECT array_agg(quote_literal(quote_ident(v))) FROM unnest(ARRAY['A','b']) g(v));
EXECUTE ' ....' USING serialized_params;
END
您的函数存在一些问题。我建议使用:
- 方便传递参数的函数
format()
,
- dollar quoted
($fmt$)
内查询 execute
,
<> all(array)
而不是 not in
运算符(您不必将数组转换为字符串)。
具有建议更改的函数:
create or replace function f_fetch_tables(variadic list text[])
returns void
as $$
declare
begin_time timestamp;
expire_time timestamp;
begin
/* to fetch the list of all objects from redshift */
execute format($fmt$
drop table if exists tmp_rs_obj_list;
create table tmp_rs_obj_list as
select *
from dblink(
'rs_link', $redshift$
select *
from (
select schemaname, tablename
from pg_tables
union
select schemaname, viewname
from pg_views) s
where schemaname <> all(%L)
$redshift$)
as t1 (schema_nm varchar(30), obj_nm varchar(100))
$fmt$, list);
end;
$$
language plpgsql;
另请注意将参数传递给具有可变参数的函数的正确方法:
select f_fetch_tables('pg_catalog', 'information_schema');
select * from tmp_rs_obj_list;
我正在尝试编写一个函数来从 Redshift 获取架构中的对象列表。我已经创建了一个从 RDS PostgreSQL 到 Redshift 的数据库链接。查询在单独调用时工作得很好,但在带有参数的函数中编写时不起作用。我想传递多个参数(模式名称),因此我使用了 VARIADIC 参数。该函数如下所示 -
CREATE FUNCTION f_fetch_tables(VARIADIC list text[])
RETURNS VOID
AS $$
DECLARE
begin_time TIMESTAMP;
expire_time TIMESTAMP;
BEGIN
/* To fetch the list of all objects from Redshift */
EXECUTE 'drop table if exists tmp_rs_obj_list;
create table tmp_rs_obj_list as
SELECT * FROM dblink(''rs_link'',$REDSHIFT$ select * from (select schemaname,
tablename from pg_tables UNION select schemaname, viewname from pg_views) where schemaname
not in (array_to_string(,'','')) $REDSHIFT$) AS t1 (schema_nm varchar(30), obj_nm varchar(100))' using list;
END;
$$
LANGUAGE plpgsql
;
该函数编译良好并成功创建,但我无法找到调用它的方法 -
到目前为止使用了这些调用,没有任何运气 -
select f_fetch_tables('{public,pg_catalog}')
错误:没有参数 $1 其中:名为 "unnamed" 的 dblink 连接发生错误:无法 执行查询。
select * 来自 f_fetch_tables(VARIADIC '{public,pg_catalog}')
错误:没有参数 $1 其中:名为 "unnamed" 的 dblink 连接发生错误:无法执行查询。
任何建议都会很有帮助。
谢谢, 卡姆莱什
此问题与可变参数无关 - 如果您也使用普通参数,您将获得相同的行为。它与动态 SQL 有关 - EXECUTE
命令从 PLpgSQL 执行的查询具有自己的参数环境。所以你不能使用函数环境中的变量或参数引用。
此代码无效:
CREATE OR REPLACE FUNCTION fx(a int)
RETURNS void AS $$
BEGIN
EXECUTE 'SELECT * FROM foo WHERE foo.a = ';
END;
$$ LANGUAGE plpgsql;
在这种情况下,没有向执行的查询传递任何参数。 </code> 无效。当您将一些参数传递给动态 SQL.</p> 时,您应该使用 <code>USING
子句
这段代码应该可以工作:
CREATE OR REPLACE FUNCTION fx(a int)
RETURNS void AS $$
BEGIN
EXECUTE 'SELECT * FROM foo WHERE foo.a = ' USING a;
END;
$$ LANGUAGE plpgsql;
但这并不能解决你的问题,因为你使用的是 USING
子句。但是您仅在级别 EXECUTE
命令上使用 USING 子句 - 而不是在 dblink
级别 - 它不受支持。 dblink
API 与 EXECUTE
命令的 USING
子句没有任何相似之处。因此,在将其发送到 dblink API.
您正在使用两个级别的动态 SQL
EXECUTE
dblink
dblink
不支持查询参数化 - 所以你不应该在那里使用参数占位符.. $x.
在这种情况下,最好将输入数组序列化为顶级 plpgsql 级别的字符串,并像动态 SQL 参数一样传递此字符串。
DECLARE serialized_params text;
BEGIN
serialized_params = (SELECT array_agg(quote_literal(quote_ident(v))) FROM unnest(ARRAY['A','b']) g(v));
EXECUTE ' ....' USING serialized_params;
END
您的函数存在一些问题。我建议使用:
- 方便传递参数的函数
format()
, - dollar quoted
($fmt$)
内查询execute
, <> all(array)
而不是not in
运算符(您不必将数组转换为字符串)。
具有建议更改的函数:
create or replace function f_fetch_tables(variadic list text[])
returns void
as $$
declare
begin_time timestamp;
expire_time timestamp;
begin
/* to fetch the list of all objects from redshift */
execute format($fmt$
drop table if exists tmp_rs_obj_list;
create table tmp_rs_obj_list as
select *
from dblink(
'rs_link', $redshift$
select *
from (
select schemaname, tablename
from pg_tables
union
select schemaname, viewname
from pg_views) s
where schemaname <> all(%L)
$redshift$)
as t1 (schema_nm varchar(30), obj_nm varchar(100))
$fmt$, list);
end;
$$
language plpgsql;
另请注意将参数传递给具有可变参数的函数的正确方法:
select f_fetch_tables('pg_catalog', 'information_schema');
select * from tmp_rs_obj_list;