diff --git a/src/pl/plpgsql/src/gram.y b/src/pl/plpgsql/src/gram.y
index ffb16bea1c..4541c9839d 100644
--- a/src/pl/plpgsql/src/gram.y
+++ b/src/pl/plpgsql/src/gram.y
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.106 2007/11/09 23:58:32 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.107 2007/11/27 19:58:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -43,6 +43,7 @@ static PLpgSQL_row		*make_scalar_list1(const char *initial_name,
 										   int lineno);
 static	void			 check_sql_expr(const char *stmt);
 static	void			 plpgsql_sql_error_callback(void *arg);
+static	char			*check_label(const char *yytxt);
 static	void			 check_labels(const char *start_label,
 									  const char *end_label);
 
@@ -214,7 +215,6 @@ static	void			 check_labels(const char *start_label,
 %token	T_ROW
 %token	T_RECORD
 %token	T_DTYPE
-%token	T_LABEL
 %token	T_WORD
 %token	T_ERROR
 
@@ -505,7 +505,8 @@ decl_aliasitem	: T_WORD
 							yyerror("only positional parameters can be aliased");
 
 						plpgsql_ns_setlocal(false);
-						nsi = plpgsql_ns_lookup(name, NULL);
+
+						nsi = plpgsql_ns_lookup(name, NULL, NULL, NULL);
 						if (nsi == NULL)
 						{
 							plpgsql_error_lineno = plpgsql_scanner_lineno();
@@ -1642,20 +1643,28 @@ opt_block_label	:
 					}
 				;
 
+/*
+ * need all the options because scanner will have tried to resolve as variable
+ */
 opt_label	:
 					{
 						$$ = NULL;
 					}
-				| T_LABEL
-					{
-						char *label_name;
-						plpgsql_convert_ident(yytext, &label_name, 1);
-						$$ = label_name;
-					}
 				| T_WORD
 					{
-						/* just to give a better error than "syntax error" */
-						yyerror("no such label");
+						$$ = check_label(yytext);
+					}
+				| T_SCALAR
+					{
+						$$ = check_label(yytext);
+					}
+				| T_RECORD
+					{
+						$$ = check_label(yytext);
+					}
+				| T_ROW
+					{
+						$$ = check_label(yytext);
 					}
 				;
 
@@ -2484,6 +2493,17 @@ plpgsql_sql_error_callback(void *arg)
 	errposition(0);
 }
 
