I'd like to mark this as Ready for Committer :)

Review below.

Cheers,
David.

== Submission review ==

* Is the patch in context diff format?

    Yes.

* Does it apply cleanly to the current CVS HEAD?

    Yes, with a few offsets.

    patch -p0 < ../reraise_issue_PG_v1.patch 
    patching file src/pl/plpgsql/src/pl_exec.c
    Hunk #9 succeeded at 2427 (offset 2 lines).
    Hunk #10 succeeded at 2663 (offset 2 lines).
    patching file src/pl/plpgsql/src/plpgsql.h

* Does it include reasonable tests, necessary doc patches, etc?

    No.  Please find new patch attached with one test and one change
    to the docs.

== Usability review ==  

Read what the patch is supposed to do, and consider:

* Does the patch actually implement that? 

    Yes.

* Do we want that? 

    While the discussion was not long or extensive, the consensus
    seemed to be yes.

* Do we already have it? 

    No.

* Does it follow SQL spec, or the community-agreed behavior? 

    Not applicable, as far as I understand the spec.

* Does it include pg_dump support (if applicable)?

    Not applicable.

* Are there dangers? 

    Old code may depend on the previous behavior.

* Have all the bases been covered?

== Feature test ==

Apply the patch, compile it and test:

* Does the feature work as advertised?

    Yes.

* Are there corner cases the author has failed to consider?

    Not that I've found.

* Are there any assertion failures or crashes?

    No.

**Review should be done with the ''configure'' options ''--enable-cassert'' and 
''--enable-debug'' turned on; see [[Working with CVS]] for a full example.  
Those will help find issues with the code that might otherwise be missed.  A 
copy of PostgreSQL built using these parameters will be substantially slower 
than one built without them.  If you're working on something 
performance-related, such as testing whether a patch slows anything down, be 
sure to build without these flags before testing execution speed.  You can turn 
off the assert testing, the larger of the slowdowns, at server start time by 
putting ''debug_assertions = false'' in your postgresql.conf.  See 
[http://www.postgresql.org/docs/current/static/runtime-config-developer.html 
Developer Options] for more details about that setting; it defaults to true in 
builds done with --enable-cassert.

== Performance review ==

* Does the patch slow down simple tests? 

    Not that I've found, although anything involving exceptions in
    PL/pgsql performs pretty poorly in stock PostgreSQL.

* If it claims to improve performance, does it?

    It makes no such claim.

* Does it slow down other things?

    Not that I've found.

== Coding review ==

Read the changes to the code in detail and consider:

* Does it follow the project 
[http://developer.postgresql.org/pgdocs/postgres/source.html coding 
guidelines]? 

    Yes.

* Are there portability issues? 

    Not that I can see.

* Will it work on Windows/BSD etc? 

    No reason it shouldn't.  Haven't tested those platforms.

* Are the comments sufficient and accurate?

    Yes.

* Does it do what it says, correctly?

    Yes, as far as I can tell.

* Does it produce compiler warnings?

    No.

* Can you make it crash?

    No.

== Architecture review ==

Consider the changes to the code in the context of the project as a whole:

* Is everything done in a way that fits together coherently with other 
features/modules? 

    Yes.

* Are there interdependencies that can cause problems?

    Not that I've found, except as noted above re: apps based on the
    previous behavior.

-- 
David Fetter <da...@fetter.org> http://fetter.org/
Phone: +1 415 235 3778  AIM: dfetter666  Yahoo!: dfetter
Skype: davidfetter      XMPP: david.fet...@gmail.com
iCal: webcal://www.tripit.com/feed/ical/people/david74/tripit.ics

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate
*** a/doc/src/sgml/plpgsql.sgml
--- b/doc/src/sgml/plpgsql.sgml
***************
*** 2374,2379 **** SELECT merge_db(1, 'dennis');
--- 2374,2420 ----
  
      </para>
      </example>
