Recognize plpgsql EXCEPTION condition names at function compile time

instead of runtime, for better detection of invalid condition names
(and maybe a little more speed, too).
This commit is contained in:
Tom Lane 2004-08-20 22:00:14 +00:00
parent 009b0d1a85
commit bf9d9bd2f3
4 changed files with 91 additions and 62 deletions

View File

@ -4,7 +4,7 @@
* procedural language
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.60 2004/08/16 17:52:06 tgl Exp $
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.61 2004/08/20 22:00:14 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@ -1568,7 +1568,7 @@ proc_exceptions : proc_exceptions proc_exception
new = malloc(sizeof(PLpgSQL_exceptions));
memset(new, 0, sizeof(PLpgSQL_exceptions));
new->exceptions_alloc = 64;
new->exceptions_alloc = 16;
new->exceptions_used = 1;
new->exceptions = malloc(sizeof(PLpgSQL_exception *) * new->exceptions_alloc);
new->exceptions[0] = $1;
@ -1594,32 +1594,17 @@ proc_exception : K_WHEN lno proc_conditions K_THEN proc_sect
proc_conditions : proc_conditions K_OR opt_lblname
{
PLpgSQL_condition *new;
PLpgSQL_condition *old;
PLpgSQL_condition *old;
new = malloc(sizeof(PLpgSQL_condition));
memset(new, 0, sizeof(PLpgSQL_condition));
for (old = $1; old->next != NULL; old = old->next)
/* skip */ ;
old->next = plpgsql_parse_err_condition($3);
new->condname = $3;
new->next = NULL;
for (old = $1; old->next != NULL; old = old->next)
/* skip */ ;
old->next = new;
$$ = $1;
$$ = $1;
}
| opt_lblname
{
PLpgSQL_condition *new;
new = malloc(sizeof(PLpgSQL_condition));
memset(new, 0, sizeof(PLpgSQL_condition));
new->condname = $1;
new->next = NULL;
$$ = new;
$$ = plpgsql_parse_err_condition($1);
}
;

View File

@ -3,7 +3,7 @@
* procedural language
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.78 2004/07/31 00:45:46 tgl Exp $
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.79 2004/08/20 22:00:14 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@ -94,6 +94,20 @@ typedef struct plpgsql_hashent
#define FUNCS_PER_USER 128 /* initial table size */
/* ----------
* Lookup table for EXCEPTION condition names
* ----------
*/
typedef struct {
const char *label;
int sqlerrstate;
} ExceptionLabelMap;
static const ExceptionLabelMap exception_label_map[] = {
#include "plerrcodes.h"
{ NULL, 0 }
};
/* ----------
* static prototypes
@ -1710,6 +1724,59 @@ build_datatype(HeapTuple typeTup, int32 typmod)
return typ;
}
/*
* plpgsql_parse_err_condition
* Generate PLpgSQL_condition entry(s) for an exception condition name
*
* This has to be able to return a list because there are some duplicate
* names in the table of error code names.
*/
PLpgSQL_condition *
plpgsql_parse_err_condition(char *condname)
{
int i;
PLpgSQL_condition *new;
PLpgSQL_condition *prev;
/*
* XXX Eventually we will want to look for user-defined exception names
* here.
*/
/*
* OTHERS is represented as code 0 (which would map to '00000', but
* we have no need to represent that as an exception condition).
*/
if (strcmp(condname, "others") == 0)
{
new = malloc(sizeof(PLpgSQL_condition));
new->sqlerrstate = 0;
new->condname = condname;
new->next = NULL;
return new;
}
prev = NULL;
for (i = 0; exception_label_map[i].label != NULL; i++)
{
if (strcmp(condname, exception_label_map[i].label) == 0)
{
new = malloc(sizeof(PLpgSQL_condition));
new->sqlerrstate = exception_label_map[i].sqlerrstate;
new->condname = condname;
new->next = prev;
prev = new;
}
}
if (!prev)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("unrecognized exception condition \"%s\"",
condname)));
return prev;
}
/* ----------
* plpgsql_adddatum Add a variable, record or row

View File

@ -3,7 +3,7 @@
* procedural language
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.115 2004/08/13 18:47:56 tgl Exp $
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.116 2004/08/20 22:00:14 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@ -56,15 +56,6 @@
static const char *const raise_skip_msg = "RAISE";
typedef struct {
const char *label;
int sqlerrstate;
} ExceptionLabelMap;
static const ExceptionLabelMap exception_label_map[] = {
#include "plerrcodes.h"
{ NULL, 0 }
};
/*
* All plpgsql function executions within a single transaction share
@ -799,40 +790,24 @@ exception_matches_conditions(ErrorData *edata, PLpgSQL_condition *cond)
{
for (; cond != NULL; cond = cond->next)
{
const char *condname = cond->condname;
int i;
int sqlerrstate = cond->sqlerrstate;
/*
* OTHERS matches everything *except* query-canceled;
* if you're foolish enough, you can match that explicitly.
*/
if (strcmp(condname, "others") == 0)
if (sqlerrstate == 0)
{
if (edata->sqlerrcode == ERRCODE_QUERY_CANCELED)
return false;
else
if (edata->sqlerrcode != ERRCODE_QUERY_CANCELED)
return true;
}
for (i = 0; exception_label_map[i].label != NULL; i++)
{
if (strcmp(condname, exception_label_map[i].label) == 0)
{
int labelerrcode = exception_label_map[i].sqlerrstate;
/* Exact match? */
if (edata->sqlerrcode == labelerrcode)
return true;
/* Category match? */
if (ERRCODE_IS_CATEGORY(labelerrcode) &&
ERRCODE_TO_CATEGORY(edata->sqlerrcode) == labelerrcode)
return true;
/*
* You would think we should "break" here, but there are some
* duplicate names in the table, so keep looking.
*/
}
}
/* Should we raise an error if condname is unrecognized?? */
/* Exact match? */
else if (edata->sqlerrcode == sqlerrstate)
return true;
/* Category match? */
else if (ERRCODE_IS_CATEGORY(sqlerrstate) &&
ERRCODE_TO_CATEGORY(edata->sqlerrcode) == sqlerrstate)
return true;
}
return false;
}

View File

@ -3,7 +3,7 @@
* procedural language
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.50 2004/08/01 17:32:22 tgl Exp $
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.51 2004/08/20 22:00:14 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@ -324,7 +324,8 @@ typedef struct
typedef struct PLpgSQL_condition
{ /* One EXCEPTION condition name */
char *condname;
int sqlerrstate; /* SQLSTATE code */
char *condname; /* condition name (for debugging) */
struct PLpgSQL_condition *next;
} PLpgSQL_condition;
@ -682,6 +683,7 @@ extern PLpgSQL_type *plpgsql_build_datatype(Oid typeOid, int32 typmod);
extern PLpgSQL_variable *plpgsql_build_variable(char *refname, int lineno,
PLpgSQL_type *dtype,
bool add2namespace);
extern PLpgSQL_condition *plpgsql_parse_err_condition(char *condname);
extern void plpgsql_adddatum(PLpgSQL_datum *new);
extern int plpgsql_add_initdatums(int **varnos);
extern void plpgsql_HashTableInit(void);