aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/utils/error/elog.c38
-rw-r--r--src/include/utils/elog.h3
-rw-r--r--src/pl/plpgsql/src/gram.y41
-rw-r--r--src/pl/plpgsql/src/pl_comp.c8
-rw-r--r--src/pl/plpgsql/src/pl_exec.c61
-rw-r--r--src/pl/plpgsql/src/pl_funcs.c4
-rw-r--r--src/pl/plpgsql/src/plpgsql.h11
-rw-r--r--src/test/regress/expected/plpgsql.out54
-rw-r--r--src/test/regress/sql/plpgsql.sql44
9 files changed, 214 insertions, 50 deletions
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 122a0a92a55..3e883887ee8 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -42,7 +42,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.159 2005/06/09 22:29:52 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.160 2005/06/10 16:23:10 neilc Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1482,6 +1482,26 @@ log_line_prefix(StringInfo buf)
}
}
+/*
+ * Unpack MAKE_SQLSTATE code. Note that this returns a pointer to a
+ * static buffer.
+ */
+char *
+unpack_sql_state(int sql_state)
+{
+ static char buf[12];
+ int i;
+
+ for (i = 0; i < 5; i++)
+ {
+ buf[i] = PGUNSIXBIT(sql_state);
+ sql_state >>= 6;
+ }
+
+ buf[i] = '\0';
+ return buf;
+}
+
/*
* Write error report to server's log
@@ -1497,21 +1517,7 @@ send_message_to_server_log(ErrorData *edata)
appendStringInfo(&buf, "%s: ", error_severity(edata->elevel));
if (Log_error_verbosity >= PGERROR_VERBOSE)
- {
- /* unpack MAKE_SQLSTATE code */
- char tbuf[12];
- int ssval;
- int i;
-
- ssval = edata->sqlerrcode;
- for (i = 0; i < 5; i++)
- {
- tbuf[i] = PGUNSIXBIT(ssval);
- ssval >>= 6;
- }
- tbuf[i] = '\0';
- appendStringInfo(&buf, "%s: ", tbuf);
- }
+ appendStringInfo(&buf, "%s: ", unpack_sql_state(edata->sqlerrcode));
if (edata->message)
append_with_tabs(&buf, edata->message);
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index 0b7d3f17ebb..f226f772911 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/utils/elog.h,v 1.78 2004/12/31 22:03:46 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/utils/elog.h,v 1.79 2005/06/10 16:23:10 neilc Exp $
*
*-------------------------------------------------------------------------
*/
@@ -282,6 +282,7 @@ extern int Log_destination;
/* Other exported functions */
extern void DebugFileOpen(void);
+extern char *unpack_sql_state(int sql_state);
/*
* Write errors to stderr (or by equal means when stderr is
diff --git a/src/pl/plpgsql/src/gram.y b/src/pl/plpgsql/src/gram.y
index e1ba564ca90..48164d983b5 100644
--- a/src/pl/plpgsql/src/gram.y
+++ b/src/pl/plpgsql/src/gram.y
@@ -4,7 +4,7 @@
* procedural language
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.74 2005/06/08 00:49:36 neilc Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.75 2005/06/10 16:23:11 neilc Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@@ -92,6 +92,7 @@ static void plpgsql_sql_error_callback(void *arg);
PLpgSQL_stmt_block *program;
PLpgSQL_condition *condition;
PLpgSQL_exception *exception;
+ PLpgSQL_exception_block *exception_block;
PLpgSQL_nsitem *nsitem;
PLpgSQL_diag_item *diagitem;
}
@@ -129,7 +130,8 @@ static void plpgsql_sql_error_callback(void *arg);
%type <stmt> stmt_dynexecute stmt_getdiag
%type <stmt> stmt_open stmt_fetch stmt_close stmt_null
-%type <list> exception_sect proc_exceptions
+%type <list> proc_exceptions
+%type <exception_block> exception_sect
%type <exception> proc_exception
%type <condition> proc_conditions
@@ -1495,9 +1497,38 @@ execsql_start : T_WORD
;
exception_sect :
- { $$ = NIL; }
- | K_EXCEPTION proc_exceptions
- { $$ = $2; }
+ { $$ = NULL; }
+ | K_EXCEPTION lno
+ {
+ /*
+ * We use a mid-rule action to add these
+ * special variables to the namespace before
+ * parsing the WHEN clauses themselves.
+ */
+ PLpgSQL_exception_block *new = palloc(sizeof(PLpgSQL_exception_block));
+ PLpgSQL_variable *var;
+
+ var = plpgsql_build_variable("sqlstate", $2,
+ plpgsql_build_datatype(TEXTOID, -1),
+ true);
+ ((PLpgSQL_var *) var)->isconst = true;
+ new->sqlstate_varno = var->dno;
+
+ var = plpgsql_build_variable("sqlerrm", $2,
+ plpgsql_build_datatype(TEXTOID, -1),
+ true);
+ ((PLpgSQL_var *) var)->isconst = true;
+ new->sqlerrm_varno = var->dno;
+
+ $<exception_block>$ = new;
+ }
+ proc_exceptions
+ {
+ PLpgSQL_exception_block *new = $<exception_block>3;
+ new->exc_list = $4;
+
+ $$ = new;
+ }
;
proc_exceptions : proc_exceptions proc_exception
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index b746a8374bd..38b3d077de2 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -3,7 +3,7 @@
* procedural language
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.90 2005/05/29 04:23:06 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.91 2005/06/10 16:23:11 neilc Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@@ -656,7 +656,7 @@ do_compile(FunctionCallInfo fcinfo,
if (num_out_args > 0 || function->fn_rettype == VOIDOID ||
function->fn_retset)
{
- if (function->action->exceptions != NIL)
+ if (function->action->exceptions != NULL)
{
PLpgSQL_stmt_block *new;
@@ -882,7 +882,7 @@ plpgsql_parse_word(char *word)
}
/*
- * Do a lookup on the compilers namestack
+ * Do a lookup on the compiler's namestack
*/
nse = plpgsql_ns_lookup(cp[0], NULL);
if (nse != NULL)
@@ -1935,7 +1935,7 @@ plpgsql_parse_err_condition(char *condname)
/* ----------
* plpgsql_adddatum Add a variable, record or row
- * to the compilers datum list.
+ * to the compiler's datum list.
* ----------
*/
void
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 1fe1ed4cbed..ae5f7473146 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -3,7 +3,7 @@
* procedural language
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.142 2005/06/07 02:47:17 neilc Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.143 2005/06/10 16:23:11 neilc Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@@ -180,7 +180,7 @@ static Datum exec_simple_cast_value(Datum value, Oid valtype,
static void exec_init_tuple_store(PLpgSQL_execstate *estate);
static bool compatible_tupdesc(TupleDesc td1, TupleDesc td2);
static void exec_set_found(PLpgSQL_execstate *estate, bool state);
-
+static void free_var(PLpgSQL_var *var);
/* ----------
* plpgsql_exec_function Called by the call handler for
@@ -760,12 +760,7 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
{
PLpgSQL_var *var = (PLpgSQL_var *) (estate->datums[n]);
- if (var->freeval)
- {
- pfree((void *) (var->value));
- var->freeval = false;
- }
-
+ free_var(var);
if (!var->isconst || var->isnull)
{
if (var->default_val == NULL)
@@ -864,13 +859,37 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
SPI_restore_connection();
/* Look for a matching exception handler */
- foreach (e, block->exceptions)
+ foreach (e, block->exceptions->exc_list)
{
PLpgSQL_exception *exception = (PLpgSQL_exception *) lfirst(e);
if (exception_matches_conditions(edata, exception->conditions))
{
+ /*
+ * Initialize the magic SQLSTATE and SQLERRM
+ * variables for the exception block. We needn't
+ * do this until we have found a matching
+ * exception.
+ */
+ PLpgSQL_var *state_var;
+ PLpgSQL_var *errm_var;
+
+ state_var = (PLpgSQL_var *) (estate->datums[block->exceptions->sqlstate_varno]);
+ state_var->value = DirectFunctionCall1(textin,
+ CStringGetDatum(unpack_sql_state(edata->sqlerrcode)));
+ state_var->freeval = true;
+ state_var->isnull = false;
+
+ errm_var = (PLpgSQL_var *) (estate->datums[block->exceptions->sqlerrm_varno]);
+ errm_var->value = DirectFunctionCall1(textin,
+ CStringGetDatum(edata->message));
+ errm_var->freeval = true;
+ errm_var->isnull = false;
+
rc = exec_stmts(estate, exception->action);
+
+ free_var(state_var);
+ free_var(errm_var);
break;
}
}
@@ -2586,9 +2605,7 @@ exec_stmt_open(PLpgSQL_execstate *estate, PLpgSQL_stmt_open *stmt)
* Store the eventually assigned cursor name in the cursor variable
* ----------
*/
- if (curvar->freeval)
- pfree((void *) (curvar->value));
-
+ free_var(curvar);
curvar->value = DirectFunctionCall1(textin, CStringGetDatum(portal->name));
curvar->isnull = false;
curvar->freeval = true;
@@ -2684,9 +2701,7 @@ exec_stmt_open(PLpgSQL_execstate *estate, PLpgSQL_stmt_open *stmt)
* Store the eventually assigned portal name in the cursor variable
* ----------
*/
- if (curvar->freeval)
- pfree((void *) (curvar->value));
-
+ free_var(curvar);
curvar->value = DirectFunctionCall1(textin, CStringGetDatum(portal->name));
curvar->isnull = false;
curvar->freeval = true;
@@ -2857,11 +2872,7 @@ exec_assign_value(PLpgSQL_execstate *estate,
errmsg("NULL cannot be assigned to variable \"%s\" declared NOT NULL",
var->refname)));
- if (var->freeval)
- {
- pfree(DatumGetPointer(var->value));
- var->freeval = false;
- }
+ free_var(var);
/*
* If type is by-reference, make sure we have a freshly
@@ -4343,3 +4354,13 @@ plpgsql_xact_cb(XactEvent event, void *arg)
FreeExecutorState(simple_eval_estate);
simple_eval_estate = NULL;
}
+
+static void
+free_var(PLpgSQL_var *var)
+{
+ if (var->freeval)
+ {
+ pfree(DatumGetPointer(var->value));
+ var->freeval = false;
+ }
+}
diff --git a/src/pl/plpgsql/src/pl_funcs.c b/src/pl/plpgsql/src/pl_funcs.c
index 475d2224bff..9e2ef4902c2 100644
--- a/src/pl/plpgsql/src/pl_funcs.c
+++ b/src/pl/plpgsql/src/pl_funcs.c
@@ -3,7 +3,7 @@
* procedural language
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.40 2005/04/05 06:22:16 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.41 2005/06/10 16:23:11 neilc Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@@ -634,7 +634,7 @@ dump_block(PLpgSQL_stmt_block *block)
{
ListCell *e;
- foreach (e, block->exceptions)
+ foreach (e, block->exceptions->exc_list)
{
PLpgSQL_exception *exc = (PLpgSQL_exception *) lfirst(e);
PLpgSQL_condition *cond;
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index a70553ac2c8..580439c88c5 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -3,7 +3,7 @@
* procedural language
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.61 2005/06/07 02:47:18 neilc Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.62 2005/06/10 16:23:11 neilc Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@@ -323,6 +323,13 @@ typedef struct PLpgSQL_condition
} PLpgSQL_condition;
typedef struct
+{
+ int sqlstate_varno;
+ int sqlerrm_varno;
+ List *exc_list; /* List of WHEN clauses */
+} PLpgSQL_exception_block;
+
+typedef struct
{ /* One EXCEPTION ... WHEN clause */
int lineno;
PLpgSQL_condition *conditions;
@@ -336,9 +343,9 @@ typedef struct
int lineno;
char *label;
List *body; /* List of statements */
- List *exceptions; /* List of WHEN clauses */
int n_initvars;
int *initvarnos;
+ PLpgSQL_exception_block *exceptions;
} PLpgSQL_stmt_block;
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index 39e61e09cf2..2650cbb908a 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -2415,3 +2415,57 @@ NOTICE: 10 15 20
drop table eifoo cascade;
drop type eitype cascade;
+--
+-- SQLSTATE and SQLERRM test
+--
+-- should fail: SQLSTATE and SQLERRM are only in defined EXCEPTION
+-- blocks
+create function excpt_test() returns void as $$
+begin
+ raise notice '% %', sqlstate, sqlerrm;
+end; $$ language plpgsql;
+ERROR: syntax error at or near "sqlstate" at character 79
+LINE 3: raise notice '% %', sqlstate, sqlerrm;
+ ^
+-- should fail
+create function excpt_test() returns void as $$
+begin
+ begin
+ begin
+ raise notice '% %', sqlstate, sqlerrm;
+ end;
+ end;
+end; $$ language plpgsql;
+ERROR: syntax error at or near "sqlstate" at character 108
+LINE 5: raise notice '% %', sqlstate, sqlerrm;
+ ^
+create function excpt_test() returns void as $$
+begin
+ begin
+ raise exception 'user exception';
+ exception when others then
+ raise notice 'caught exception % %', sqlstate, sqlerrm;
+ begin
+ raise notice '% %', sqlstate, sqlerrm;
+ perform 10/0;
+ exception
+ when substring_error then
+ -- this exception handler shouldn't be invoked
+ raise notice 'unexpected exception: % %', sqlstate, sqlerrm;
+ when division_by_zero then
+ raise notice 'caught exception % %', sqlstate, sqlerrm;
+ end;
+ raise notice '% %', sqlstate, sqlerrm;
+ end;
+end; $$ language plpgsql;
+select excpt_test();
+NOTICE: caught exception P0001 user exception
+NOTICE: P0001 user exception
+NOTICE: caught exception 22012 division by zero
+NOTICE: P0001 user exception
+ excpt_test
+------------
+
+(1 row)
+
+drop function excpt_test();
diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql
index 314f69915fc..9dc00f2f1e5 100644
--- a/src/test/regress/sql/plpgsql.sql
+++ b/src/test/regress/sql/plpgsql.sql
@@ -2050,3 +2050,47 @@ select execute_into_test('eifoo');
drop table eifoo cascade;
drop type eitype cascade;
+
+--
+-- SQLSTATE and SQLERRM test
+--
+
+-- should fail: SQLSTATE and SQLERRM are only in defined EXCEPTION
+-- blocks
+create function excpt_test() returns void as $$
+begin
+ raise notice '% %', sqlstate, sqlerrm;
+end; $$ language plpgsql;
+
+-- should fail
+create function excpt_test() returns void as $$
+begin
+ begin
+ begin
+ raise notice '% %', sqlstate, sqlerrm;
+ end;
+ end;
+end; $$ language plpgsql;
+
+create function excpt_test() returns void as $$
+begin
+ begin
+ raise exception 'user exception';
+ exception when others then
+ raise notice 'caught exception % %', sqlstate, sqlerrm;
+ begin
+ raise notice '% %', sqlstate, sqlerrm;
+ perform 10/0;
+ exception
+ when substring_error then
+ -- this exception handler shouldn't be invoked
+ raise notice 'unexpected exception: % %', sqlstate, sqlerrm;
+ when division_by_zero then
+ raise notice 'caught exception % %', sqlstate, sqlerrm;
+ end;
+ raise notice '% %', sqlstate, sqlerrm;
+ end;
+end; $$ language plpgsql;
+
+select excpt_test();
+drop function excpt_test();