+     <example id="plpgsql-reraise-example">
+     <title>Re-Raising Exceptions</title>
+     <para>
+ 
+     This example shows how to re-raise an exception, which helps you
+     write more complex exception-handling in your functions:
+ <programlisting>
+ CREATE OR REPLACE FUNCTION raisetest()
+ RETURNS VOID
+ LANGUAGE plpgsql
+ 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;
+ $$;
+ 
+ select raisetest();
+ NOTICE:  exception thrown in inner block, reraising
+ NOTICE:  RIGHT - exception caught in innermost block
+  raisetest 
+ -----------
+  
+ (1 row)
+ </programlisting>
+ 
+     </para>
+     </example>
    </sect2>
    </sect1>
  
*** a/src/pl/plpgsql/src/pl_exec.c
--- b/src/pl/plpgsql/src/pl_exec.c
***************
*** 327,336 **** plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo 
fcinfo)
                        ereport(ERROR,
                                        (errcode(ERRCODE_SYNTAX_ERROR),
                                         errmsg("CONTINUE cannot be used 
outside a loop")));
-               else if (rc == PLPGSQL_RC_RERAISE)
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_SYNTAX_ERROR),
-                                        errmsg("RAISE without parameters 
cannot be used outside an exception handler")));
                else
                        ereport(ERROR,
                           
(errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT),
--- 327,332 ----
***************
*** 695,704 **** plpgsql_exec_trigger(PLpgSQL_function *func,
                        ereport(ERROR,
                                        (errcode(ERRCODE_SYNTAX_ERROR),
                                         errmsg("CONTINUE cannot be used 
outside a loop")));
-               else if (rc == PLPGSQL_RC_RERAISE)
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_SYNTAX_ERROR),
-                                        errmsg("RAISE without parameters 
cannot be used outside an exception handler")));
                else
                        ereport(ERROR,
                           
(errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT),
--- 691,696 ----
***************
*** 1132,1138 **** exec_stmt_block(PLpgSQL_execstate *estate, 
PLpgSQL_stmt_block *block)
--- 1124,1136 ----
  
                                        estate->err_text = NULL;
  
+                                       /*
+                                        * Set last_caught_error for the 
duration of the
+                                        * exception handler, so that "RAISE;" 
can rethrow it.
+                                        */
+                                       estate->last_caught_error = edata;
                                        rc = exec_stmts(estate, 
exception->action);
+                                       estate->last_caught_error = NULL;
  
                                        free_var(state_var);
                                        state_var->value = (Datum) 0;
***************
*** 1141,1150 **** exec_stmt_block(PLpgSQL_execstate *estate, 
PLpgSQL_stmt_block *block)
                                        errm_var->value = (Datum) 0;
                                        errm_var->isnull = true;
  
-                                       /* re-throw error if requested by 
handler */
-                                       if (rc == PLPGSQL_RC_RERAISE)
-                                               ReThrowError(edata);
- 
                                        break;
                                }
                        }
--- 1139,1144 ----
***************
*** 1177,1183 **** exec_stmt_block(PLpgSQL_execstate *estate, 
PLpgSQL_stmt_block *block)
                case PLPGSQL_RC_OK:
                case PLPGSQL_RC_RETURN:
                case PLPGSQL_RC_CONTINUE:
-               case PLPGSQL_RC_RERAISE:
                        return rc;
  
                case PLPGSQL_RC_EXIT:
--- 1171,1176 ----
***************
*** 1599,1605 **** exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop 
*stmt)
                                break;
  
                        case PLPGSQL_RC_RETURN:
-                       case PLPGSQL_RC_RERAISE:
                                return rc;
  
                        default:
--- 1592,1597 ----
***************
*** 1663,1669 **** exec_stmt_while(PLpgSQL_execstate *estate, 
PLpgSQL_stmt_while *stmt)
                                break;
  
                        case PLPGSQL_RC_RETURN:
-                       case PLPGSQL_RC_RERAISE:
                                return rc;
  
                        default:
--- 1655,1660 ----
***************
*** 1782,1789 **** exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori 
*stmt)
                 */
                rc = exec_stmts(estate, stmt->body);
  
!               if (rc == PLPGSQL_RC_RETURN ||
!                       rc == PLPGSQL_RC_RERAISE)
                        break;                          /* break out of the 
loop */
                else if (rc == PLPGSQL_RC_EXIT)
                {
--- 1773,1779 ----
                 */
                rc = exec_stmts(estate, stmt->body);
  
!               if (rc == PLPGSQL_RC_RETURN)
                        break;                          /* break out of the 
loop */
                else if (rc == PLPGSQL_RC_EXIT)
                {
***************
*** 2437,2443 **** exec_stmt_raise(PLpgSQL_execstate *estate, 
PLpgSQL_stmt_raise *stmt)
        /* RAISE with no parameters: re-throw current exception */
        if (stmt->condname == NULL && stmt->message == NULL &&
                stmt->options == NIL)
!               return PLPGSQL_RC_RERAISE;
  
        if (stmt->condname)
        {
--- 2427,2440 ----
        /* RAISE with no parameters: re-throw current exception */
        if (stmt->condname == NULL && stmt->message == NULL &&
                stmt->options == NIL)
!       {
!               if (estate->last_caught_error == NULL)
!                       ereport(ERROR,
!                               (errcode(ERRCODE_SYNTAX_ERROR),
!                                errmsg("RAISE without parameters cannot be 
used outside an exception handler")));
! 
!               ReThrowError(estate->last_caught_error);
!       }
  
        if (stmt->condname)
        {
***************
*** 2666,2671 **** plpgsql_estate_setup(PLpgSQL_execstate *estate,
--- 2663,2669 ----
        estate->err_text = NULL;
  
        estate->plugin_info = NULL;
+       estate->last_caught_error = NULL;
  
        /*
         * Create an EState and ExprContext for evaluation of simple 
expressions.
*** a/src/pl/plpgsql/src/plpgsql.h
--- b/src/pl/plpgsql/src/plpgsql.h
***************
*** 115,122 **** enum
        PLPGSQL_RC_OK,
        PLPGSQL_RC_EXIT,
        PLPGSQL_RC_RETURN,
!       PLPGSQL_RC_CONTINUE,
!       PLPGSQL_RC_RERAISE
  };
  
  /* ----------
--- 115,121 ----
        PLPGSQL_RC_OK,
        PLPGSQL_RC_EXIT,
        PLPGSQL_RC_RETURN,
!       PLPGSQL_RC_CONTINUE
  };
  
  /* ----------
***************
*** 721,726 **** typedef struct PLpgSQL_execstate
--- 720,726 ----
        const char *err_text;           /* additional state info */
  
        void       *plugin_info;        /* reserved for use by optional plugin 
*/
+       ErrorData       *last_caught_error;
  } PLpgSQL_execstate;
  
  
*** a/src/test/regress/expected/plpgsql.out
--- b/src/test/regress/expected/plpgsql.out
***************
*** 3577,3583 **** end;
  $$ language plpgsql;
  select raise_test();
  ERROR:  RAISE without parameters cannot be used outside an exception handler
! CONTEXT:  PL/pgSQL function "raise_test"
  -- check cases where implicit SQLSTATE variable could be confused with
  -- SQLSTATE as a keyword, cf bug #5524
  create or replace function raise_test() returns void as $$
--- 3577,3583 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  RAISE without parameters cannot be used outside an exception handler
! CONTEXT:  PL/pgSQL function "raise_test" line 2 at RAISE
  -- check cases where implicit SQLSTATE variable could be confused with
  -- SQLSTATE as a keyword, cf bug #5524
  create or replace function raise_test() returns void as $$
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to