diff --git a/src/backend/parser/Makefile b/src/backend/parser/Makefile
index 553fda257e1bcf88137ded726861c03359f037de..3099f77ca64faeb9978ef575f173f59770a2864e 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.43 2006/03/07 01:00:17 tgl Exp $
+# $PostgreSQL: pgsql/src/backend/parser/Makefile,v 1.44 2006/05/27 17:38:45 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -57,7 +57,7 @@ endif
 
 
 # Force these dependencies to be known even without dependency info built:
-gram.o keywords.o: $(srcdir)/parse.h
+gram.o keywords.o parser.o: $(srcdir)/parse.h
 
 
 # gram.c, parse.h, and scan.c are in the distribution tarball, so they
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 69e7a2014259c43b0f7e622fb87039655d5d4f54..d84f4034abab41cba17a337959633ad17dca107a 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.544 2006/04/30 18:30:39 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.545 2006/05/27 17:38:45 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -70,6 +70,12 @@
 			(Current) = (Rhs)[0]; \
 	} while (0)
 
+/*
+ * The %name-prefix option below will make bison call base_yylex, but we
+ * really want it to call filtered_base_yylex (see parser.c).
+ */
+#define base_yylex filtered_base_yylex
+
 extern List *parsetree;			/* final parse result is delivered here */
 
 static bool QueryIsRule = FALSE;
@@ -339,6 +345,7 @@ static void doNegateFloat(Value *v);
 %type <list>	constraints_set_list
 %type <boolean> constraints_set_mode
 %type <str>		OptTableSpace OptConsTableSpace OptTableSpaceOwner
+%type <list>	opt_check_option
 
 
 /*
@@ -356,7 +363,7 @@ static void doNegateFloat(Value *v);
 	BACKWARD BEFORE BEGIN_P BETWEEN BIGINT BINARY BIT
 	BOOLEAN_P BOTH BY
 
-	CACHE CALLED CASCADE CASE CAST CHAIN CHAR_P
+	CACHE CALLED CASCADE CASCADED CASE CAST CHAIN CHAR_P
 	CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
 	CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT
 	COMMITTED CONNECTION CONSTRAINT CONSTRAINTS CONVERSION_P CONVERT COPY CREATE CREATEDB
@@ -431,6 +438,12 @@ 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			WITH_CASCADED WITH_LOCAL WITH_CHECK
+
 /* Special token types, not actually keywords - see the "lex" file */
 %token <str>	IDENT FCONST SCONST BCONST XCONST Op
 %token <ival>	ICONST PARAM
@@ -4618,12 +4631,13 @@ transaction_mode_list_or_empty:
 /*****************************************************************************
  *
  *	QUERY:
- *		CREATE [ OR REPLACE ] [ TEMP ] VIEW <viewname> '('target-list ')' AS <query>
+ *		CREATE [ OR REPLACE ] [ TEMP ] VIEW <viewname> '('target-list ')'
+ *			AS <query> [ WITH [ CASCADED | LOCAL ] CHECK OPTION ]
  *
  *****************************************************************************/
 
 ViewStmt: CREATE OptTemp VIEW qualified_name opt_column_list
-				AS SelectStmt
+				AS SelectStmt opt_check_option
 				{
 					ViewStmt *n = makeNode(ViewStmt);
 					n->replace = false;
@@ -4634,7 +4648,7 @@ ViewStmt: CREATE OptTemp VIEW qualified_name opt_column_list
 					$$ = (Node *) n;
 				}
 		| CREATE OR REPLACE OptTemp VIEW qualified_name opt_column_list
-				AS SelectStmt
+				AS SelectStmt opt_check_option
 				{
 					ViewStmt *n = makeNode(ViewStmt);
 					n->replace = true;
@@ -4646,6 +4660,32 @@ ViewStmt: CREATE OptTemp VIEW qualified_name opt_column_list
 				}
 		;
 
