diff --git a/src/pl/plpgsql/src/gram.y b/src/pl/plpgsql/src/gram.y index c5c6ddf703ccfcc8c298284d7e87a2b6d5a2b23f..3bf7b2f50452b45c99c487ec33752c4bcc5873f2 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.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); } ; diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index 75d0a1f8a82edf3053961b8890e1927f66ea9029..2c9ae832860a7d83d467f8daf5b616a6d6869dde 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.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 diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 47a505a8d3433fe21337b637bb453dbe7213630a..48148c90cbe8eaf8b1313ee5f66634eb919bfe40 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.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; } diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h index e054d5b25f1ec5197ebdf53a6e6345271e6104ca..346f82c5c83dab564d857a5da0ebc7aa2d9a0609 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.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);