aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/pl/plpgsql/src/pl_exec.c46
-rw-r--r--src/pl/plpgsql/src/plpgsql.h6
-rw-r--r--src/test/regress/expected/plpgsql.out31
-rw-r--r--src/test/regress/sql/plpgsql.sql25
4 files changed, 85 insertions, 23 deletions
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index e1f48e3d75d..a1ff9120f47 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.261 2010/07/06 19:19:01 momjian Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.262 2010/08/09 02:25:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -327,10 +327,6 @@ 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),
@@ -695,10 +691,6 @@ 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),
@@ -1019,6 +1011,7 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
MemoryContext oldcontext = CurrentMemoryContext;
ResourceOwner oldowner = CurrentResourceOwner;
ExprContext *old_eval_econtext = estate->eval_econtext;
+ ErrorData *save_cur_error = estate->cur_error;
estate->err_text = gettext_noop("during statement block entry");
@@ -1130,6 +1123,12 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
unpack_sql_state(edata->sqlerrcode));
assign_text_var(errm_var, edata->message);
+ /*
+ * Also set up cur_error so the error data is accessible
+ * inside the handler.
+ */
+ estate->cur_error = edata;
+
estate->err_text = NULL;
rc = exec_stmts(estate, exception->action);
@@ -1141,14 +1140,17 @@ 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;
}
}
+ /*
+ * Restore previous state of cur_error, whether or not we executed
+ * a handler. This is needed in case an error got thrown from
+ * some inner block's exception handler.
+ */
+ estate->cur_error = save_cur_error;
+
/* If no match found, re-throw the error */
if (e == NULL)
ReThrowError(edata);
@@ -1156,6 +1158,8 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
FreeErrorData(edata);
}
PG_END_TRY();
+
+ Assert(save_cur_error == estate->cur_error);
}
else
{
@@ -1177,7 +1181,6 @@ 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:
@@ -1599,7 +1602,6 @@ exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
break;
case PLPGSQL_RC_RETURN:
- case PLPGSQL_RC_RERAISE:
return rc;
default:
@@ -1663,7 +1665,6 @@ exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
break;
case PLPGSQL_RC_RETURN:
- case PLPGSQL_RC_RERAISE:
return rc;
default:
@@ -1782,8 +1783,7 @@ 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)
+ if (rc == PLPGSQL_RC_RETURN)
break; /* break out of the loop */
else if (rc == PLPGSQL_RC_EXIT)
{
@@ -2437,7 +2437,14 @@ 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 (estate->cur_error != NULL)
+ ReThrowError(estate->cur_error);
+ /* oops, we're not inside a handler */
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("RAISE without parameters cannot be used outside an exception handler")));
+ }
if (stmt->condname)
{
@@ -2637,6 +2644,7 @@ plpgsql_estate_setup(PLpgSQL_execstate *estate,
estate->rettupdesc = NULL;
estate->exitlabel = NULL;
+ estate->cur_error = NULL;
estate->tuple_store = NULL;
if (rsi)
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index 16e073c2109..488c85bd898 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.130 2010/02/26 02:01:35 momjian Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.131 2010/08/09 02:25:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -115,8 +115,7 @@ enum
PLPGSQL_RC_OK,
PLPGSQL_RC_EXIT,
PLPGSQL_RC_RETURN,
- PLPGSQL_RC_CONTINUE,
- PLPGSQL_RC_RERAISE
+ PLPGSQL_RC_CONTINUE
};
/* ----------
@@ -699,6 +698,7 @@ typedef struct PLpgSQL_execstate
TupleDesc rettupdesc;
char *exitlabel; /* the "target" label of the current EXIT or
* CONTINUE stmt, if any */
+ ErrorData *cur_error; /* current exception handler's error */
Tuplestorestate *tuple_store; /* SRFs accumulate results here */
MemoryContext tuple_store_cxt;
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index f101108aab2..34ad4d86516 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -2312,6 +2312,35 @@ $$ language plpgsql;
select raise_test2(10);
ERROR: too few parameters specified for RAISE
CONTEXT: PL/pgSQL function "raise_test2" line 3 at RAISE
+-- Test re-RAISE inside a nested exception block. This case is allowed
+-- by Oracle's PL/SQL but was handled differently by PG before 9.1.
+CREATE FUNCTION reraise_test() RETURNS void AS $$
+BEGIN
+ BEGIN
+ RAISE syntax_error;
+ EXCEPTION
+ WHEN syntax_error THEN
+ BEGIN
+ raise notice 'exception % thrown in inner block, reraising', sqlerrm;
+ RAISE;
+ EXCEPTION
+ WHEN OTHERS THEN
+ raise notice 'RIGHT - exception % caught in inner block', sqlerrm;
+ END;
+ END;
+EXCEPTION
+ WHEN OTHERS THEN
+ raise notice 'WRONG - exception % caught in outer block', sqlerrm;
+END;
+$$ LANGUAGE plpgsql;
+SELECT reraise_test();
+NOTICE: exception syntax_error thrown in inner block, reraising
+NOTICE: RIGHT - exception syntax_error caught in inner block
+ reraise_test
+--------------
+
+(1 row)
+
--
-- reject function definitions that contain malformed SQL queries at
-- compile-time, where possible
@@ -3577,7 +3606,7 @@ end;
$$ language plpgsql;
select raise_test();
ERROR: RAISE without parameters cannot be used outside an exception handler
-CONTEXT: PL/pgSQL function "raise_test"
+CONTEXT: PL/pgSQL function "raise_test" line 3 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 $$
diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql
index 612e92d21be..48496f51996 100644
--- a/src/test/regress/sql/plpgsql.sql
+++ b/src/test/regress/sql/plpgsql.sql
@@ -1966,6 +1966,31 @@ $$ language plpgsql;
select raise_test2(10);
+-- Test re-RAISE inside a nested exception block. This case is allowed
+-- by Oracle's PL/SQL but was handled differently by PG before 9.1.
+
+CREATE FUNCTION reraise_test() RETURNS void AS $$
+BEGIN
+ BEGIN
+ RAISE syntax_error;
+ EXCEPTION
+ WHEN syntax_error THEN
+ BEGIN
+ raise notice 'exception % thrown in inner block, reraising', sqlerrm;
+ RAISE;
+ EXCEPTION
+ WHEN OTHERS THEN
+ raise notice 'RIGHT - exception % caught in inner block', sqlerrm;
+ END;
+ END;
+EXCEPTION
+ WHEN OTHERS THEN
+ raise notice 'WRONG - exception % caught in outer block', sqlerrm;
+END;
+$$ LANGUAGE plpgsql;
+
+SELECT reraise_test();
+
--
-- reject function definitions that contain malformed SQL queries at
-- compile-time, where possible