diff --git a/src/backend/optimizer/path/clausesel.c b/src/backend/optimizer/path/clausesel.c
index 37d438fefce663584288cec4edb13f47d51d6c2c..3ff02902f7c7e52c82bce4981b0f44105c62dc01 100644
--- a/src/backend/optimizer/path/clausesel.c
+++ b/src/backend/optimizer/path/clausesel.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/path/clausesel.c,v 1.78 2006/03/05 15:58:28 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/path/clausesel.c,v 1.79 2006/03/07 01:00:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -449,8 +449,6 @@ clause_selectivity(PlannerInfo *root,
 					cacheable = true;
 					break;
 
-				case JOIN_UNION:
-					/* unimplemented anyway... */
 				case JOIN_IN:
 				case JOIN_REVERSE_IN:
 				case JOIN_UNIQUE_OUTER:
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 21b10cf817cd65b7b725879e76ad4aad16fc6d81..d980cde06bca9c1741f52985955c17960c94de30 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.115 2006/03/05 15:58:29 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.116 2006/03/07 01:00:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -363,18 +363,6 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
 				*qualscope = bms_union(leftids, rightids);
 				nonnullable_rels = leftids;
 				break;
-			case JOIN_UNION:
-
-				/*
-				 * This is where we fail if upper levels of planner haven't
-				 * rewritten UNION JOIN as an Append ...
-				 */
-				ereport(ERROR,
-						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-						 errmsg("UNION JOIN is not implemented")));
-				nonnullable_rels = NULL;		/* keep compiler quiet */
-				leftjoinlist = rightjoinlist = NIL;
-				break;
 			default:
 				elog(ERROR, "unrecognized join type: %d",
 					 (int) j->jointype);
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index c318b89d39c84812a095f1ee28a34ad425fcc49c..ae538c9cc00e62e16869f4e7e79f6b3acd109873 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.36 2006/03/05 15:58:30 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.37 2006/03/07 01:00:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -242,16 +242,6 @@ pull_up_subqueries(PlannerInfo *root, Node *jtnode,
 				j->rarg = pull_up_subqueries(root, j->rarg,
 											 below_outer_join, false);
 				break;
-			case JOIN_UNION:
-
-				/*
-				 * This is where we fail if upper levels of planner haven't
-				 * rewritten UNION JOIN as an Append ...
-				 */
-				ereport(ERROR,
-						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-						 errmsg("UNION JOIN is not implemented")));
-				break;
 			default:
 				elog(ERROR, "unrecognized join type: %d",
 					 (int) j->jointype);
diff --git a/src/backend/parser/Makefile b/src/backend/parser/Makefile
index da5ac26ed6744acd8cb8d5260b0ec3981a6994db..553fda257e1bcf88137ded726861c03359f037de 100644
--- a/src/backend/parser/Makefile
+++ b/src/backend/parser/Makefile
@@ -2,7 +2,7 @@
 #
 # Makefile for parser
 #
-# $PostgreSQL: pgsql/src/backend/parser/Makefile,v 1.42 2003/11/29 19:51:51 pgsql Exp $
+# $PostgreSQL: pgsql/src/backend/parser/Makefile,v 1.43 2006/03/07 01:00:17 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -57,8 +57,7 @@ endif
 
 
 # Force these dependencies to be known even without dependency info built:
-
-gram.o keywords.o parser.o: $(srcdir)/parse.h
+gram.o keywords.o: $(srcdir)/parse.h
 
 
 # gram.c, parse.h, and scan.c are in the distribution tarball, so they
@@ -66,4 +65,4 @@ gram.o keywords.o parser.o: $(srcdir)/parse.h
 clean: 
 	rm -f SUBSYS.o $(OBJS)
 # And the garbage that might have been left behind by partial build:
-	@rm -f y.tab.c y.tab.h lex.yy.c
+	@rm -f y.tab.h y.tab.c y.output lex.yy.c
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 135f2272defd55fc068a28fb96ab21b231fce58e..c86a6888f205a960d65c9f1be549d8b8f7c8ecdc 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.533 2006/03/05 15:58:32 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.534 2006/03/07 01:00:16 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -95,6 +95,7 @@ static void doNegateFloat(Value *v);
 
 %}
 
+%name-prefix="base_yy"
 
 %union
 {
@@ -418,12 +419,6 @@ static void doNegateFloat(Value *v);
 
 	ZONE
 
-/* The grammar thinks these are keywords, but they are not in the keywords.c
- * list and so can never be entered directly.  The filter in parser.c
- * creates these tokens when required.
- */
-%token			UNIONJOIN
-
 /* Special token types, not actually keywords - see the "lex" file */
 %token <str>	IDENT FCONST SCONST BCONST XCONST Op
 %token <ival>	ICONST PARAM
@@ -464,7 +459,7 @@ static void doNegateFloat(Value *v);
  * They wouldn't be given a precedence at all, were it not that we need
  * left-associativity among the JOIN rules themselves.
  */
-%left		JOIN UNIONJOIN CROSS LEFT FULL RIGHT INNER_P NATURAL
+%left		JOIN CROSS LEFT FULL RIGHT INNER_P NATURAL
 %%
 
 /*
@@ -5774,20 +5769,6 @@ joined_table:
 					n->quals = NULL;
 					$$ = n;
 				}
-			| table_ref UNIONJOIN table_ref
-				{
-					/* UNION JOIN is made into 1 token to avoid shift/reduce
-					 * conflict against regular UNION keyword.
-					 */
-					JoinExpr *n = makeNode(JoinExpr);
-					n->jointype = JOIN_UNION;
-					n->isNatural = FALSE;
-					n->larg = $1;
-					n->rarg = $3;
-					n->using = NIL;
-					n->quals = NULL;
-					$$ = n;
-				}
 			| table_ref join_type JOIN table_ref join_qual
 				{
 					JoinExpr *n = makeNode(JoinExpr);
diff --git a/src/backend/parser/parser.c b/src/backend/parser/parser.c
index 4b5d12c0bf439c3b6a07829601113769a786a965..6c331ad338d8c904eb896464b21fd9dfdc0a43c9 100644
--- a/src/backend/parser/parser.c
+++ b/src/backend/parser/parser.c
@@ -7,32 +7,26 @@
  * (since we need to be able to do basic parsing even while inside an
  * aborted transaction).  Therefore, the data structures returned by
  * the grammar are "raw" parsetrees that still need to be analyzed by
- * parse_analyze.
+ * analyze.c and related files.
  *
  *
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/parser.c,v 1.64 2006/03/05 15:58:34 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/parser.c,v 1.65 2006/03/07 01:00:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
 
-#include "nodes/parsenodes.h"
 #include "parser/gramparse.h"
-#include "parser/parse.h"
 #include "parser/parser.h"
-#include "parser/parse_expr.h"
 
 
 List	   *parsetree;			/* result of parsing is left here */
 
-static int	lookahead_token;	/* one-token lookahead */
-static bool have_lookahead;		/* lookahead_token set? */
-
 
 /*
  * raw_parser
@@ -46,12 +40,11 @@ raw_parser(const char *str)
 	int			yyresult;
 
 	parsetree = NIL;			/* in case grammar forgets to set it */
-	have_lookahead = false;
 
 	scanner_init(str);
 	parser_init();
 
-	yyresult = yyparse();
+	yyresult = base_yyparse();
 
 	scanner_finish();
 
@@ -60,48 +53,3 @@ raw_parser(const char *str)
 
 	return parsetree;
 }
-
-
-/*
- * Intermediate filter between parser and base lexer (base_yylex in scan.l).
- *
- * The filter is needed because in some cases SQL92 requires more than one
- * token lookahead.  We reduce these cases to one-token lookahead by combining
- * tokens here, in order to keep the grammar LR(1).
- *
- * Using a filter is simpler than trying to recognize multiword tokens
- * directly in scan.l, because we'd have to allow for comments between the
- * words ...
- */
-int
-yylex(void)
-{
-	int			cur_token;
-
-	/* Get next token --- we might already have it */
-	if (have_lookahead)
-	{
-		cur_token = lookahead_token;
-		have_lookahead = false;
-	}
-	else
-		cur_token = base_yylex();
-
-	/* Do we need to look ahead for a possible multiword token? */
-	switch (cur_token)
-	{
-		case UNION:
-			/* UNION JOIN must be reduced to a single UNIONJOIN token */
-			lookahead_token = base_yylex();
-			if (lookahead_token == JOIN)
-				cur_token = UNIONJOIN;
-			else
-				have_lookahead = true;
-			break;
-
-		default:
-			break;
-	}
-
-	return cur_token;
-}
diff --git a/src/backend/parser/scan.l b/src/backend/parser/scan.l
index e277920ee2037224309a6084ba8a9e27d1bf0a0f..3d63cb73c8aabb9db77907c23d0095c4bcd543b2 100644
--- a/src/backend/parser/scan.l
+++ b/src/backend/parser/scan.l
@@ -24,7 +24,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/scan.l,v 1.131 2006/03/06 19:49:20 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/scan.l,v 1.132 2006/03/07 01:00:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -45,8 +45,6 @@
 #undef fprintf
 #define fprintf(file, fmt, msg)  ereport(ERROR, (errmsg_internal("%s", msg)))
 
