aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/pl/plpgsql/src/gram.y32
-rw-r--r--src/pl/plpgsql/src/pl_exec.c47
-rw-r--r--src/pl/plpgsql/src/plpgsql.h10
-rw-r--r--src/test/regress/expected/plpgsql.out26
-rw-r--r--src/test/regress/sql/plpgsql.sql20
5 files changed, 125 insertions, 10 deletions
diff --git a/src/pl/plpgsql/src/gram.y b/src/pl/plpgsql/src/gram.y
index 8b5f6b5e28d..d4a535d548b 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.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.
*
@@ -80,6 +80,11 @@ static void plpgsql_sql_error_callback(void *arg);
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 */
@@ -96,6 +101,7 @@ static void plpgsql_sql_error_callback(void *arg);
PLpgSQL_diag_item *diagitem;
}
+%type <fict_vars> fict_vars_sect
%type <declhdr> decl_sect
%type <varname> decl_varname
%type <str> decl_renname
@@ -244,19 +250,22 @@ opt_semi :
| ';'
;
-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();
@@ -264,6 +273,19 @@ pl_block : decl_sect K_BEGIN lno proc_sect exception_sect K_END
}
;
+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
{
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 18bcd4fe2ee..333ca21c0ba 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.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.
*
@@ -180,6 +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 char *unpack_sql_state(int ssval);
/* ----------
@@ -747,6 +748,20 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
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
*/
@@ -855,6 +870,16 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *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,
@@ -919,6 +944,26 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
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
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index 80bcd9e8fa6..f3b14fdf643 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.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.
*
@@ -336,9 +336,11 @@ typedef struct
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;
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index 08fbe46b3a2..5ee5c338e46 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -2380,3 +2380,29 @@ ERROR: control reached end of function without RETURN
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();
diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql
index 7ea7c8c6e0c..e2ef2ec5fe3 100644
--- a/src/test/regress/sql/plpgsql.sql
+++ b/src/test/regress/sql/plpgsql.sql
@@ -2018,3 +2018,23 @@ select 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();
+
+drop function trap_exceptions();