首页 > 解决方案 > postgresql:测试 dblink 连接的触发器,如果​​不存在则建立

问题描述

我正在尝试在 postgresql 9.6 中设置一个触发器,当将一行插入到它自己的表中时,它将使用 dblink 将一行插入到另一个数据库中。由于这些插入量可能很大,我不想在每次插入时都连接和断开与数据库的连接,所以我希望有一个持久连接,每次插入都使用它。但我想我必须测试连接是否可用,因为很多事情都可能导致连接断开。

我的伪代码如下:

-- 1. test if named dblink connection already exists
-- 2.   if it does not, create a named dblink connection
-- 3. insert data via dblink

我到目前为止是这样的:

CREATE OR REPLACE FUNCTION db_link_trigger()
   RETURNS trigger AS
$BODY$
BEGIN
   -- 1. test if named dblink connection already exists
   IF (SELECT COALESCE('dblinktest' = ANY (dblink_get_connections()), false)) = false THEN 
      -- 2. if it does not, create a named dblink connection
      RAISE NOTICE 'dblink connection not established.  Connecting now';
      PERFORM dblink_connect('dblinktest', 'hostaddr=192.168.1.30 port=5433 dbname=otherdb user=myuser password=mypassword');
   ELSE
      RAISE NOTICE 'dblink connection already established';
   END IF;

   -- 3. insert data via dblink
   PERFORM dblink_exec('dblinktest', 'insert into mytable(data) values(''' || NEW.data || ''');');

   RETURN NEW;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;

我主要关心的是如何处理错误以及如何处理触发器的近乎同时调用。考虑两个 INSERTS 是否同时进入,并且之前没有名为 'dblinktest' 的 dblink。当第一个发现连接不存在时,它会继续设置它。然后第二个可以看到链接也没有建立并尝试连接自己,但它会失败,因为第一个会在它之前连接,它会引发错误:

ERROR:  duplicate connection name

我该如何处理这样的错误?postgresql 有类似这种受 python 启发的伪代码吗?

try:
  if dblink connection is not established:
    establish dblink connection
except 'ERROR:  duplicate connection name':
  pass # do nothing
finally:
  insert row into other db via dblink connection

标签: postgresqlexceptionerror-handlingpostgresql-9.6dblink

解决方案


您可以从此链接https://www.postgresql.org/docs/10/errcodes-appendix.html获取错误代码,这种情况是:

42710 -> 重复对象

并使用带有 EXCEPTION 子句的 PL/pgSQL BEGIN 块管理此错误

例如:

 CREATE OR REPLACE FUNCTION db_link_function()
 RETURNS void AS
 $BODY$
 declare
  rec record;
 BEGIN

 BEGIN   
  PERFORM  dblink_connect('dblinktest', 'hostaddr=127.0.0.1 port=5435 dbname=dell user=postgres password=password');
  --the EXCEPTION
  EXCEPTION
   WHEN duplicate_object THEN --code error 42710
    RAISE NOTICE 'this connections exists';

 END;
   --select data via dblink
 SELECT * FROM dblink('dblinktest','SELECT * FROM categories where category=1') AS t(cid int, cname text) into rec;
 raise notice 'value of rec: %,%', rec.cid, rec.cname;  


END;
$BODY$
LANGUAGE plpgsql;

我建议使用 FDW 而不是 dblink https://www.postgresql.org/docs/10/postgres-fdw.html


推荐阅读