error.
Pavel Stehule
- By default, any error occurring in a
PL/pgSQL>
- function aborts execution of the function, and indeed of the
- surrounding transaction as well. You can trap errors and recover
- from them by using a BEGIN> block with an
- EXCEPTION> clause. The syntax is an extension of the
- normal syntax for a BEGIN> block:
+ Any error occurring in
PL/pgSQL> sets variables
+ SQLSTATE> and SQLERRM>, and, by default,
+ aborts execution of the function, and indeed of the surrounding
+ transaction as well. You can trap errors and recover from them by
+ using a BEGIN> block with an EXCEPTION>
+ clause. The syntax is an extension of the normal syntax for a
+ BEGIN> block:
<<label>>
* procedural language
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.69 2005/04/07 14:53:04 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.70 2005/05/26 00:16:31 momjian Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
int n_initvars;
int *initvarnos;
} declhdr;
+ struct
+ {
+ int sqlstate_varno;
+ int sqlerrm_varno;
+ } fict_vars;
List *list;
PLpgSQL_type *dtype;
PLpgSQL_datum *scalar; /* a VAR, RECFIELD, or TRIGARG */
PLpgSQL_diag_item *diagitem;
}
+%type fict_vars_sect
%type decl_sect
%type decl_varname
%type decl_renname
| ';'
;
-pl_block : decl_sect K_BEGIN lno proc_sect exception_sect K_END
+pl_block : decl_sect fict_vars_sect K_BEGIN lno proc_sect exception_sect K_END
{
PLpgSQL_stmt_block *new;
new = palloc0(sizeof(PLpgSQL_stmt_block));
new->cmd_type = PLPGSQL_STMT_BLOCK;
- new->lineno = $3;
+ new->lineno = $4;
new->label = $1.label;
new->n_initvars = $1.n_initvars;
new->initvarnos = $1.initvarnos;
- new->body = $4;
- new->exceptions = $5;
+ new->body = $5;
+ new->exceptions = $6;
+
+ new->sqlstate_varno = $2.sqlstate_varno;
+ new->sqlerrm_varno = $2.sqlerrm_varno;
plpgsql_ns_pop();
}
;
+fict_vars_sect :
+ {
+ PLpgSQL_variable *var;
+
+ plpgsql_ns_setlocal(false);
+ var = plpgsql_build_variable("sqlstate", 0,
+ plpgsql_build_datatype(TEXTOID, -1), true);
+ $$.sqlstate_varno = var->dno;
+ var = plpgsql_build_variable("sqlerrm", 0,
+ plpgsql_build_datatype(TEXTOID, -1), true);
+ $$.sqlerrm_varno = var->dno;
+ plpgsql_add_initdatums(NULL);
+ };
decl_sect : opt_label
{
* procedural language
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.138 2005/05/06 17:24:55 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.139 2005/05/26 00:16:31 momjian Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
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 char *unpack_sql_state(int ssval);
/* ----------
int i;
int n;
+
+ /* setup SQLSTATE and SQLERRM */
+ PLpgSQL_var *var;
+
+ var = (PLpgSQL_var *) (estate->datums[block->sqlstate_varno]);
+ var->isnull = false;
+ var->freeval = true;
+ var->value = DirectFunctionCall1(textin, CStringGetDatum("00000"));
+
+ var = (PLpgSQL_var *) (estate->datums[block->sqlerrm_varno]);
+ var->isnull = false;
+ var->freeval = true;
+ var->value = DirectFunctionCall1(textin, CStringGetDatum("Sucessful completion"));
+
/*
* First initialize all variables declared in this block
*/
RollbackAndReleaseCurrentSubTransaction();
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
+
+ /* set SQLSTATE and SQLERRM variables */
+
+ var = (PLpgSQL_var *) (estate->datums[block->sqlstate_varno]);
+ pfree((void *) (var->value));
+ var->value = DirectFunctionCall1(textin, CStringGetDatum(unpack_sql_state(edata->sqlerrcode)));
+
+ var = (PLpgSQL_var *) (estate->datums[block->sqlerrm_varno]);
+ pfree((void *) (var->value));
+ var->value = DirectFunctionCall1(textin, CStringGetDatum(edata->message));
/*
* If AtEOSubXact_SPI() popped any SPI context of the subxact,
return PLPGSQL_RC_OK;
}
+/*
+ * unpack MAKE_SQLSTATE code
+ * This code is copied from backend/utils/error/elog.c.
+ */
+static char *
+unpack_sql_state(int ssval)
+{
+ static char tbuf[12];
+ int i;
+
+ for (i = 0; i < 5; i++)
+ {
+ tbuf[i] = PGUNSIXBIT(ssval);
+ ssval >>= 6;
+ }
+ tbuf[i] = '\0';
+ return tbuf;
+}
+
+
/* ----------
* exec_stmts Iterate over a list of statements
* procedural language
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.58 2005/04/05 06:22:16 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.59 2005/05/26 00:16:31 momjian Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
int lineno;
char *label;
List *body; /* List of statements */
- List *exceptions; /* List of WHEN clauses */
- int n_initvars;
- int *initvarnos;
+ List *exceptions; /* List of WHEN clauses */
+ int n_initvars;
+ int *initvarnos;
+ int sqlstate_varno;
+ int sqlerrm_varno;
} PLpgSQL_stmt_block;
CONTEXT: PL/pgSQL function "missing_return_expr"
drop function void_return_expr();
drop function missing_return_expr();
+-- test SQLSTATE and SQLERRM
+create or replace function trap_exceptions() returns void as $_$
+begin
+ begin
+ raise exception 'first exception';
+ exception when others then
+ raise notice '% %', SQLSTATE, SQLERRM;
+ end;
+ raise notice '% %', SQLSTATE, SQLERRM;
+ begin
+ raise exception 'last exception';
+ exception when others then
+ raise notice '% %', SQLSTATE, SQLERRM;
+ end;
+ return;
+end; $_$ language plpgsql;
+select trap_exceptions();
+NOTICE: P0001 first exception
+NOTICE: 00000 Sucessful completion
+NOTICE: P0001 last exception
+ trap_exceptions
+-----------------
+
+(1 row)
+
+drop function trap_exceptions();
drop function void_return_expr();
drop function missing_return_expr();
+-- test SQLSTATE and SQLERRM
+create or replace function trap_exceptions() returns void as $_$
+begin
+ begin
+ raise exception 'first exception';
+ exception when others then
+ raise notice '% %', SQLSTATE, SQLERRM;
+ end;
+ raise notice '% %', SQLSTATE, SQLERRM;
+ begin
+ raise exception 'last exception';
+ exception when others then
+ raise notice '% %', SQLSTATE, SQLERRM;
+ end;
+ return;
+end; $_$ language plpgsql;
+
+select trap_exceptions();
+
+drop function trap_exceptions();