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