在postgresql中单个函数失败时中止整个事务

在postgresql中单个函数失败时中止整个事务,postgresql,plpgsql,Postgresql,Plpgsql,我有一个主函数来调用每个子函数。如果其中一个子函数抛出错误,我希望函数回滚。如果主函数出现问题,事务将停止,但错误消息未在errorlog表中发布,则主函数可以正常工作。我希望如果子函数出现问题,我确实关心主函数的事务是否会停止并回滚所有未成功子函数的其余部分 这是我的剧本: CREATE OR REPLACE FUNCTION ecisdrdm.pr_merge_staging_tables( OUT v_ret text) RETURNS text LANGUAGE '

我有一个主函数来调用每个子函数。如果其中一个子函数抛出错误,我希望函数回滚。如果主函数出现问题,事务将停止,但错误消息未在errorlog表中发布,则主函数可以正常工作。我希望如果子函数出现问题,我确实关心主函数的事务是否会停止并回滚所有未成功子函数的其余部分

这是我的剧本:

CREATE OR REPLACE FUNCTION ecisdrdm.pr_merge_staging_tables(    OUT v_ret text)
    RETURNS text
    LANGUAGE 'plpgsql'

    COST 100
    VOLATILE  AS $BODY$

DECLARE

    v_errorcode      text;   v_errormsg       varchar(512);    v_module         varchar(32) = 'pr_merge_staging_tables';    v_host          varchar(32) = inet_server_addr();

begin

    PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0', 'Starting MERGE Process' );       begin   v_ret = '0';

    if v_ret = '0' then            ---     --- Perform the merge on APPLICATION_CDIM    ---
            PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0', 'Started merging STG_APPLICATION_CDIM' );
                PERFORM ecisdrdm.pr_mig_stg_application_cdim();         -- TODO: INVESTIGATE HOW TO RECEIVE THE OUT PARAMETER RETRUNED FROM FUNCTION
                PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0', 'Finished merging STG_APPLICATION_CDIM' );
            end if;


    ---  2. STG_BNFT_CURR_FACT  ----
        if v_ret = '0' then

    ---     --- Perform the merge on BNFT_CURR_FACT     ---

        PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0', 'Started merging STG_BNFT_CURR_FACT' );
                PERFORM ecisdrdm.pr_mig_stg_bnft_curr_fact();       -- TODO: INVESTIGATE HOW TO RECEIVE THE OUT PARAMETER RETRUNED FROM FUNCTION

        PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0', 'Finished merging STG_BNFT_CURR_FACT' );
            end if;


    ----    --  3. STG_BNFT_FACT    ----
        if v_ret = '0' then     ---     --- Perform the merge on BNFT_FACT  ---
            PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0', 'Started merging STG_BNFT_FACT' );
                PERFORM ecisdrdm.pr_mig_stg_bnft_fact();        -- TODO: INVESTIGATE HOW TO RECEIVE THE OUT PARAMETER RETRUNED FROM FUNCTION        v_ret = '0';
                PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0', 'Finished merging STG_BNFT_FACT' );       end if;


    ----    --  4. STG_BNFT_HIST_ACTN_LDIM  ----
        if v_ret = '0' then     ---     --- Perform the merge on BNFT_HIST_ACTN_LDIM    ---
            PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0', 'Started merging STG_BNFT_HIST_ACTN_LDIM ' );
                PERFORM ecisdrdm.pr_mig_stg_bnft_hist_actn_ldim ();         -- TODO: INVESTIGATE HOW TO RECEIVE THE OUT PARAMETER RETRUNED FROM FUNCTION
                PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0', 'Finished merging STG_BNFT_HIST_ACTN_LDIM ' );

    end if;


    ----    --  5. STG_CNTRY_ST_CDIM    ----
        if v_ret = '0' then     ---     --- Perform the merge on CNTRY_ST_CDIM  ---
            PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0','Started merging STG_CNTRY_ST_CDIM ' );
                PERFORM ecisdrdm.pr_mig_stg_cntry_st_cdim();        -- TODO: INVESTIGATE HOW TO RECEIVE THE OUT PARAMETER RETRUNED FROM FUNCTION
                PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0', 'Finished merging STG_CNTRY_ST_CDIM ');       end if;


    ----    --  6. STG_FRM_CDIM     ----
        if v_ret = '0' then     ---     --- Perform the merge on FRM_CDIM   ---
            PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0', 'Started merging STG_FRM_CDIM ' );
                PERFORM ecisdrdm.pr_mig_stg_frm_cdim();         -- TODO: INVESTIGATE HOW TO RECEIVE THE OUT PARAMETER RETRUNED FROM FUNCTION
                        PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0', 'Finished merging STG_FRM_CDIM ' );       end if;


    ----    --  7. STG_G28  ----
        if v_ret = '0' then     ---     --- Perform the merge on G28    ---
            PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0','Started merging STG_G28 ' );
                PERFORM ecisdrdm.pr_mig_stg_g28();      -- TODO: INVESTIGATE HOW TO RECEIVE THE OUT PARAMETER RETRUNED FROM FUNCTION
                PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0', 'Finished merging STG_G28 ' );        end if;


    ----    --  8. STG_PRTY_CDIM    ----
        if v_ret = '0' then     ---     --- Perform the merge on PRTY_CDIM  ---
            PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0', 'Started merging STG_PRTY_CDIM ' );
                PERFORM ecisdrdm.pr_mig_stg_prty_cdim();        -- TODO: INVESTIGATE HOW TO RECEIVE THE OUT PARAMETER RETRUNED FROM FUNCTION
                PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0', 'Finished merging STG_PRTY_CDIM ' );      end if;


    ----    --  9. STG_PRTY_TYP_LKUP    ----
        if v_ret = '0' then     ---     --- Perform the merge on PRTY_TYP_LKUP  ---
            PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0', 'Started merging STG_PRTY_TYP_LKUP ' );
                PERFORM ecisdrdm.pr_mig_stg_prty_typ_lkup();        -- TODO: INVESTIGATE HOW TO RECEIVE THE OUT PARAMETER RETRUNED FROM FUNCTION
            PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0','Finished merging STG_ PRTY_TYP_LKUP ' );      end if;

    ----    --  10. STG_R2I864  ----
        if v_ret = '0' then     ---     --- Perform the merge on R2I864     ---
            PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0', 'Started merging STG_R2I864 ' );
                PERFORM ecisdrdm.pr_mig_stg_r2i864();       -- TODO: INVESTIGATE HOW TO RECEIVE THE OUT PARAMETER RETRUNED FROM FUNCTION
                PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0', 'Finished merging STG_R2I864 ' );         end if;

    ----    --  11. STG_REMIT   ----
        if v_ret = '0' then     ---     --- Perform the merge on REMIT  ---
            PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0', 'Started merging STG_REMIT ' );
                PERFORM ecisdrdm.pr_mig_stg_remit();        -- TODO: INVESTIGATE HOW TO RECEIVE THE OUT PARAMETER RETRUNED FROM FUNCTION
                PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0','Finished merging STG_ REMIT ' );      end if;

    ----    --  12. STG_SRC_SYS_CDIM    ----
        if v_ret = '0' then     ---     --- Perform the merge on SRC_SYS_CDIM   ---
            PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0','Started merging STG_SRC_SYS_CDIM ' );
                PERFORM ecisdrdm.pr_mig_stg_src_sys_cdim();         -- TODO: INVESTIGATE HOW TO RECEIVE THE OUT PARAMETER RETRUNED FROM FUNCTION
                PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0',  'Finished merging STG_SRC_SYS_CDIM ' );      end if;


    ----    --  13. STG_SVC_CTR_CDIM    ----
        if v_ret = '0' then     ---     --- Perform the merge on SVC_CTR_CDIM   ---
            PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0', 'Started merging STG_SVC_CTR_CDIM ' );
                PERFORM ecisdrdm.pr_mig_stg_svc_ctr_cdim();         -- TODO: INVESTIGATE HOW TO RECEIVE THE OUT PARAMETER RETRUNED FROM FUNCTION
                PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0','Finished merging STG_SVC_CTR_CDIM ' );        end if;


    ----    --  14. STG_USCIS_EMP_CDIM  ----
        if v_ret = '0' then     ---     --- Perform the merge on USCIS_EMP_CDIM     ---
            PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0','Started merging STG_USCIS_EMP_CDIM ' );
                PERFORM ecisdrdm.pr_mig_stg_uscis_emp_cdim_cd ();       -- TODO: INVESTIGATE HOW TO RECEIVE THE OUT PARAMETER RETRUNED FROM FUNCTION
                PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0','Finished merging STG_USCIS_EMP_CDIM ' );      end if;


