The distributed transaction Prepare broadcast fail

由于GREENPLUM是分布式数据库集群,因此,如果存储过程异常处理不当会导致真正的SQL错误信息无法显示,对开发人员产生误导,比如下面的例子

CREATE TABLE public.generate_error (
  id                INTEGER               NOT NULL  PRIMARY KEY,
  data              TEXT                  NOT NULL
);
INSERT INTO public.generate_error (id, data) VALUES (1, 'test 1');
INSERT INTO public.generate_error (id, data) VALUES (2, 'test 2');
CREATE OR REPLACE FUNCTION public.f_generate_error()
  RETURNS integer AS
$BODY$
DECLARE
BEGIN
    INSERT INTO public.generate_error (id, data) VALUES (1, 'test 1');
    RETURN 1;
EXCEPTION
    WHEN OTHERS THEN
        DECLARE
            x INT;
        BEGIN
            RAISE NOTICE 'Raised an error ...';
            RETURN -1;
        END;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE;

去执行函数

SELECT public.f_generate_error();

得到如下错误
WARNING:  The distributed transaction 'Abort [Prepared]' broadcast failed to one or more segments for gid = 1310028785-0000000049.
NOTICE:  Releasing gangs for retry broadcast.
NOTICE:  Retry of the distributed transaction 'Abort Prepared' broadcast succeeded to the segments for gid = 1310028785-0000000049.
ERROR:  The distributed transaction 'Prepare' broadcast failed to one or more segments for gid = 1310028785-0000000049. (cdbtm.c:618)
本来很简单的主键重复的错误,变成了broadcast failed,看上去很严重的错误。使得开发人员无法对真正的问题进行纠正。
这要改变一下异常处理的定义

CREATE OR REPLACE FUNCTION public.f_generate_error()
  RETURNS integer AS
$BODY$
BEGIN
    INSERT INTO public.generate_error (id, data) VALUES (1, 'test 1');
    RETURN 1;
EXCEPTION
    WHEN OTHERS THEN
            RAISE EXCEPTION 'Raised an error ...%', sqlerrm;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE;

再次执行

SELECT public.f_generate_error();

就可以得到真正导致错误原因的信息。

ERROR:  Raised an error ...duplicate key violates unique constraint "generate_error_pkey"  (seg0 roberj12-mbp:50000 pid=21389)

由于抛异常会中断执行,如果希望这个函数异常处理部分继续像原始定义那样返回-1,这样改写

CREATE OR REPLACE FUNCTION public.f_generate_error()
  RETURNS integer AS
$BODY$
BEGIN
    BEGIN
        INSERT INTO public.generate_error (id, data) VALUES (1, 'test 1');
    EXCEPTION
        WHEN OTHERS THEN
                RAISE WARNING '%', sqlerrm;
                RETURN -1;
    END;
    RETURN 1;
EXCEPTION
    WHEN OTHERS THEN
            RAISE EXCEPTION 'Raised an error ...%', sqlerrm;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE;

但是如果直接执行

poc=# SELECT public.f_generate_error();

WARNING:  Warning:duplicate key violates unique constraint "generate_error_pkey"  (seg0 roberj12-mbp:50000 pid=22127)
WARNING:  The distributed transaction 'Abort [Prepared]' broadcast failed to one or more segments for gid = 1310068719-0000000197.
NOTICE:  Releasing gangs for retry broadcast.
NOTICE:  Retry of the distributed transaction 'Abort Prepared' broadcast succeeded to the segments for gid = 1310068719-0000000197.
ERROR:  The distributed transaction 'Prepare' broadcast failed to one or more segments for gid = 1310068719-0000000197. (cdbtm.c:605)

错误依旧,这是因为函数自动提交。你可以在调用代码中引入事务控制异常处理。

poc=# begin work;
BEGIN
poc=# SELECT public.f_generate_error();
WARNING:  Warning:duplicate key violates unique constraint "generate_error_pkey"  (seg0 roberj12-mbp:50000 pid=22132)

f_generate_error

------------------

               -1

(1 row)

poc=# commit;
WARNING:  The distributed transaction 'Abort [Prepared]' broadcast failed to one or more segments for gid = 1310068719-0000000198.
NOTICE:  Releasing gangs for retry broadcast.
NOTICE:  Retry of the distributed transaction 'Abort Prepared' broadcast succeeded to the segments for gid = 1310068719-0000000198.
ERROR:  The distributed transaction 'Prepare' broadcast failed to one or more segments for gid = 1310068719-0000000198. (cdbtm.c:605)

也可以选择回滚,这时不再会产生错误信息

poc=# begin work;
BEGIN
poc=# SELECT public.f_generate_error();
WARNING:  Warning:duplicate key violates unique constraint "generate_error_pkey"  (seg0 roberj12-mbp:50000 pid=22140)

f_generate_error

------------------

               -1

(1 row)

 
poc=# rollback;
ROLLBACK
poc=#

 

 


你可能感兴趣的:(The distributed transaction Prepare broadcast fail)