将查询作为参数传递时找不到变量

Doesn't find variable when passing query as parameter

我有一个带有静态输出的函数可以正常工作。 (Postgres v.10) 这 returns 每个服务器的用户数量。

代码如下:

CREATE OR REPLACE FUNCTION public.test()
 RETURNS SETOF record
 LANGUAGE plpgsql
AS $function$
DECLARE
    var_req TEXT;
    var_error text;
    rec_key record;
    cur_key CURSOR FOR Select s.srv,s.host,s.port from public.connections() s where s.online = true;
BEGIN
open cur_key;
loop
   fetch cur_key into rec_key;
   EXIT WHEN NOT FOUND;

var_req := 
'Select * from dblink(
''host=' || rec_key.host || '
port=' || rec_key.port || '
user=**
password=**
dbname=mydb'',
''
select '''''|| rec_key.srv ||''''' as srv ,count (*) as total from users '') as (srv varchar,total integer)
';
return query execute var_req;  
end loop;
close cur_key;
END 
$function$
; 

输出=

srv      total
rp1       50
sr2       41
xy        100

为了能够重用此查询,我想移出 sql 部分,以便我可以将其作为参数传递。

CREATE OR REPLACE FUNCTION public.test2(text)
 RETURNS SETOF record
 LANGUAGE plpgsql
AS $function$
DECLARE
    var_req TEXT;
    var_error text;
    rec_key record;
    cur_key CURSOR FOR Select s.srv,s.host,s.port from public.connections() s where s.online = true;
BEGIN
open cur_key;
loop
   fetch cur_key into rec_key;
   EXIT WHEN NOT FOUND;

var_req := 
'Select * from dblink(
''host=' || rec_key.host || '
port=' || rec_key.port || '
user=**
password=**
dbname=**'',
''
' ||  || '
';
return query execute var_req;  
end loop;
close cur_key;
END 
$function$
;

现在,当我尝试使用动态函数进行完全相同的查询时,我无法使用它。 像这样,我非常接近我的目标,但我没有使用 rec_key.srv 变量中的内容,而是 returns '''''|| rec_key.srv ||''''' :(

select * from public.test2('select ''''''''''''|| rec_key.srv ||'''''''''''' as srv ,count (*) as total from users '') as (srv varchar,total integer)') as (srv varchar,total integer)

输出=

            srv                   total
'''''|| rec_key.srv ||'''''        50
'''''|| rec_key.srv ||'''''        41
'''''|| rec_key.srv ||'''''        100

谁能告诉我如何用新函数调用变量 rec_key.srv 中的内容?

归结为:(!)

SELECT s.srv, t.*
FROM   public.connections() s
     , dblink('host=' || s.host || ' port=' || s.port || ' user=** password=** dbname=**'
            , 'SELECT count(*) FROM users') AS t(total integer);

没有包装函数,没有动态 SQL,没有游标。
只需在隐式 CROSS JOIN LATERAL.

中执行 dblink()

我还在结果中添加了 srv,就像您在第一个函数中所做的那样。无需通过 dblink 进行管道传输。

参见:

传递任意查询对SQL注入开放。请务必了解可能的影响,并仅在受信任的输入下执行。参见: