Thanks to visit codestin.com
Credit goes to github.com

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

Lines changed: 8 additions & 23 deletions
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

Lines changed: 68 additions & 1 deletion
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

Lines changed: 11 additions & 36 deletions
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

Lines changed: 4 additions & 2 deletions
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)