---
--- This does the final commit or rollback for the entire merge process.
---

    if v_errorcode = '0' then       PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0', 'Finished MERGE PROCESS - COMMIT WORK' );         /*  commit work; */     else        PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, '0', 'Finished MERGE PROCESS - ROLLBACK WORK ' );      /*  rollback work; */       ROLLBACK;       end if;

----
--- Exception error handler
----

exception    when others then
        v_errorcode := SQLSTATE;
        v_errormsg  := SQLERRM;         v_ret       := v_errorcode;

    PERFORM ecisdrdm.pr_write_error_log( CURRENT_USER, v_host, v_module, v_errorcode, v_errormsg);   end;

END; $BODY$;


我确实希望得到在应用程序级别发生的违反通知,写入errorlog表并回滚,无论哪个函数失败,不仅仅是继续事务函数的其余部分。

从您的级联文字中,我假设您希望撤消函数中发生的所有操作并记录错误消息。其工作如下:

BEGIN
   PERFORM function1();
   PERFORM function2();
   /* more work */
EXCEPTION
   WHEN OTHERS THEN
      INSERT INTO log_table VALUES (...);
END;

BEGIN
EXCEPTION
之间的所有内容都将在子事务中运行。如果抛出任何异常,整个子事务都将回滚并记录错误。

是的,这就是我所做的,但每个函数都使用“If…end If;”语句。当抛出异常时,它们都不起作用。问题是如果我对每个子函数使用“if…end if”语句,即使其中一个是error,主函数也会发布所有start。。。结束功能成功。如果我在主函数中出错/键入错误,它将在错误日志中抛出一个错误并停止,而不发布启动过程,诸如此类……诸如此类与oracle过程不同,甚至与从ora2pg转换的脚本不同,为了使其正常工作,我已经进行了大量修复。如果没有任何错误,它就工作,如果函数和日志中的一个有错误消息,则不正确。甚至我也删除了“如果……结束如果”这句话。如果你深吸一口气,花点时间,试着用简单明了的英语写一篇描述,那就太好了。我听不懂你说的。我说我确实像你昨天建议的那样尝试过,如果抛出任何异常,根本就不会回滚。即使引发一个异常,子事务仍在继续运行。如果抛出一个子事务,我希望回滚整个子事务。