+static char *
+check_label(const char *yytxt)
+{
+	char	   *label_name;
+
+	plpgsql_convert_ident(yytxt, &label_name, 1);
+	if (plpgsql_ns_lookup_label(label_name) == NULL)
+		yyerror("no such label");
+	return label_name;
+}
+
 static void
 check_labels(const char *start_label, const char *end_label)
 {
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index edb423e521..2e76b5e187 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.119 2007/11/15 21:14:46 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.120 2007/11/27 19:58:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -787,7 +787,7 @@ plpgsql_compile_error_callback(void *arg)
  * ----------
  */
 int
-plpgsql_parse_word(char *word)
+plpgsql_parse_word(const char *word)
 {
 	PLpgSQL_nsitem *nse;
 	char	   *cp[1];
@@ -797,6 +797,7 @@ plpgsql_parse_word(char *word)
 
 	/*
 	 * Recognize tg_argv when compiling triggers
+	 * (XXX this sucks, it should be a regular variable in the namestack)
 	 */
 	if (plpgsql_curr_compile->fn_functype == T_TRIGGER)
 	{
@@ -825,15 +826,13 @@ plpgsql_parse_word(char *word)
 	/*
 	 * Do a lookup on the compiler's namestack
 	 */
-	nse = plpgsql_ns_lookup(cp[0], NULL);
+	nse = plpgsql_ns_lookup(cp[0], NULL, NULL, NULL);
+	pfree(cp[0]);
+
 	if (nse != NULL)
 	{
-		pfree(cp[0]);
 		switch (nse->itemtype)
 		{
-			case PLPGSQL_NSTYPE_LABEL:
-				return T_LABEL;
-
 			case PLPGSQL_NSTYPE_VAR:
 				plpgsql_yylval.scalar = plpgsql_Datums[nse->itemno];
 				return T_SCALAR;
@@ -855,7 +854,6 @@ plpgsql_parse_word(char *word)
 	 * Nothing found - up to now it's a word without any special meaning for
 	 * us.
 	 */
-	pfree(cp[0]);
 	return T_WORD;
 }
 
@@ -866,18 +864,19 @@ plpgsql_parse_word(char *word)
  * ----------
  */
 int
-plpgsql_parse_dblword(char *word)
+plpgsql_parse_dblword(const char *word)
 {
 	PLpgSQL_nsitem *ns;
 	char	   *cp[2];
+	int			nnames;
 
 	/* Do case conversion and word separation */
 	plpgsql_convert_ident(word, cp, 2);
 
 	/*
-	 * Lookup the first word
+	 * Do a lookup on the compiler's namestack
 	 */
-	ns = plpgsql_ns_lookup(cp[0], NULL);
+	ns = plpgsql_ns_lookup(cp[0], cp[1], NULL, &nnames);
 	if (ns == NULL)
 	{
 		pfree(cp[0]);
@@ -887,39 +886,15 @@ plpgsql_parse_dblword(char *word)
 
 	switch (ns->itemtype)
 	{
-		case PLPGSQL_NSTYPE_LABEL:
-
-			/*
-			 * First word is a label, so second word could be a variable,
-			 * record or row in that bodies namestack. Anything else could
-			 * only be something in a query given to the SPI manager and
-			 * T_ERROR will get eaten up by the collector routines.
-			 */
-			ns = plpgsql_ns_lookup(cp[1], cp[0]);
+		case PLPGSQL_NSTYPE_VAR:
+			/* Block-qualified reference to scalar variable. */
+			plpgsql_yylval.scalar = plpgsql_Datums[ns->itemno];
 			pfree(cp[0]);
 			pfree(cp[1]);
-			if (ns == NULL)
-				return T_ERROR;
-			switch (ns->itemtype)
-			{
-				case PLPGSQL_NSTYPE_VAR:
-					plpgsql_yylval.scalar = plpgsql_Datums[ns->itemno];
-					return T_SCALAR;
-
-				case PLPGSQL_NSTYPE_REC:
-					plpgsql_yylval.rec = (PLpgSQL_rec *) (plpgsql_Datums[ns->itemno]);
-					return T_RECORD;
-
-				case PLPGSQL_NSTYPE_ROW:
-					plpgsql_yylval.row = (PLpgSQL_row *) (plpgsql_Datums[ns->itemno]);
-					return T_ROW;
-
-				default:
-					return T_ERROR;
-			}
-			break;
+			return T_SCALAR;
 
 		case PLPGSQL_NSTYPE_REC:
+			if (nnames == 1)
 			{
 				/*
 				 * First word is a record name, so second word must be a field
@@ -940,8 +915,17 @@ plpgsql_parse_dblword(char *word)
 				pfree(cp[1]);
 				return T_SCALAR;
 			}
+			else
+			{
+				/* Block-qualified reference to record variable. */
+				plpgsql_yylval.rec = (PLpgSQL_rec *) (plpgsql_Datums[ns->itemno]);
+				pfree(cp[0]);
+				pfree(cp[1]);
+				return T_RECORD;
+			}
 
 		case PLPGSQL_NSTYPE_ROW:
+			if (nnames == 1)
 			{
 				/*
 				 * First word is a row name, so second word must be a field in
@@ -967,6 +951,14 @@ plpgsql_parse_dblword(char *word)
 						 errmsg("row \"%s\" has no field \"%s\"",
 								cp[0], cp[1])));
 			}
+			else
+			{
+				/* Block-qualified reference to row variable. */
+				plpgsql_yylval.row = (PLpgSQL_row *) (plpgsql_Datums[ns->itemno]);
+				pfree(cp[0]);
+				pfree(cp[1]);
+				return T_ROW;
+			}
 
 		default:
 			break;
@@ -984,38 +976,21 @@ plpgsql_parse_dblword(char *word)
  * ----------
  */
 int
-plpgsql_parse_tripword(char *word)
+plpgsql_parse_tripword(const char *word)
 {
 	PLpgSQL_nsitem *ns;
 	char	   *cp[3];
+	int			nnames;
 
 	/* Do case conversion and word separation */
 	plpgsql_convert_ident(word, cp, 3);
 
 	/*
-	 * Lookup the first word - it must be a label
+	 * Do a lookup on the compiler's namestack.
+	 * Must find a qualified reference.
 	 */
-	ns = plpgsql_ns_lookup(cp[0], NULL);
-	if (ns == NULL)
-	{
-		pfree(cp[0]);
-		pfree(cp[1]);
-		pfree(cp[2]);
-		return T_ERROR;
-	}
-	if (ns->itemtype != PLPGSQL_NSTYPE_LABEL)
-	{
-		pfree(cp[0]);
-		pfree(cp[1]);
-		pfree(cp[2]);
-		return T_ERROR;
-	}
-
-	/*
-	 * First word is a label, so second word could be a record or row
-	 */
-	ns = plpgsql_ns_lookup(cp[1], cp[0]);
-	if (ns == NULL)
+	ns = plpgsql_ns_lookup(cp[0], cp[1], cp[2], &nnames);
+	if (ns == NULL || nnames != 2)
 	{
 		pfree(cp[0]);
 		pfree(cp[1]);
@@ -1028,7 +1003,7 @@ plpgsql_parse_tripword(char *word)
 		case PLPGSQL_NSTYPE_REC:
 			{
 				/*
-				 * This word is a record name, so third word must be a field
+				 * words 1/2 are a record name, so third word must be a field
 				 * in this record.
 				 */
 				PLpgSQL_recfield *new;
@@ -1052,7 +1027,7 @@ plpgsql_parse_tripword(char *word)
 		case PLPGSQL_NSTYPE_ROW:
 			{
 				/*
-				 * This word is a row name, so third word must be a field in
+				 * words 1/2 are a row name, so third word must be a field in
 				 * this row.
 				 */
 				PLpgSQL_row *row;
@@ -1114,11 +1089,10 @@ plpgsql_parse_wordtype(char *word)
 	pfree(cp[1]);
 
 	/*
-	 * Do a lookup on the compiler's namestack. But ensure it moves up to the
-	 * toplevel.
+	 * Do a lookup on the compiler's namestack.  Ensure we scan all levels.
 	 */
 	old_nsstate = plpgsql_ns_setlocal(false);
-	nse = plpgsql_ns_lookup(cp[0], NULL);
+	nse = plpgsql_ns_lookup(cp[0], NULL, NULL, NULL);
 	plpgsql_ns_setlocal(old_nsstate);
 
 	if (nse != NULL)
@@ -1200,32 +1174,21 @@ plpgsql_parse_dblwordtype(char *word)
 	word[i] = '.';
 	plpgsql_convert_ident(word, cp, 3);
 	word[i] = '%';
+	pfree(cp[2]);
 
 	/*
-	 * Lookup the first word
+	 * Do a lookup on the compiler's namestack.  Ensure we scan all levels.
+	 * We don't need to check number of names matched, because we will only
+	 * consider scalar variables.
 	 */
-	nse = plpgsql_ns_lookup(cp[0], NULL);
+	old_nsstate = plpgsql_ns_setlocal(false);
+	nse = plpgsql_ns_lookup(cp[0], cp[1], NULL, NULL);
+	plpgsql_ns_setlocal(old_nsstate);
 
-	/*
-	 * If this is a label lookup the second word in that label's namestack
-	 * level
-	 */
-	if (nse != NULL)
+	if (nse != NULL && nse->itemtype == PLPGSQL_NSTYPE_VAR)
 	{
-		if (nse->itemtype == PLPGSQL_NSTYPE_LABEL)
-		{
-			old_nsstate = plpgsql_ns_setlocal(false);
-			nse = plpgsql_ns_lookup(cp[1], cp[0]);
-			plpgsql_ns_setlocal(old_nsstate);
-
-			if (nse != NULL && nse->itemtype == PLPGSQL_NSTYPE_VAR)
-			{
-				plpgsql_yylval.dtype = ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype;
-				result = T_DTYPE;
-			}
-		}
-
-		/* Return T_ERROR if not found, otherwise T_DTYPE */
+		plpgsql_yylval.dtype = ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype;
+		result = T_DTYPE;
 		goto done;
 	}
 
@@ -1291,8 +1254,6 @@ done:
  * plpgsql_parse_tripwordtype		Same lookup for word.word.word%TYPE
  * ----------
  */
-#define TYPE_JUNK_LEN	5
-
 int
 plpgsql_parse_tripwordtype(char *word)
 {
@@ -1302,10 +1263,7 @@ plpgsql_parse_tripwordtype(char *word)
 	HeapTuple	typetup = NULL;
 	Form_pg_class classStruct;
 	Form_pg_attribute attrStruct;
-	char	   *cp[2];
-	char	   *colname[1];
-	int			qualified_att_len;
-	int			numdots = 0;
+	char	   *cp[4];
 	int			i;
 	RangeVar   *relvar;
 	MemoryContext oldCxt;
@@ -1315,27 +1273,15 @@ plpgsql_parse_tripwordtype(char *word)
 	oldCxt = MemoryContextSwitchTo(compile_tmp_cxt);
 
 	/* Do case conversion and word separation */
-	qualified_att_len = strlen(word) - TYPE_JUNK_LEN;
-	Assert(word[qualified_att_len] == '%');
+	/* We convert %type to .type momentarily to keep converter happy */
+	i = strlen(word) - 5;
+	Assert(word[i] == '%');
+	word[i] = '.';
+	plpgsql_convert_ident(word, cp, 4);
+	word[i] = '%';
+	pfree(cp[3]);
 
-	for (i = 0; i < qualified_att_len; i++)
-	{
-		if (word[i] == '.' && ++numdots == 2)
-			break;
-	}
-
-	cp[0] = (char *) palloc((i + 1) * sizeof(char));
-	memcpy(cp[0], word, i * sizeof(char));
-	cp[0][i] = '\0';
-
-	/*
-	 * qualified_att_len - one based position + 1 (null terminator)
-	 */
-	cp[1] = (char *) palloc((qualified_att_len - i) * sizeof(char));
-	memcpy(cp[1], &word[i + 1], (qualified_att_len - i - 1) * sizeof(char));
-	cp[1][qualified_att_len - i - 1] = '\0';
-
-	relvar = makeRangeVarFromNameList(stringToQualifiedNameList(cp[0]));
+	relvar = makeRangeVar(cp[0], cp[1]);
 	classOid = RangeVarGetRelid(relvar, true);
 	if (!OidIsValid(classOid))
 		goto done;
@@ -1359,8 +1305,7 @@ plpgsql_parse_tripwordtype(char *word)
 	/*
 	 * Fetch the named table field and its type
 	 */
-	plpgsql_convert_ident(cp[1], colname, 1);
-	attrtup = SearchSysCacheAttName(classOid, colname[0]);
+	attrtup = SearchSysCacheAttName(classOid, cp[2]);
 	if (!HeapTupleIsValid(attrtup))
 		goto done;
 	attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup);
@@ -1436,13 +1381,11 @@ plpgsql_parse_wordrowtype(char *word)
  *			So word must be a namespace qualified table name.
  * ----------
  */
-#define ROWTYPE_JUNK_LEN	8
-
 int
 plpgsql_parse_dblwordrowtype(char *word)
 {
 	Oid			classOid;
-	char	   *cp;
+	char	   *cp[3];
 	int			i;
 	RangeVar   *relvar;
 	MemoryContext oldCxt;
@@ -1452,19 +1395,19 @@ plpgsql_parse_dblwordrowtype(char *word)
 
 	/* Do case conversion and word separation */
 	/* We convert %rowtype to .rowtype momentarily to keep converter happy */
-	i = strlen(word) - ROWTYPE_JUNK_LEN;
+	i = strlen(word) - 8;
 	Assert(word[i] == '%');
-	word[i] = '\0';
-	cp = pstrdup(word);
+	word[i] = '.';
+	plpgsql_convert_ident(word, cp, 3);
 	word[i] = '%';
 
 	/* Lookup the relation */
-	relvar = makeRangeVarFromNameList(stringToQualifiedNameList(cp));
+	relvar = makeRangeVar(cp[0], cp[1]);
 	classOid = RangeVarGetRelid(relvar, true);
 	if (!OidIsValid(classOid))
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_TABLE),
-				 errmsg("relation \"%s\" does not exist", cp)));
+				 errmsg("relation \"%s.%s\" does not exist", cp[0], cp[1])));
 
 	/* Build and return the row type struct */
 	plpgsql_yylval.dtype = plpgsql_build_datatype(get_rel_type_id(classOid),
diff --git a/src/pl/plpgsql/src/pl_funcs.c b/src/pl/plpgsql/src/pl_funcs.c
index 573bfd4e0c..66e0f47d8c 100644
--- a/src/pl/plpgsql/src/pl_funcs.c
+++ b/src/pl/plpgsql/src/pl_funcs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.65 2007/11/15 22:25:17 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.66 2007/11/27 19:58:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -126,9 +126,15 @@ plpgsql_ns_init(void)
 
 
 /* ----------
- * plpgsql_ns_setlocal			Tell plpgsql_ns_lookup to or to
- *					not look into the current level
- *					only.
+ * plpgsql_ns_setlocal			Tell plpgsql_ns_lookup whether to
+ *					look into the current level only.
+ *
+ * This is a crock, but in the current design we need it because scan.l
+ * initiates name lookup, and the scanner does not know whether we are
+ * examining a name being declared in a DECLARE section.  For that case
+ * we only want to know if there is a conflicting name earlier in the
+ * same DECLARE section.  So the grammar must temporarily set local mode
+ * before scanning decl_varnames.
  * ----------
  */
 bool
@@ -219,59 +225,98 @@ plpgsql_ns_additem(int itemtype, int itemno, const char *name)
 
 
 /* ----------
- * plpgsql_ns_lookup			Lookup for a word in the namestack
+ * plpgsql_ns_lookup			Lookup an identifier in the namestack
+ *
+ * Note that this only searches for variables, not labels.
+ *
+ * name1 must be non-NULL.  Pass NULL for name2 and/or name3 if parsing a name
+ * with fewer than three components.
+ *
+ * If names_used isn't NULL, *names_used receives the number of names
+ * matched: 0 if no match, 1 if name1 matched an unqualified variable name,
+ * 2 if name1 and name2 matched a block label + variable name.
+ *
+ * Note that name3 is never directly matched to anything.  However, if it
+ * isn't NULL, we will disregard qualified matches to scalar variables.
+ * Similarly, if name2 isn't NULL, we disregard unqualified matches to
+ * scalar variables.
  * ----------
  */
 PLpgSQL_nsitem *
-plpgsql_ns_lookup(const char *name, const char *label)
+plpgsql_ns_lookup(const char *name1, const char *name2, const char *name3,
+				  int *names_used)
 {
 	PLpgSQL_ns *ns;
 	int			i;
 
-	/*
-	 * If a label is specified, lookup only in that
-	 */
-	if (label != NULL)
+	/* Scan each level of the namestack */
+	for (ns = ns_current; ns != NULL; ns = ns->upper)
 	{
-		for (ns = ns_current; ns != NULL; ns = ns->upper)
+		/* Check for unqualified match to variable name */
+		for (i = 1; i < ns->items_used; i++)
 		{
-			if (strcmp(ns->items[0]->name, label) == 0)
+			PLpgSQL_nsitem *nsitem = ns->items[i];
+
+			if (strcmp(nsitem->name, name1) == 0)
 			{
-				for (i = 1; i < ns->items_used; i++)
+				if (name2 == NULL ||
+					nsitem->itemtype != PLPGSQL_NSTYPE_VAR)
 				{
-					if (strcmp(ns->items[i]->name, name) == 0)
-						return ns->items[i];
+					if (names_used)
+						*names_used = 1;
+					return nsitem;
 				}
-				return NULL;	/* name not found in specified label */
 			}
 		}
-		return NULL;			/* label not found */
+
+		/* Check for qualified match to variable name */
+		if (name2 != NULL &&
+			strcmp(ns->items[0]->name, name1) == 0)
+		{
+			for (i = 1; i < ns->items_used; i++)
+			{
+				PLpgSQL_nsitem *nsitem = ns->items[i];
+
+				if (strcmp(nsitem->name, name2) == 0)
+				{
+					if (name3 == NULL ||
+						nsitem->itemtype != PLPGSQL_NSTYPE_VAR)
+					{
+						if (names_used)
+							*names_used = 2;
+						return nsitem;
+					}
+				}
+			}
+		}
+
+		if (ns_localmode)
+			break;				/* do not look into upper levels */
 	}
 
-	/*
-	 * No label given, lookup for visible labels ignoring localmode
-	 */
+	/* This is just to suppress possibly-uninitialized-variable warnings */
+	if (names_used)
+		*names_used = 0;
+	return NULL;				/* No match found */
+}
+
+
+/* ----------
+ * plpgsql_ns_lookup_label		Lookup a label in the namestack
+ * ----------
+ */
+PLpgSQL_nsitem *
+plpgsql_ns_lookup_label(const char *name)
+{
+	PLpgSQL_ns *ns;
+
 	for (ns = ns_current; ns != NULL; ns = ns->upper)
 	{
 		if (strcmp(ns->items[0]->name, name) == 0)
 			return ns->items[0];
 	}
 
-	/*
-	 * Finally lookup name in the namestack
-	 */
-	for (ns = ns_current; ns != NULL; ns = ns->upper)
-	{
-		for (i = 1; i < ns->items_used; i++)
-		{
-			if (strcmp(ns->items[i]->name, name) == 0)
-				return ns->items[i];
-		}
-		if (ns_localmode)
-			return NULL;		/* name not found in current namespace */
-	}
-
-	return NULL;
+	return NULL;				/* label not found */
 }
 
 
@@ -846,8 +891,9 @@ static void
 dump_exit(PLpgSQL_stmt_exit *stmt)
 {
 	dump_ind();
-	printf("%s label='%s'",
-		   stmt->is_exit ? "EXIT" : "CONTINUE", stmt->label);
+	printf("%s", stmt->is_exit ? "EXIT" : "CONTINUE");
+	if (stmt->label != NULL)
+		printf(" label='%s'", stmt->label);
 	if (stmt->cond != NULL)
 	{
 		printf(" WHEN ");
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index 6ba0126b49..7bbed551ab 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.93 2007/11/15 22:25:17 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.94 2007/11/27 19:58:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -473,7 +473,7 @@ typedef struct
 	int			cmd_type;
 	int			lineno;
 	bool		is_exit;		/* Is this an exit or a continue? */
-	char	   *label;
+	char	   *label;			/* NULL if it's an unlabelled EXIT/CONTINUE */
 	PLpgSQL_expr *cond;
 } PLpgSQL_stmt_exit;
 
@@ -723,9 +723,9 @@ extern PLpgSQL_plugin **plugin_ptr;
  */
 extern PLpgSQL_function *plpgsql_compile(FunctionCallInfo fcinfo,
 				bool forValidator);
-extern int	plpgsql_parse_word(char *word);
-extern int	plpgsql_parse_dblword(char *word);
-extern int	plpgsql_parse_tripword(char *word);
+extern int	plpgsql_parse_word(const char *word);
+extern int	plpgsql_parse_dblword(const char *word);
+extern int	plpgsql_parse_tripword(const char *word);
 extern int	plpgsql_parse_wordtype(char *word);
 extern int	plpgsql_parse_dblwordtype(char *word);
 extern int	plpgsql_parse_tripwordtype(char *word);
@@ -773,7 +773,7 @@ extern void plpgsql_dstring_append_char(PLpgSQL_dstring *ds, char c);
 extern char *plpgsql_dstring_get(PLpgSQL_dstring *ds);
 
 /* ----------
- * Functions for the namestack handling in pl_funcs.c
+ * Functions for namestack handling in pl_funcs.c
  * ----------
  */
 extern void plpgsql_ns_init(void);
@@ -781,7 +781,9 @@ extern bool plpgsql_ns_setlocal(bool flag);
 extern void plpgsql_ns_push(const char *label);
 extern void plpgsql_ns_pop(void);
 extern void plpgsql_ns_additem(int itemtype, int itemno, const char *name);
-extern PLpgSQL_nsitem *plpgsql_ns_lookup(const char *name, const char *nsname);
+extern PLpgSQL_nsitem *plpgsql_ns_lookup(const char *name1, const char *name2,
+										 const char *name3, int *names_used);
+extern PLpgSQL_nsitem *plpgsql_ns_lookup_label(const char *name);
 extern void plpgsql_ns_rename(char *oldname, char *newname);
 
 /* ----------