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);