Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit bf9d9bd

Browse files
committed
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).
1 parent 009b0d1 commit bf9d9bd

File tree

4 files changed

+91
-62
lines changed

4 files changed

+91
-62
lines changed

src/pl/plpgsql/src/gram.y

+8-23
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* procedural language
55
*
66
* IDENTIFICATION
7-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.60 2004/08/16 17:52:06 tgl Exp $
7+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.61 2004/08/20 22:00:14 tgl Exp $
88
*
99
* This software is copyrighted by Jan Wieck - Hamburg.
1010
*
@@ -1568,7 +1568,7 @@ proc_exceptions : proc_exceptions proc_exception
15681568
new = malloc(sizeof(PLpgSQL_exceptions));
15691569
memset(new, 0, sizeof(PLpgSQL_exceptions));
15701570

1571-
new->exceptions_alloc = 64;
1571+
new->exceptions_alloc = 16;
15721572
new->exceptions_used = 1;
15731573
new->exceptions = malloc(sizeof(PLpgSQL_exception *) * new->exceptions_alloc);
15741574
new->exceptions[0] = $1;
@@ -1594,32 +1594,17 @@ proc_exception : K_WHEN lno proc_conditions K_THEN proc_sect
15941594

15951595
proc_conditions : proc_conditions K_OR opt_lblname
15961596
{
1597-
PLpgSQL_condition *new;
1598-
PLpgSQL_condition *old;
1597+
PLpgSQL_condition *old;
15991598

1600-
new = malloc(sizeof(PLpgSQL_condition));
1601-
memset(new, 0, sizeof(PLpgSQL_condition));
1599+
for (old = $1; old->next != NULL; old = old->next)
1600+
/* skip */ ;
1601+
old->next = plpgsql_parse_err_condition($3);
16021602

1603-
new->condname = $3;
1604-
new->next = NULL;
1605-
1606-
for (old = $1; old->next != NULL; old = old->next)
1607-
/* skip */ ;
1608-
old->next = new;
1609-
1610-
$$ = $1;
1603+
$$ = $1;
16111604
}
16121605
| opt_lblname
16131606
{
1614-
PLpgSQL_condition *new;
1615-
1616-
new = malloc(sizeof(PLpgSQL_condition));
1617-
memset(new, 0, sizeof(PLpgSQL_condition));
1618-
1619-
new->condname = $1;
1620-
new->next = NULL;
1621-
1622-
$$ = new;
1607+
$$ = plpgsql_parse_err_condition($1);
16231608
}
16241609
;
16251610

src/pl/plpgsql/src/pl_comp.c

+68-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* procedural language
44
*
55
* IDENTIFICATION
6-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.78 2004/07/31 00:45:46 tgl Exp $
6+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.79 2004/08/20 22:00:14 tgl Exp $
77
*
88
* This software is copyrighted by Jan Wieck - Hamburg.
99
*
@@ -94,6 +94,20 @@ typedef struct plpgsql_hashent
9494

9595
#define FUNCS_PER_USER 128 /* initial table size */
9696

97+
/* ----------
98+
* Lookup table for EXCEPTION condition names
99+
* ----------
100+
*/
101+
typedef struct {
102+
const char *label;
103+
int sqlerrstate;
104+
} ExceptionLabelMap;
105+
106+
static const ExceptionLabelMap exception_label_map[] = {
107+
#include "plerrcodes.h"
108+
{ NULL, 0 }
109+
};
110+
97111

98112
/* ----------
99113
* static prototypes
@@ -1710,6 +1724,59 @@ build_datatype(HeapTuple typeTup, int32 typmod)
17101724
return typ;
17111725
}
17121726

1727+
/*
1728+
* plpgsql_parse_err_condition
1729+
* Generate PLpgSQL_condition entry(s) for an exception condition name
1730+
*
1731+
* This has to be able to return a list because there are some duplicate
1732+
* names in the table of error code names.
1733+
*/
1734+
PLpgSQL_condition *
1735+
plpgsql_parse_err_condition(char *condname)
1736+
{
1737+
int i;
1738+
PLpgSQL_condition *new;
1739+
PLpgSQL_condition *prev;
1740+
1741+
/*
1742+
* XXX Eventually we will want to look for user-defined exception names
1743+
* here.
1744+
*/
1745+
1746+
/*
1747+
* OTHERS is represented as code 0 (which would map to '00000', but
1748+
* we have no need to represent that as an exception condition).
1749+
*/
1750+
if (strcmp(condname, "others") == 0)
1751+
{
1752+
new = malloc(sizeof(PLpgSQL_condition));
1753+
new->sqlerrstate = 0;
1754+
new->condname = condname;
1755+
new->next = NULL;
1756+
return new;
1757+
}
1758+
1759+
prev = NULL;
1760+
for (i = 0; exception_label_map[i].label != NULL; i++)
1761+
{
1762+
if (strcmp(condname, exception_label_map[i].label) == 0)
1763+
{
1764+
new = malloc(sizeof(PLpgSQL_condition));
1765+
new->sqlerrstate = exception_label_map[i].sqlerrstate;
1766+
new->condname = condname;
1767+
new->next = prev;
1768+
prev = new;
1769+
}
1770+
}
1771+
1772+
if (!prev)
1773+
ereport(ERROR,
1774+
(errcode(ERRCODE_UNDEFINED_OBJECT),
1775+
errmsg("unrecognized exception condition \"%s\"",
1776+
condname)));
1777+
1778+
return prev;
1779+
}
17131780