-extern YYSTYPE yylval;
-
 static int		xcdepth = 0;	/* depth of nesting in slash-star comments */
 static char    *dolqstart;      /* current $foo$ quote start string */
 
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 05e817ecc085d9043335d21e3a737f6637bd7b45..d6e8907c73f73cd9e02052c78d0bab1f9b484f0b 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -3,7 +3,7 @@
  *				back to source text
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.213 2006/01/26 17:08:19 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.214 2006/03/07 01:00:17 tgl Exp $
  *
  *	  This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -4357,11 +4357,6 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
 										 -PRETTYINDENT_JOIN,
 										 PRETTYINDENT_JOIN, 0);
 					break;
-				case JOIN_UNION:
-					appendContextKeyword(context, "NATURAL UNION JOIN ",
-										 -PRETTYINDENT_JOIN,
-										 PRETTYINDENT_JOIN, 0);
-					break;
 				default:
 					elog(ERROR, "unrecognized join type: %d",
 						 (int) j->jointype);
@@ -4396,11 +4391,6 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
 										 -PRETTYINDENT_JOIN,
 										 PRETTYINDENT_JOIN, 2);
 					break;
-				case JOIN_UNION:
-					appendContextKeyword(context, " UNION JOIN ",
-										 -PRETTYINDENT_JOIN,
-										 PRETTYINDENT_JOIN, 2);
-					break;
 				default:
 					elog(ERROR, "unrecognized join type: %d",
 						 (int) j->jointype);
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index b092563e41c53badf83a1bd1a75954cdc0765203..b8415378d950238a80e7ba6cea4cd2c103144e40 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.183 2006/03/05 15:58:56 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.184 2006/03/07 01:00:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -457,13 +457,6 @@ typedef enum JoinType
 	JOIN_FULL,					/* pairs + unmatched outer + unmatched inner */
 	JOIN_RIGHT,					/* pairs + unmatched inner tuples */
 
-	/*
-	 * SQL92 considers UNION JOIN to be a kind of join, so list it here for
-	 * parser convenience, even though it's not implemented like a join in the
-	 * executor.  (The planner must convert it to an Append plan.)
-	 */
-	JOIN_UNION,
-
 	/*
 	 * These are used for queries like WHERE foo IN (SELECT bar FROM ...).
 	 * Only JOIN_IN is actually implemented in the executor; the others are
diff --git a/src/include/parser/gramparse.h b/src/include/parser/gramparse.h
index eb043965d0dfba95ef0edff2620ac9f7d3ac4343..054604521bc754d128888f829bd720a415222fe3 100644
--- a/src/include/parser/gramparse.h
+++ b/src/include/parser/gramparse.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/parser/gramparse.h,v 1.32 2006/03/05 15:58:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/parser/gramparse.h,v 1.33 2006/03/07 01:00:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,18 +18,15 @@
 #include "nodes/parsenodes.h"
 
 
-/* from parser.c */
-extern int	yylex(void);
-
 /* from scan.l */
 extern void scanner_init(const char *str);
 extern void scanner_finish(void);
 extern int	base_yylex(void);
-extern void yyerror(const char *message);
+extern void base_yyerror(const char *message);
 
 /* from gram.y */
 extern void parser_init(void);
-extern int	yyparse(void);
+extern int	base_yyparse(void);
 extern List *SystemFuncName(char *name);
 extern TypeName *SystemTypeName(char *name);
 extern bool exprIsNullConstant(Node *arg);
diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y
index 4c07d4218c0a85ca2495651013126eff65062645..c73aa41a19f2898deccc0f4fe5471217f4b85102 100644
--- a/src/interfaces/ecpg/preproc/preproc.y
+++ b/src/interfaces/ecpg/preproc/preproc.y
@@ -1,4 +1,4 @@
-/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/preproc.y,v 1.320 2006/02/08 09:10:04 meskes Exp $ */
+/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/preproc.y,v 1.321 2006/03/07 01:00:19 tgl Exp $ */
 
 /* Copyright comment */
 %{
@@ -426,12 +426,6 @@ add_additional_variables(char *name, bool insert)
 	YEAR_P
 	ZONE
 
-/* The grammar thinks these are keywords, but they are not in the keywords.c
- * list and so can never be entered directly.  The filter in parser.c
- * creates these tokens when required.
- */
-%token	UNIONJOIN
-
 /* Special token types, not actually keywords - see the "lex" file */
 %token <str>	IDENT SCONST Op CSTRING CVARIABLE CPP_LINE IP BCONST XCONST DOLCONST
 %token <ival>	ICONST PARAM
@@ -465,7 +459,7 @@ add_additional_variables(char *name, bool insert)
 %left		'(' ')'
 %left		TYPECAST
 %left		'.'
-%left		JOIN UNIONJOIN CROSS LEFT FULL RIGHT INNER_P NATURAL
+%left		JOIN CROSS LEFT FULL RIGHT INNER_P NATURAL
 
 %type  <str>	Iconst Fconst Sconst TransactionStmt CreateStmt RoleId
 %type  <str>	CreateAsElement OptCreateAs CreateAsList CreateAsStmt
@@ -3391,8 +3385,6 @@ joined_table:  '(' joined_table ')'
 			{ $$ = cat_str(3, make_str("("), $2, make_str(")")); }
 		| table_ref CROSS JOIN table_ref
 			{ $$ = cat_str(3, $1, make_str("cross join"), $4); }
-		| table_ref UNIONJOIN table_ref
-			{ $$ = cat_str(3, $1, make_str("unionjoin"), $3); }
 		| table_ref join_type JOIN table_ref join_qual
 			{ $$ = cat_str(5, $1, $2, make_str("join"), $4, $5); }
 		| table_ref JOIN table_ref join_qual
diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out
index 614f6f07858d3a775124c7ef459b0fb9062c8e37..0a7c5605cd255a611bd97b2b924ae194316ed3d2 100644
--- a/src/test/regress/expected/join.out
+++ b/src/test/regress/expected/join.out
@@ -1846,10 +1846,6 @@ SELECT '' AS "xxx", *
 --
 -- More complicated constructs
 --
--- UNION JOIN isn't implemented yet
-SELECT '' AS "xxx", *
-  FROM J1_TBL UNION JOIN J2_TBL;
-ERROR:  UNION JOIN is not implemented
 --
 -- Multiway full join
 --
diff --git a/src/test/regress/expected/join_1.out b/src/test/regress/expected/join_1.out
index 725cbee267751dad0b3353b217a03949fde87c21..289ccb6c9f7940abc972c457aef0d97c4493eb53 100644
--- a/src/test/regress/expected/join_1.out
+++ b/src/test/regress/expected/join_1.out
@@ -1846,10 +1846,6 @@ SELECT '' AS "xxx", *
 --
 -- More complicated constructs
 --
--- UNION JOIN isn't implemented yet
-SELECT '' AS "xxx", *
-  FROM J1_TBL UNION JOIN J2_TBL;
-ERROR:  UNION JOIN is not implemented
 --
 -- Multiway full join
 --
diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql
index a5e521e714a1125e4556880d314247aa6b91ea38..ffc2afe6ed441e2ec996769fd5a4d49b8bee4bcd 100644
--- a/src/test/regress/sql/join.sql
+++ b/src/test/regress/sql/join.sql
@@ -198,10 +198,6 @@ SELECT '' AS "xxx", *
 -- More complicated constructs
 --
 
--- UNION JOIN isn't implemented yet
-SELECT '' AS "xxx", *
-  FROM J1_TBL UNION JOIN J2_TBL;
-
 --
 -- Multiway full join
 --