+/*
+ * We use merged tokens here to avoid creating shift/reduce conflicts against
+ * a whole lot of other uses of WITH.
+ */
+opt_check_option:
+		WITH_CHECK OPTION
+				{
+					ereport(ERROR,
+							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							 errmsg("WITH CHECK OPTION is not implemented")));
+				}
+		| WITH_CASCADED CHECK OPTION
+				{
+					ereport(ERROR,
+							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							 errmsg("WITH CHECK OPTION is not implemented")));
+				}
+		| WITH_LOCAL CHECK OPTION
+				{
+					ereport(ERROR,
+							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							 errmsg("WITH CHECK OPTION is not implemented")));
+				}
+		| /* EMPTY */							{ $$ = NIL; }
+		;
+
 /*****************************************************************************
  *
  *		QUERY:
@@ -8319,6 +8359,7 @@ unreserved_keyword:
 			| CACHE
 			| CALLED
 			| CASCADE
+			| CASCADED
 			| CHAIN
 			| CHARACTERISTICS
 			| CHECKPOINT
@@ -9139,4 +9180,10 @@ doNegateFloat(Value *v)
 	}
 }
 
+/*
+ * Must undefine base_yylex before including scan.c, since we want it
+ * to create the function base_yylex not filtered_base_yylex.
+ */
+#undef base_yylex
+
 #include "scan.c"
diff --git a/src/backend/parser/parser.c b/src/backend/parser/parser.c
index 6c331ad338d8c904eb896464b21fd9dfdc0a43c9..de40e64fa8ae60298a7811812b4b36896e70b293 100644
--- a/src/backend/parser/parser.c
+++ b/src/backend/parser/parser.c
@@ -14,7 +14,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/parser.c,v 1.65 2006/03/07 01:00:17 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/parser.c,v 1.66 2006/05/27 17:38:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,11 +22,15 @@
 #include "postgres.h"
 
 #include "parser/gramparse.h"
+#include "parser/parse.h"
 #include "parser/parser.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
@@ -40,6 +44,7 @@ raw_parser(const char *str)
 	int			yyresult;
 
 	parsetree = NIL;			/* in case grammar forgets to set it */
+	have_lookahead = false;
 
 	scanner_init(str);
 	parser_init();
@@ -53,3 +58,70 @@ 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 the standard SQL grammar
+ * requires more than one token lookahead.  We reduce these cases to one-token
+ * lookahead by combining tokens here, in order to keep the grammar LALR(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.  Furthermore it's not clear how to do it without re-introducing
+ * scanner backtrack, which would cost more performance than this filter
+ * layer does.
+ */
+int
+filtered_base_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 WITH:
+			/*
+			 * WITH CASCADED, LOCAL, or CHECK must be reduced to one token
+			 *
+			 * XXX an alternative way is to recognize just WITH_TIME and
+			 * put the ugliness into the datetime datatype productions
+			 * instead of WITH CHECK OPTION.  However that requires promoting
+			 * WITH to a fully reserved word.  If we ever have to do that
+			 * anyway (perhaps for SQL99 recursive queries), come back and
+			 * simplify this code.
+			 */
+			lookahead_token = base_yylex();
+			switch (lookahead_token)
+			{
+				case CASCADED:
+					cur_token = WITH_CASCADED;
+					break;
+				case LOCAL:
+					cur_token = WITH_LOCAL;
+					break;
+				case CHECK:
+					cur_token = WITH_CHECK;
+					break;
+				default:
+					have_lookahead = true;
+					break;
+			}
+			break;
+
+		default:
+			break;
+	}
+
+	return cur_token;
+}
diff --git a/src/include/parser/gramparse.h b/src/include/parser/gramparse.h
index 38f4b26f94e7427eb8e85f0ccadc17c6c5ff2f6f..b61ceb0ac72348148cf9a3abeee70a4184933ec7 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.36 2006/05/21 20:10:42 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/parser/gramparse.h,v 1.37 2006/05/27 17:38:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -40,6 +40,9 @@ extern bool escape_string_warning;
 extern bool standard_conforming_strings;
 
 
+/* from parser.c */
+extern int	filtered_base_yylex(void);
+
 /* from scan.l */
 extern void scanner_init(const char *str);
 extern void scanner_finish(void);