Thread

  1. Issue with ReRaise in PG

    Piyush Newe <piyush.newe@enterprisedb.com> — 2010-04-23T09:30:42Z

    Hi,
    
    Please consider the following test case
    
    > CREATE OR REPLACE FUNCTION raisetest() returns void AS $$
     BEGIN
       BEGIN
           RAISE syntax_error;
       EXCEPTION
           WHEN syntax_error THEN
               BEGIN
                   raise notice 'exception thrown in inner block, reraising';
                   RAISE;
               EXCEPTION
                   WHEN OTHERS THEN
                       raise notice 'RIGHT - exception caught in innermost
    block';
               END;
       END;
     EXCEPTION
       WHEN OTHERS THEN
           raise notice 'WRONG - exception caught in outer block';
     END;
    $$ LANGUAGE plpgsql;
    
    > select raisetest();
    NOTICE:  exception thrown in inner block, reraising
    NOTICE:  WRONG - exception caught in outer block
    block
     raisetest
    -----------
    
    (1 row)
    
    
    The output of the above function seems to be wrong. Ideally the Exception
    should have caught in the inner most block instead of the outer block.
    
    Below I am sharing my obsevation while debuging this issue.
    When we give RAISE without the exception name statement, it is internally
    returning PLPGSQL_RC_RERAISE instead of jumping to the EXCEPTION block of
    the current Begin-End Block. This will force engine to eliminate/skip the
    current block's EXCEPTION block. This is the reason its got caught in the
    next exception block.
    
    To fix this, instead of returning PLPGSQL_RC_RERAISE from the function, we
    will rethrow the exception if their is no EXCEPTION name given to the RAISE
    statement. When their is RAISE (without exception name) statement, it is
    been assume that their must be some exception already raised earlier. We are
    now storing the 'errordata' into the 'estate' structure, while raising the
    exception.
    
    Now since we are not returning PLPGSQL_RC_RERAISE statement, I have also
    removed the related redundunt code in the pl_exec.c.
    
    The testcase mentioned above is behaving correctly like
    
    postgres=# select raisetest();
    NOTICE:  exception thrown in inner block, reraising
    NOTICE:  RIGHT - exception caught in innermost
    block
     raisetest
    -----------
    
    (1 row)
    
    Please find attached patch generated on the current branch to fix the
    problem.
    
    -- 
    Piyush S Newe
    Principal Engineer
    EnterpriseDB
    office: +91 20 3058 9500
    www.enterprisedb.com
    
    Website: www.enterprisedb.com
    EnterpriseDB Blog: http://blogs.enterprisedb.com/
    Follow us on Twitter: http://www.twitter.com/enterprisedb
    
    This e-mail message (and any attachment) is intended for the use of the
    individual or entity to whom it is addressed. This message contains
    information from EnterpriseDB Corporation that may be privileged,
    confidential, or exempt from disclosure under applicable law. If you are not
    the intended recipient or authorized to receive this for the intended
    recipient, any use, dissemination, distribution, retention, archiving, or
    copying of this communication is strictly prohibited. If you have received
    this e-mail in error, please notify the sender immediately by reply e-mail
    and delete this message.
    
  2. Re: Issue with ReRaise in PG

    Tom Lane <tgl@sss.pgh.pa.us> — 2010-04-23T15:57:24Z

    Piyush Newe <piyush.newe@enterprisedb.com> writes:
    > Please consider the following test case
    
    > CREATE OR REPLACE FUNCTION raisetest() returns void AS $$
    >  BEGIN
    >    BEGIN
    >        RAISE syntax_error;
    >    EXCEPTION
    >        WHEN syntax_error THEN
    >            BEGIN
    >                raise notice 'exception thrown in inner block, reraising';
    >                RAISE;
    >            EXCEPTION
    >                WHEN OTHERS THEN
    >                    raise notice 'RIGHT - exception caught in innermost
    > block';
    >            END;
    >    END;
    >  EXCEPTION
    >    WHEN OTHERS THEN
    >        raise notice 'WRONG - exception caught in outer block';
    >  END;
    > $$ LANGUAGE plpgsql;
    
    > select raisetest();
    > NOTICE:  exception thrown in inner block, reraising
    > NOTICE:  WRONG - exception caught in outer block
    
    RAISE without parameters is only allowed inside an exception handler,
    and what it throws is that handler's exception.  In this example, it is
    within an exception handler ---- of the outer block.  So it's allowed,
    but it re-throws from that handler.
    
    We could possibly make the above case throw an "improperly placed RAISE"
    error instead of doing what it does now, but I don't think there is a
    good argument for having it do what you propose.
    
    			regards, tom lane
    
    
  3. Re: Issue with ReRaise in PG

    Heikki Linnakangas <heikki.linnakangas@enterprisedb.com> — 2010-04-23T16:06:50Z

    Tom Lane wrote:
    > Piyush Newe <piyush.newe@enterprisedb.com> writes:
    >> Please consider the following test case
    > 
    >> CREATE OR REPLACE FUNCTION raisetest() returns void AS $$
    >>  BEGIN
    >>    BEGIN
    >>        RAISE syntax_error;
    >>    EXCEPTION
    >>        WHEN syntax_error THEN
    >>            BEGIN
    >>                raise notice 'exception thrown in inner block, reraising';
    >>                RAISE;
    >>            EXCEPTION
    >>                WHEN OTHERS THEN
    >>                    raise notice 'RIGHT - exception caught in innermost
    >> block';
    >>            END;
    >>    END;
    >>  EXCEPTION
    >>    WHEN OTHERS THEN
    >>        raise notice 'WRONG - exception caught in outer block';
    >>  END;
    >> $$ LANGUAGE plpgsql;
    > 
    >> select raisetest();
    >> NOTICE:  exception thrown in inner block, reraising
    >> NOTICE:  WRONG - exception caught in outer block
    > 
    > RAISE without parameters is only allowed inside an exception handler,
    > and what it throws is that handler's exception.  In this example, it is
    > within an exception handler ---- of the outer block.  So it's allowed,
    > but it re-throws from that handler.
    > 
    > We could possibly make the above case throw an "improperly placed RAISE"
    > error instead of doing what it does now, but I don't think there is a
    > good argument for having it do what you propose.
    
    It's worth noting that RAISE without parameters was added to mimic the
    corresponding RAISE command on Oracle, and on Oracle Piyush's test case
    works as he says.
    
    -- 
      Heikki Linnakangas
      EnterpriseDB   http://www.enterprisedb.com