]> granicus.if.org Git - postgresql/commitdiff
Recognize plpgsql EXCEPTION condition names at function compile time
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 20 Aug 2004 22:00:14 +0000 (22:00 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 20 Aug 2004 22:00:14 +0000 (22:00 +0000)
instead of runtime, for better detection of invalid condition names
(and maybe a little more speed, too).

src/pl/plpgsql/src/gram.y
src/pl/plpgsql/src/pl_comp.c
src/pl/plpgsql/src/pl_exec.c
src/pl/plpgsql/src/plpgsql.h

index c5c6ddf703ccfcc8c298284d7e87a2b6d5a2b23f..3bf7b2f50452b45c99c487ec33752c4bcc5873f2 100644 (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);
                                                }
                                ;
 
index 75d0a1f8a82edf3053961b8890e1927f66ea9029..2c9ae832860a7d83d467f8daf5b616a6d6869dde 100644 (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
index 47a505a8d3433fe21337b637bb453dbe7213630a..48148c90cbe8eaf8b1313ee5f66634eb919bfe40 100644 (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.
  *
 
 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;
 }
index e054d5b25f1ec5197ebdf53a6e6345271e6104ca..346f82c5c83dab564d857a5da0ebc7aa2d9a0609 100644 (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);