使用 dblink 复制新数据的函数中出现语法错误

Syntax error in function using dblink to replicate new data

我从来没有在 Postgres 中创建过函数,我按照一些教程制作了这段代码,但我不知道为什么会出错,控制台中的错误是:

"syntax error at or near "SELECT"
LINE 5:     SELECT public.dblink_connect('hostaddr=127.0.0.1 port=54...

我在 Ubuntu 上使用 9.3.6 版。

CREATE OR REPLACE FUNCTION fn_replicate_insertof_students()
      RETURNS text AS
    $BODY$
    BEGIN
    SELECT public.dblink_connect('hostaddr=127.0.0.1 port=5433 dbname=Utiles user=postgres password=Mypass');

INSERT INTO res_partner (company_id,name,lang,comment,street,supplier,city,zip,country_id,email,phone,date,customer,mobile,ref,state_id,opt_out,city_id,l10n_mx_city2,l10n_mx_street3,l10n_mx_street4,notification_email_send,type,street2,active)
                        VALUES  (1,NEW.name,'es_MX',NEW.comment,NEW.street,false,NEW.city,NEW.zip,NEW.country_id,NEW.email,NEW.phone,NEW.date,true,NEW.mobile,NEW.ref,NEW.state_id,false,NEW.city_id,NEW.l10n_mx_city2,NEW.l10n_mx_street3,NEW.l10n_mx_street4,NEW.notification_email_send,NEW.type,NEW.street2,NEW.active));

SELECT public.dblink_disconnect();

END;
$BODY$ LANGUAGE sql VOLATILE SECURITY DEFINER
SET search_path=myschema, pg_temp;


CREATE TRIGGER tr_replicate_insertof_students
  AFTER INSERT 
  ON res_partner
  FOR EACH ROW
  EXECUTE PROCEDURE fn_replicate_insertof_students();

您已将函数标记为 LANGUAGE sql,这仅适用于包含单个 SQL 语句的函数。这个函数写在LANGUAGE plpgsql.

它仍然会抱怨 SELECT,因为 plpgsql 要求您实际对 SELECT 的结果执行某些操作。您需要将 SELECT 替换为 PERFORM,以明确表示您要丢弃结果。

,但还有更多:

您的 search_path 实际上 做对了 pg_catalog 自动包含在 first 除非您明确将其放在其他位置。

  • How does the search_path influence identifier resolution and the "current schema"

更重要的是,整个函数的当前形式毫无意义。您打开了一个 dblink 连接,但您没有使用它。看起来你想加入 dblink_exec()。但是您需要首先将查询字符串与 NEW 形式的值连接起来,因为 NEW 在虫洞的另一边是不可见的。所以你自己就有了一个动态 SQL 的很好的例子。对于初学者来说,这是一个相当陡峭的开始!

最近在 dba.SE:

上的相关回答中详细的代码示例和 dblink 函数的解释

此外,这必须是 trigger function 才能在触发器中使用。
您的函数可以这样工作:

CREATE OR REPLACE FUNCTION fn_replicate_insertof_students()
  RETURNS <b>trigger</b> AS
$func$
BEGIN
<b>PERFORM</b> public.dblink_connect('hostaddr=127.0.0.1 port=5433 
                dbname=Utiles user=postgres password=Mypass');

<b>PERFORM public.dblink_exec(format(
   $f$INSERT INTO res_partner (company_id, name, lang, comment, ... )
      VALUES  (1, %L, 'es_MX', %L, ... )$f$
    , NEW.name, NEW.comment, ... ));</b>

<b>PERFORM</b> public.dblink_disconnect();

<b>RETURN NULL;</b>  -- only ok for AFTER trigger

END
$func$ LANGUAGE <b>plpgsql</b> VOLATILE SECURITY DEFINER
                        SET search_path=myschema, pg_temp;
ALTER FUNCTION fn_replicate_insertof_students() OWNER TO postgres;  -- guessing

还要确保为 SECURITY DEFINER function.

设置所有者权限

考虑在目标服务器上使用 FOREIGN SERVERUSER MAPPING 和密码文件。 above link.

中的详细信息

整个想法是一个相当昂贵的复制特例。对于 table 的一些插入,这没问题,但是有 better solutions for massive load.