17141781
/* ----------
17151782
* plpgsql_adddatum Add a variable, record or row

src/pl/plpgsql/src/pl_exec.c

+11-36
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* procedural language
44
*
55
* IDENTIFICATION
6-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.115 2004/08/13 18:47:56 tgl Exp $
6+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.116 2004/08/20 22:00:14 tgl Exp $
77
*
88
* This software is copyrighted by Jan Wieck - Hamburg.
99
*
@@ -56,15 +56,6 @@
5656

5757
static const char *const raise_skip_msg = "RAISE";
5858

59-
typedef struct {
60-
const char *label;
61-
int sqlerrstate;
62-
} ExceptionLabelMap;
63-
64-
static const ExceptionLabelMap exception_label_map[] = {
65-
#include "plerrcodes.h"
66-
{ NULL, 0 }
67-
};
6859

6960
/*
7061
* All plpgsql function executions within a single transaction share
@@ -799,40 +790,24 @@ exception_matches_conditions(ErrorData *edata, PLpgSQL_condition *cond)
799790
{
800791
for (; cond != NULL; cond = cond->next)
801792
{
802-
const char *condname = cond->condname;
803-
int i;
793+
int sqlerrstate = cond->sqlerrstate;
804794

805795
/*
806796
* OTHERS matches everything *except* query-canceled;
807797
* if you're foolish enough, you can match that explicitly.
808798
*/
809-
if (strcmp(condname, "others") == 0)
799+
if (sqlerrstate == 0)
810800
{
811-
if (edata->sqlerrcode == ERRCODE_QUERY_CANCELED)
812-
return false;
813-
else
801+
if (edata->sqlerrcode != ERRCODE_QUERY_CANCELED)
814802
return true;
815803
}
816-
for (i = 0; exception_label_map[i].label != NULL; i++)
817-
{
818-
if (strcmp(condname, exception_label_map[i].label) == 0)
819-
{
820-
int labelerrcode = exception_label_map[i].sqlerrstate;
821-
822-
/* Exact match? */
823-
if (edata->sqlerrcode == labelerrcode)
824-
return true;
825-
/* Category match? */
826-
if (ERRCODE_IS_CATEGORY(labelerrcode) &&
827-
ERRCODE_TO_CATEGORY(edata->sqlerrcode) == labelerrcode)
828-
return true;
829-
/*
830-
* You would think we should "break" here, but there are some
831-
* duplicate names in the table, so keep looking.
832-
*/
833-
}
834-
}
835-
/* Should we raise an error if condname is unrecognized?? */
804+
/* Exact match? */
805+
else if (edata->sqlerrcode == sqlerrstate)
806+
return true;
807+
/* Category match? */
808+
else if (ERRCODE_IS_CATEGORY(sqlerrstate) &&
809+
ERRCODE_TO_CATEGORY(edata->sqlerrcode) == sqlerrstate)
810+
return true;
836811
}
837812
return false;
838813
}

src/pl/plpgsql/src/plpgsql.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* procedural language
44
*
55
* IDENTIFICATION
6-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.50 2004/08/01 17:32:22 tgl Exp $
6+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.51 2004/08/20 22:00:14 tgl Exp $
77
*
88
* This software is copyrighted by Jan Wieck - Hamburg.
99
*
@@ -324,7 +324,8 @@ typedef struct
324324

325325
typedef struct PLpgSQL_condition
326326
{ /* One EXCEPTION condition name */
327-
char *condname;
327+
int sqlerrstate; /* SQLSTATE code */
328+
char *condname; /* condition name (for debugging) */
328329
struct PLpgSQL_condition *next;
329330
} PLpgSQL_condition;
330331

@@ -682,6 +683,7 @@ extern PLpgSQL_type *plpgsql_build_datatype(Oid typeOid, int32 typmod);
682683
extern PLpgSQL_variable *plpgsql_build_variable(char *refname, int lineno,
683684
PLpgSQL_type *dtype,
684685
bool add2namespace);
686+
extern PLpgSQL_condition *plpgsql_parse_err_condition(char *condname);
685687
extern void plpgsql_adddatum(PLpgSQL_datum *new);
686688
extern int plpgsql_add_initdatums(int **varnos);
687689
extern void plpgsql_HashTableInit(void);

0 commit comments

Comments
 (0)