reraise_issue_PG_v2.patch
text/plain
Filename: reraise_issue_PG_v2.patch
Type: text/plain
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: context
Series: patch v2
| File | + | − |
|---|---|---|
| doc/src/sgml/plpgsql.sgml | 41 | 0 |
| src/pl/plpgsql/src/pl_exec.c | 16 | 0 |
| src/pl/plpgsql/src/plpgsql.h | 2 | 0 |
| src/test/regress/expected/plpgsql.out | 1 | 0 |
*** 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 $$