PostgreSQL:处理 dblink 查询中的变量和撇号

PostgreSQL: dealing with variables and apostrophes in dblink query

我正在尝试执行 dblink,我需要将变量放入它的查询中,但问题是 dblink 执行字符串,并且在执行之前将 "converts" 变量放入该字符串中。

p_int int := 1;
p_text text;
p_apostroph text := '''';
p_sql text;

p_text := (select columnXY from table2 where id =1);

p_sql: =
'insert into table (column1,column2,column3,column4) 
 select 1
 ' || p_int  || ',
 ' || p_apostroph || p_text || p_apostroph || ',
 ''text''
 ';

dblink_exec('connection' , p_sql);

正如在代码中看到的那样,文本变量带来了问题(数组带来了噩梦),因为我已经不得不手动将我的文本变量 p_text 放在撇号之间,而且本质上我不知道它包含什么(我从另一个 table 或用户界面或我无法控制的任何其他来源填写它)。所以每次这个变量包含和撇号时,它都会以错误结束,因为字符串被破坏了。所以这意味着我将不得不想出一些复杂的字符串分析来应对所有可能性。

有没有其他方法如何将变量放入 dblink 查询而不将它们放入字符串?

PostgreSQL 11.6 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39), 64-bit

按照@a_horse_with_no_name的建议,我尝试了美元引号字符串

create table table1 (column1 int, column2 int, column3 text, column4 text);
create table table2 (column1 text, id int);
insert into table2 values ('unsafe ''',1);
insert into table2 values ('safe ',2);

create or replace function test (p_id int) returns integer as 
$body$
declare
p_int int := 1;
p_text text;
p_apostroph text := '''';
p_sql text;
begin

p_text := (select column1 from table2 where id = p_id);

p_sql:= 
$$
insert into table1(column1,column2,column3,column4) 
   select 
   1,
   $$ || p_int  || $$,
   $$ || p_apostroph || p_text || p_apostroph || $$,
   'textz'
$$ 
 ;
raise notice '%', p_sql;
perform dblink_exec('connection' , p_sql );
return 1;
end;
$body$ LANGUAGE plpgsql

select * from test (2); -- no problem
select * from test (1); -- error

[Code: 0, SQL State: 42601] ERROR: unterminated quoted string at or near "' " Kde: while executing command on unnamed dblink connection SQL statement "SELECT dblink_exec('connection' , p_sql )" PL/pgSQL function s5_text_apostrop(integer) line 22 at PERFORM

您在 INSERT 语句中忘记了一个逗号。

您的代码也容易受到 SQL 注入攻击。使用 format 来避免这种情况并使您的代码更具可读性:

p_sql: = format(
            'insert into atable (column1, column2, column3, column4)'
            'select 1, %s, %L, %L',
            p_int, p_text, 'text'
         );