Postgresql函数-使用文本类型的可变参数

Postgresql函数-使用文本类型的可变参数,postgresql,plpgsql,amazon-rds,dynamic-sql,variadic-functions,Postgresql,Plpgsql,Amazon Rds,Dynamic Sql,Variadic Functions,我试图编写一个函数,从红移中获取模式中的对象列表。我已经创建了一个从RDS PostgreSQL到Redshift的数据库链接。单独调用查询时,查询工作正常,但在包含参数的函数中写入时,查询不工作。我想传递多个参数(模式名称),因此我使用了可变参数。函数如下所示- CREATE FUNCTION f_fetch_tables(VARIADIC list text[]) RETURNS VOID AS $$ DECLARE begin_time TIMESTAMP;

我试图编写一个函数,从红移中获取模式中的对象列表。我已经创建了一个从RDS PostgreSQL到Redshift的数据库链接。单独调用查询时,查询工作正常,但在包含参数的函数中写入时,查询不工作。我想传递多个参数(模式名称),因此我使用了可变参数。函数如下所示-

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($1,'','')) $REDSHIFT$) AS t1 (schema_nm varchar(30), obj_nm varchar(100))' using list;
    END;
  $$
  LANGUAGE plpgsql
;
该函数编译得很好,创建成功,但我无法找到调用它的方法-

到目前为止都用过这些电话,运气不好-

  • 选择f_fetch_tables(“{public,pg_catalog}”)

    错误:没有参数$1 其中:名为“未命名”的dblink连接上发生错误:无法 执行查询

  • 从f_fetch_表中选择*(变量“{public,pg_catalog}”)

    错误:没有参数$1 其中:名为“未命名”的dblink连接出错:无法执行查询

  • 任何建议都会很有帮助

    谢谢,,
    Kamlesh

    此问题与可变参数无关-如果您也使用正常参数,您将得到相同的行为。它与动态SQL相关-由PLpgSQL中的
    EXECUTE
    命令执行的查询具有自己的参数环境。所以您不能使用函数环境中的变量或参数引用

    此代码不起作用:

    CREATE OR REPLACE FUNCTION fx(a int)
    RETURNS void AS $$
    BEGIN
      EXECUTE 'SELECT * FROM foo WHERE foo.a = $1';
    END;
    $$ LANGUAGE plpgsql;
    
    在这种情况下,并没有向执行的查询传递任何参数<代码>$1无效。当您想要向动态SQL传递一些参数时,应该使用
    USING
    子句

    此代码应在以下情况下运行:

    CREATE OR REPLACE FUNCTION fx(a int)
    RETURNS void AS $$
    BEGIN
      EXECUTE 'SELECT * FROM foo WHERE foo.a = $1' USING a;
    END;
    $$ LANGUAGE plpgsql;
    
    但这并不能解决您的问题,因为您正在使用
    using
    子句。但您仅在
    EXECUTE
    command级别使用USING子句,而不是在
    dblink
    级别使用USING子句,因为它不受支持
    dblink
    API与使用
    EXECUTE
    命令的
    子句的
    没有任何相似之处。因此,在将其发送到dblink API之前,必须使用未打包(预评估)的参数构建本机SQL字符串

    您正在使用两个级别的动态SQL

    • 执行
      • dblink
    dblink
    不支持查询参数化-因此您不应该在那里使用参数占位符$十,

    在这种情况下,最好将输入数组序列化为顶级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
    

    这个问题与可变参数无关-如果您也使用正常参数,您将得到相同的行为。它与动态SQL相关-由PLpgSQL中的
    EXECUTE
    命令执行的查询具有自己的参数环境。所以您不能使用函数环境中的变量或参数引用

    此代码不起作用:

    CREATE OR REPLACE FUNCTION fx(a int)
    RETURNS void AS $$
    BEGIN
      EXECUTE 'SELECT * FROM foo WHERE foo.a = $1';
    END;
    $$ LANGUAGE plpgsql;
    
    在这种情况下,并没有向执行的查询传递任何参数<代码>$1
    无效。当您想要向动态SQL传递一些参数时,应该使用
    USING
    子句

    此代码应在以下情况下运行:

    CREATE OR REPLACE FUNCTION fx(a int)
    RETURNS void AS $$
    BEGIN
      EXECUTE 'SELECT * FROM foo WHERE foo.a = $1' USING a;
    END;
    $$ LANGUAGE plpgsql;
    
    但这并不能解决您的问题,因为您正在使用
    using
    子句。但您仅在
    EXECUTE
    command级别使用USING子句,而不是在
    dblink
    级别使用USING子句,因为它不受支持
    dblink
    API与使用
    EXECUTE
    命令的
    子句的
    没有任何相似之处。因此,在将其发送到dblink API之前,必须使用未打包(预评估)的参数构建本机SQL字符串

    您正在使用两个级别的动态SQL

    • 执行
      • dblink
    dblink
    不支持查询参数化-因此您不应该在那里使用参数占位符$十,

    在这种情况下,最好将输入数组序列化为顶级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()
      用于轻松传递参数
    • 美元报价
      ($fmt$)
      执行
      中的查询
    • all(array)
      而不是
      不在
      运算符中(您不必将数组转换为字符串)
    具有建议更改的功能:

    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;
    

    您的功能存在一些问题。我建议使用:

    • 函数
      format()
      用于轻松传递参数
    • 美元报价
      ($fmt$)
      执行
      中的查询
    • all(array)
      而不是
      不在
      运算符中(您不必将数组转换为字符串)
    具有建议更改的功能:

    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;