diff --git a/src/backend/nls.mk b/src/backend/nls.mk
index 8b5504bb9715e7f90afb5d8a87b6caf0dc5e8b9d..45c51b3b73b849540f11cefd948b4f5ed9bfc297 100644
--- a/src/backend/nls.mk
+++ b/src/backend/nls.mk
@@ -1,8 +1,8 @@
-# $PostgreSQL: pgsql/src/backend/nls.mk,v 1.27 2009/06/26 19:33:43 petere Exp $
+# $PostgreSQL: pgsql/src/backend/nls.mk,v 1.28 2009/07/13 02:02:19 tgl Exp $
 CATALOG_NAME	:= postgres
 AVAIL_LANGUAGES	:= de es fr ja pt_BR tr
 GETTEXT_FILES	:= + gettext-files
-GETTEXT_TRIGGERS:= _ errmsg errmsg_plural:1,2 errdetail errdetail_log errdetail_plural:1,2 errhint errcontext write_stderr yyerror
+GETTEXT_TRIGGERS:= _ errmsg errmsg_plural:1,2 errdetail errdetail_log errdetail_plural:1,2 errhint errcontext write_stderr yyerror parser_yyerror
 
 gettext-files: distprep
 	find $(srcdir)/ $(srcdir)/../port/ -name '*.c' -print >$@
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index dd71071efd08b5bbd013aa51d47042af7b7ea325..f4b795db451d5754970ee1394e9da47b818c9046 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.667 2009/07/12 17:12:33 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.668 2009/07/13 02:02:20 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -92,10 +92,6 @@
 #define YYMALLOC palloc
 #define YYFREE   pfree
 
-extern List *parsetree;			/* final parse result is delivered here */
-
-static bool QueryIsRule = FALSE;
-
 /* Private struct for the result of privilege_target production */
 typedef struct PrivTarget
 {
@@ -103,14 +99,14 @@ typedef struct PrivTarget
 	List	   *objs;
 } PrivTarget;
 
-/*
- * If you need access to certain yacc-generated variables and find that
- * they're static by default, uncomment the next line.  (this is not a
- * problem, yet.)
- */
-/*#define __YYSCLASS*/
 
-static Node *makeColumnRef(char *colname, List *indirection, int location);
+#define parser_yyerror(msg)  scanner_yyerror(msg, yyscanner)
+#define parser_errposition(pos)  scanner_errposition(pos, yyscanner)
+
+static void base_yyerror(YYLTYPE *yylloc, base_yyscan_t yyscanner,
+						 const char *msg);
+static Node *makeColumnRef(char *colname, List *indirection,
+						   int location, base_yyscan_t yyscanner);
 static Node *makeTypeCast(Node *arg, TypeName *typename, int location);
 static Node *makeStringConst(char *str, int location);
 static Node *makeStringConstCast(char *str, int location, TypeName *typename);
@@ -120,16 +116,18 @@ static Node *makeBitStringConst(char *str, int location);
 static Node *makeNullAConst(int location);
 static Node *makeAConst(Value *v, int location);
 static Node *makeBoolAConst(bool state, int location);
-static FuncCall *makeOverlaps(List *largs, List *rargs, int location);
-static void check_qualified_name(List *names);
-static List *check_func_name(List *names);
-static List *check_indirection(List *indirection);
+static FuncCall *makeOverlaps(List *largs, List *rargs,
+							  int location, base_yyscan_t yyscanner);
+static void check_qualified_name(List *names, base_yyscan_t yyscanner);
+static List *check_func_name(List *names, base_yyscan_t yyscanner);
+static List *check_indirection(List *indirection, base_yyscan_t yyscanner);
 static List *extractArgTypes(List *parameters);
 static SelectStmt *findLeftmostSelect(SelectStmt *node);
 static void insertSelectOptions(SelectStmt *stmt,
 								List *sortClause, List *lockingClause,
 								Node *limitOffset, Node *limitCount,
-								WithClause *withClause);
+								WithClause *withClause,
+								base_yyscan_t yyscanner);
 static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg);
 static Node *doNegate(Node *n, int location);
 static void doNegateFloat(Value *v);
@@ -141,10 +139,14 @@ static TypeName *TableFuncTypeName(List *columns);
 
 %}
 
+%pure-parser
 %expect 0
 %name-prefix="base_yy"
 %locations
 
+%parse-param {base_yyscan_t yyscanner}
+%lex-param   {base_yyscan_t yyscanner}
+
 %union
 {
 	int					ival;
@@ -576,26 +578,29 @@ static TypeName *TableFuncTypeName(List *columns);
 %%
 
 /*
- *	Handle comment-only lines, and ;; SELECT * FROM pg_class ;;;
- *	psql already handles such cases, but other interfaces don't.
- *	bjm 1999/10/05
+ *	The target production for the whole parse.
  */
-stmtblock:	stmtmulti								{ parsetree = $1; }
+stmtblock:	stmtmulti
+			{
+				pg_yyget_extra(yyscanner)->parsetree = $1;
+			}
 		;
 
 /* the thrashing around here is to discard "empty" statements... */
 stmtmulti:	stmtmulti ';' stmt
-				{ if ($3 != NULL)
-					$$ = lappend($1, $3);
-				  else
-					$$ = $1;
+				{
+					if ($3 != NULL)
+						$$ = lappend($1, $3);
+					else
+						$$ = $1;
 				}
 			| stmt
-					{ if ($1 != NULL)
+				{
+					if ($1 != NULL)
 						$$ = list_make1($1);
-					  else
+					else
 						$$ = NIL;
-					}
+				}
 		;
 
 stmt :
@@ -1190,7 +1195,7 @@ set_rest:	/* Generic SET syntaxes: */
 					ereport(ERROR,
 							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 							 errmsg("current database cannot be changed"),
-							 scanner_errposition(@2)));
+							 parser_errposition(@2)));
 					$$ = NULL; /*not reached*/
 				}
 			| SCHEMA Sconst
@@ -1305,7 +1310,7 @@ zone_value:
 							ereport(ERROR,
 									(errcode(ERRCODE_SYNTAX_ERROR),
 									 errmsg("time zone interval must be HOUR or HOUR TO MINUTE"),
-									 scanner_errposition(@3)));
+									 parser_errposition(@3)));
 					}
 					t->typmods = $3;
 					$$ = makeStringConstCast($2, @2, t);
@@ -1320,12 +1325,12 @@ zone_value:
 							ereport(ERROR,
 									(errcode(ERRCODE_SYNTAX_ERROR),
 									 errmsg("time zone interval must be HOUR or HOUR TO MINUTE"),
-									 scanner_errposition(@6)));
+									 parser_errposition(@6)));
 						if (list_length($6) != 1)
 							ereport(ERROR,
 									(errcode(ERRCODE_SYNTAX_ERROR),
 									 errmsg("interval precision specified twice"),
-									 scanner_errposition(@1)));
+									 parser_errposition(@1)));
 						t->typmods = lappend($6, makeIntConst($3, @3));
 					}
 					else
@@ -2428,7 +2433,7 @@ key_match:  MATCH FULL
 				ereport(ERROR,
 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 						 errmsg("MATCH PARTIAL not yet implemented"),
-						 scanner_errposition(@1)));
+						 parser_errposition(@1)));
 				$$ = FKCONSTR_MATCH_PARTIAL;
 			}
 		| MATCH SIMPLE
@@ -2521,7 +2526,7 @@ CreateAsStmt:
 						ereport(ERROR,
 								(errcode(ERRCODE_SYNTAX_ERROR),
 								 errmsg("CREATE TABLE AS cannot specify INTO"),
-								 scanner_errposition(exprLocation((Node *) n->intoClause))));
+								 parser_errposition(exprLocation((Node *) n->intoClause))));
 					$4->rel->istemp = $2;
 					n->intoClause = $4;
 					/* Implement WITH NO DATA by forcing top-level LIMIT 0 */
@@ -3174,7 +3179,7 @@ TriggerEvents:
 			| TriggerEvents OR TriggerOneEvent
 				{
 					if ($1 & $3)
-						yyerror("duplicate trigger events specified");
+						parser_yyerror("duplicate trigger events specified");
 					$$ = $1 | $3;
 				}
 		;
@@ -3245,7 +3250,7 @@ ConstraintAttributeSpec:
 						ereport(ERROR,
 								(errcode(ERRCODE_SYNTAX_ERROR),
 								 errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"),
-								 scanner_errposition(@1)));
+								 parser_errposition(@1)));
 					$$ = $1 | $2;
 				}
 			| ConstraintTimeSpec
@@ -3261,7 +3266,7 @@ ConstraintAttributeSpec:
 						ereport(ERROR,
 								(errcode(ERRCODE_SYNTAX_ERROR),
 								 errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"),
-								 scanner_errposition(@1)));
+								 parser_errposition(@1)));
 					$$ = $1 | $2;
 				}
 			| /*EMPTY*/
@@ -3434,7 +3439,7 @@ DefineStmt:
 									(errcode(ERRCODE_SYNTAX_ERROR),
 									 errmsg("improper qualified name (too many dotted names): %s",
 											NameListToString($3)),
-											scanner_errposition(@3)));
+											parser_errposition(@3)));
 							break;
 					}
 					r->location = @3;
@@ -3638,7 +3643,7 @@ opt_recheck:	RECHECK
 							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 							 errmsg("RECHECK is no longer required"),
 							 errhint("Update your data type."),
-							 scanner_errposition(@1)));
+							 parser_errposition(@1)));
 					$$ = TRUE;
 				}
 			| /*EMPTY*/						{ $$ = FALSE; }
@@ -5043,7 +5048,7 @@ oper_argtypes:
 						   (errcode(ERRCODE_SYNTAX_ERROR),
 							errmsg("missing argument"),
 							errhint("Use NONE to denote the missing argument of a unary operator."),
-							scanner_errposition(@3)));
+							parser_errposition(@3)));
 				}
 			| '(' Typename ',' Typename ')'
 					{ $$ = list_make2($2, $4); }
@@ -5600,7 +5605,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
  *****************************************************************************/
 
 RuleStmt:	CREATE opt_or_replace RULE name AS
-			{ QueryIsRule=TRUE; }
+			{ pg_yyget_extra(yyscanner)->QueryIsRule = TRUE; }
 			ON event TO qualified_name where_clause
 			DO opt_instead RuleActionList
 				{
@@ -5613,7 +5618,7 @@ RuleStmt:	CREATE opt_or_replace RULE name AS
 					n->instead = $13;
 					n->actions = $14;
 					$$ = (Node *)n;
-					QueryIsRule=FALSE;
+					pg_yyget_extra(yyscanner)->QueryIsRule = FALSE;
 				}
 		;
 
@@ -6605,7 +6610,7 @@ insert_column_item:
 				{
 					$$ = makeNode(ResTarget);
 					$$->name = $1;
-					$$->indirection = check_indirection($2);
+					$$->indirection = check_indirection($2, yyscanner);
 					$$->val = NULL;
 					$$->location = @1;
 				}
@@ -6735,7 +6740,7 @@ multiple_set_clause:
 						ereport(ERROR,
 								(errcode(ERRCODE_SYNTAX_ERROR),
 								 errmsg("number of columns does not match number of values"),
-								 scanner_errposition(@1)));
+								 parser_errposition(@1)));
 					forboth(col_cell, $2, val_cell, $5)
 					{
 						ResTarget *res_col = (ResTarget *) lfirst(col_cell);
@@ -6753,7 +6758,7 @@ set_target:
 				{
 					$$ = makeNode(ResTarget);
 					$$->name = $1;
-					$$->indirection = check_indirection($2);
+					$$->indirection = check_indirection($2, yyscanner);
 					$$->val = NULL;	/* upper production sets this */
 					$$->location = @1;
 				}
@@ -6863,49 +6868,56 @@ select_no_parens:
 			| select_clause sort_clause
 				{
 					insertSelectOptions((SelectStmt *) $1, $2, NIL,
-										NULL, NULL, NULL);
+										NULL, NULL, NULL,
+										yyscanner);
 					$$ = $1;
 				}
 			| select_clause opt_sort_clause for_locking_clause opt_select_limit
 				{
 					insertSelectOptions((SelectStmt *) $1, $2, $3,
 										list_nth($4, 0), list_nth($4, 1),
-										NULL);
+										NULL,
+										yyscanner);
 					$$ = $1;
 				}
 			| select_clause opt_sort_clause select_limit opt_for_locking_clause
 				{
 					insertSelectOptions((SelectStmt *) $1, $2, $4,
 										list_nth($3, 0), list_nth($3, 1),
-										NULL);
+										NULL,
+										yyscanner);
 					$$ = $1;
 				}
 			| with_clause select_clause
 				{
 					insertSelectOptions((SelectStmt *) $2, NULL, NIL,
 										NULL, NULL,
-										$1);
+										$1,
+										yyscanner);
 					$$ = $2;
 				}
 			| with_clause select_clause sort_clause
 				{
 					insertSelectOptions((SelectStmt *) $2, $3, NIL,
 										NULL, NULL,
-										$1);
+										$1,
+										yyscanner);
 					$$ = $2;
 				}
 			| with_clause select_clause opt_sort_clause for_locking_clause opt_select_limit
 				{
 					insertSelectOptions((SelectStmt *) $2, $3, $4,
 										list_nth($5, 0), list_nth($5, 1),
-										$1);
+										$1,
+										yyscanner);
 					$$ = $2;
 				}
 			| with_clause select_clause opt_sort_clause select_limit opt_for_locking_clause
 				{
 					insertSelectOptions((SelectStmt *) $2, $3, $5,
 										list_nth($4, 0), list_nth($4, 1),
-										$1);
+										$1,
+										yyscanner);
 					$$ = $2;
 				}
 		;
@@ -7160,7 +7172,7 @@ select_limit:
 							(errcode(ERRCODE_SYNTAX_ERROR),
 							 errmsg("LIMIT #,# syntax is not supported"),
 							 errhint("Use separate LIMIT and OFFSET clauses."),
-							 scanner_errposition(@1)));
+							 parser_errposition(@1)));
 				}
 			/* SQL:2008 syntax variants */
 			| OFFSET select_offset_value2 row_or_rows
@@ -7382,13 +7394,13 @@ table_ref:	relation_expr
 								(errcode(ERRCODE_SYNTAX_ERROR),
 								 errmsg("VALUES in FROM must have an alias"),
 								 errhint("For example, FROM (VALUES ...) [AS] foo."),
-								 scanner_errposition(@1)));
+								 parser_errposition(@1)));
 					else
 						ereport(ERROR,
 								(errcode(ERRCODE_SYNTAX_ERROR),
 								 errmsg("subquery in FROM must have an alias"),
 								 errhint("For example, FROM (SELECT ...) [AS] foo."),
-								 scanner_errposition(@1)));
+								 parser_errposition(@1)));
 					$$ = NULL;
 				}
 			| select_with_parens alias_clause
@@ -7743,7 +7755,7 @@ SimpleTypename:
 							ereport(ERROR,
 									(errcode(ERRCODE_SYNTAX_ERROR),
 									 errmsg("interval precision specified twice"),
-									 scanner_errposition(@1)));
+									 parser_errposition(@1)));
 						$$->typmods = lappend($5, makeIntConst($3, @3));
 					}
 					else
@@ -7869,7 +7881,7 @@ opt_float:	'(' Iconst ')'
 						ereport(ERROR,
 								(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 								 errmsg("precision for type float must be at least 1 bit"),
-								 scanner_errposition(@2)));
+								 parser_errposition(@2)));
 					else if ($2 <= 24)
 						$$ = SystemTypeName("float4");
 					else if ($2 <= 53)
@@ -7878,7 +7890,7 @@ opt_float:	'(' Iconst ')'
 						ereport(ERROR,
 								(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 								 errmsg("precision for type float must be less than 54 bits"),
-								 scanner_errposition(@2)));
+								 parser_errposition(@2)));
 				}
 			| /*EMPTY*/
 				{
@@ -8394,7 +8406,7 @@ a_expr:		c_expr									{ $$ = $1; }
 				}
 			| row OVERLAPS row
 				{
-					$$ = (Node *)makeOverlaps($1, $3, @2);
+					$$ = (Node *)makeOverlaps($1, $3, @2, yyscanner);
 				}
 			| a_expr IS TRUE_P
 				{
@@ -8574,7 +8586,7 @@ a_expr:		c_expr									{ $$ = $1; }
 					ereport(ERROR,
 							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 							 errmsg("UNIQUE predicate is not yet implemented"),
-							 scanner_errposition(@1)));
+							 parser_errposition(@1)));
 				}
 			| a_expr IS DOCUMENT_P					%prec IS
 				{
@@ -8681,7 +8693,7 @@ c_expr:		columnref								{ $$ = $1; }
 					{
 						A_Indirection *n = makeNode(A_Indirection);
 						n->arg = (Node *) p;
-						n->indirection = check_indirection($2);
+						n->indirection = check_indirection($2, yyscanner);
 						$$ = (Node *) n;
 					}
 					else
@@ -8693,7 +8705,7 @@ c_expr:		columnref								{ $$ = $1; }
 					{
 						A_Indirection *n = makeNode(A_Indirection);
 						n->arg = $2;
-						n->indirection = check_indirection($4);
+						n->indirection = check_indirection($4, yyscanner);
 						$$ = (Node *)n;
 					}
 					else
@@ -9413,12 +9425,12 @@ frame_extent: frame_bound
 						ereport(ERROR,
 								(errcode(ERRCODE_WINDOWING_ERROR),
 								 errmsg("frame start cannot be UNBOUNDED FOLLOWING"),
-								 scanner_errposition(@1)));
+								 parser_errposition(@1)));
 					if ($1 & FRAMEOPTION_START_CURRENT_ROW)
 						ereport(ERROR,
 								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 								 errmsg("frame start at CURRENT ROW is not implemented"),
-								 scanner_errposition(@1)));
+								 parser_errposition(@1)));
 					$$ = $1 | FRAMEOPTION_END_CURRENT_ROW;
 				}
 			| BETWEEN frame_bound AND frame_bound
@@ -9428,17 +9440,17 @@ frame_extent: frame_bound
 						ereport(ERROR,
 								(errcode(ERRCODE_WINDOWING_ERROR),
 								 errmsg("frame start cannot be UNBOUNDED FOLLOWING"),
-								 scanner_errposition(@2)));
+								 parser_errposition(@2)));
 					if ($2 & FRAMEOPTION_START_CURRENT_ROW)
 						ereport(ERROR,
 								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 								 errmsg("frame start at CURRENT ROW is not implemented"),
-								 scanner_errposition(@2)));
+								 parser_errposition(@2)));
 					if ($4 & FRAMEOPTION_START_UNBOUNDED_PRECEDING)
 						ereport(ERROR,
 								(errcode(ERRCODE_WINDOWING_ERROR),
 								 errmsg("frame end cannot be UNBOUNDED PRECEDING"),
-								 scanner_errposition(@4)));
+								 parser_errposition(@4)));
 					/* shift converts START_ options to END_ options */
 					$$ = FRAMEOPTION_BETWEEN | $2 | ($4 << 1);
 				}
@@ -9742,11 +9754,11 @@ case_arg:	a_expr									{ $$ = $1; }
  */
 columnref:	relation_name
 				{
-					$$ = makeColumnRef($1, NIL, @1);
+					$$ = makeColumnRef($1, NIL, @1, yyscanner);
 				}
 			| relation_name indirection
 				{
-					$$ = makeColumnRef($1, $2, @1);
+					$$ = makeColumnRef($1, $2, @1, yyscanner);
 				}
 		;
 
@@ -9912,7 +9924,7 @@ qualified_name:
 				}
 			| relation_name indirection
 				{
-					check_qualified_name($2);
+					check_qualified_name($2, yyscanner);
 					$$ = makeNode(RangeVar);
 					switch (list_length($2))
 					{
@@ -9931,7 +9943,7 @@ qualified_name:
 									(errcode(ERRCODE_SYNTAX_ERROR),
 									 errmsg("improper qualified name (too many dotted names): %s",
 											NameListToString(lcons(makeString($1), $2))),
-									 scanner_errposition(@1)));
+									 parser_errposition(@1)));
 							break;
 					}
 					$$->location = @1;
@@ -9970,7 +9982,10 @@ file_name:	Sconst									{ $$ = $1; };
 func_name:	type_function_name
 					{ $$ = list_make1(makeString($1)); }
 			| relation_name indirection
-					{ $$ = check_func_name(lcons(makeString($1), $2)); }
+					{
+						$$ = check_func_name(lcons(makeString($1), $2),
+											 yyscanner);
+					}
 		;
 
 
@@ -10036,7 +10051,7 @@ AexprConst: Iconst
 							ereport(ERROR,
 									(errcode(ERRCODE_SYNTAX_ERROR),
 									 errmsg("interval precision specified twice"),
-									 scanner_errposition(@1)));
+									 parser_errposition(@1)));
 						t->typmods = lappend($6, makeIntConst($3, @3));
 					}
 					else
@@ -10552,30 +10567,42 @@ reserved_keyword:
 SpecialRuleRelation:
 			OLD
 				{
-					if (QueryIsRule)
+					if (pg_yyget_extra(yyscanner)->QueryIsRule)
 						$$ = "*OLD*";
 					else
 						ereport(ERROR,
 								(errcode(ERRCODE_SYNTAX_ERROR),
 								 errmsg("OLD used in query that is not in a rule"),
-								 scanner_errposition(@1)));
+								 parser_errposition(@1)));
 				}
 			| NEW
 				{
-					if (QueryIsRule)
+					if (pg_yyget_extra(yyscanner)->QueryIsRule)
 						$$ = "*NEW*";
 					else
 						ereport(ERROR,
 								(errcode(ERRCODE_SYNTAX_ERROR),
 								 errmsg("NEW used in query that is not in a rule"),
-								 scanner_errposition(@1)));
+								 parser_errposition(@1)));
 				}
 		;
 
 %%
 
+/*
+ * The signature of this function is required by bison.  However, we
+ * ignore the passed yylloc and instead use the last token position
+ * available from the scanner.
+ */
+static void
+base_yyerror(YYLTYPE *yylloc, base_yyscan_t yyscanner, const char *msg)
+{
+	parser_yyerror(msg);
+}
+
 static Node *
-makeColumnRef(char *colname, List *indirection, int location)
+makeColumnRef(char *colname, List *indirection,
+			  int location, base_yyscan_t yyscanner)
 {
 	/*
 	 * Generate a ColumnRef node, with an A_Indirection node added if there
@@ -10598,13 +10625,14 @@ makeColumnRef(char *colname, List *indirection, int location)
 			{
 				/* easy case - all indirection goes to A_Indirection */
 				c->fields = list_make1(makeString(colname));
-				i->indirection = check_indirection(indirection);
+				i->indirection = check_indirection(indirection, yyscanner);
 			}
 			else
 			{
 				/* got to split the list in two */
 				i->indirection = check_indirection(list_copy_tail(indirection,
-																  nfields));
+																  nfields),
+												   yyscanner);
 				indirection = list_truncate(indirection, nfields);
 				c->fields = lcons(makeString(colname), indirection);
 			}
@@ -10615,7 +10643,7 @@ makeColumnRef(char *colname, List *indirection, int location)
 		{
 			/* We only allow '*' at the end of a ColumnRef */
 			if (lnext(l) != NULL)
-				yyerror("improper use of \"*\"");
+				parser_yyerror("improper use of \"*\"");
 		}
 		nfields++;
 	}
@@ -10744,7 +10772,7 @@ makeBoolAConst(bool state, int location)
  * Create and populate a FuncCall node to support the OVERLAPS operator.
  */
 static FuncCall *
-makeOverlaps(List *largs, List *rargs, int location)
+makeOverlaps(List *largs, List *rargs, int location, base_yyscan_t yyscanner)
 {
 	FuncCall *n = makeNode(FuncCall);
 
@@ -10755,14 +10783,14 @@ makeOverlaps(List *largs, List *rargs, int location)
 		ereport(ERROR,
 				(errcode(ERRCODE_SYNTAX_ERROR),
 				 errmsg("wrong number of parameters on left side of OVERLAPS expression"),
-				 scanner_errposition(location)));
+				 parser_errposition(location)));
 	if (list_length(rargs) == 1)
 		rargs = lappend(rargs, rargs);
 	else if (list_length(rargs) != 2)
 		ereport(ERROR,
 				(errcode(ERRCODE_SYNTAX_ERROR),
 				 errmsg("wrong number of parameters on right side of OVERLAPS expression"),
-				 scanner_errposition(location)));
+				 parser_errposition(location)));
 	n->args = list_concat(largs, rargs);
 	n->agg_star = FALSE;
 	n->agg_distinct = FALSE;
@@ -10778,14 +10806,14 @@ makeOverlaps(List *largs, List *rargs, int location)
  * subscripts and '*', which we then must reject here.
  */
 static void
-check_qualified_name(List *names)
+check_qualified_name(List *names, base_yyscan_t yyscanner)
 {
 	ListCell   *i;
 
 	foreach(i, names)
 	{
 		if (!IsA(lfirst(i), String))
-			yyerror("syntax error");
+			parser_yyerror("syntax error");
 	}
 }
 
@@ -10795,14 +10823,14 @@ check_qualified_name(List *names)
  * and '*', which we then must reject here.
  */
 static List *
-check_func_name(List *names)
+check_func_name(List *names, base_yyscan_t yyscanner)
 {
 	ListCell   *i;
 
 	foreach(i, names)
 	{
 		if (!IsA(lfirst(i), String))
-			yyerror("syntax error");
+			parser_yyerror("syntax error");
 	}
 	return names;
 }
@@ -10813,7 +10841,7 @@ check_func_name(List *names)
  * in the grammar, so do it here.
  */
 static List *
-check_indirection(List *indirection)
+check_indirection(List *indirection, base_yyscan_t yyscanner)
 {
 	ListCell *l;
 
@@ -10822,7 +10850,7 @@ check_indirection(List *indirection)
 		if (IsA(lfirst(l), A_Star))
 		{
 			if (lnext(l) != NULL)
-				yyerror("improper use of \"*\"");
+				parser_yyerror("improper use of \"*\"");
 		}
 	}
 	return indirection;
@@ -10871,7 +10899,8 @@ static void
 insertSelectOptions(SelectStmt *stmt,
 					List *sortClause, List *lockingClause,
 					Node *limitOffset, Node *limitCount,
-					WithClause *withClause)
+					WithClause *withClause,
+					base_yyscan_t yyscanner)
 {
 	Assert(IsA(stmt, SelectStmt));
 
@@ -10885,7 +10914,7 @@ insertSelectOptions(SelectStmt *stmt,
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
 					 errmsg("multiple ORDER BY clauses not allowed"),
-					 scanner_errposition(exprLocation((Node *) sortClause))));
+					 parser_errposition(exprLocation((Node *) sortClause))));
 		stmt->sortClause = sortClause;
 	}
 	/* We can handle multiple locking clauses, though */
@@ -10896,7 +10925,7 @@ insertSelectOptions(SelectStmt *stmt,
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
 					 errmsg("multiple OFFSET clauses not allowed"),
-					 scanner_errposition(exprLocation(limitOffset))));
+					 parser_errposition(exprLocation(limitOffset))));
 		stmt->limitOffset = limitOffset;
 	}
 	if (limitCount)
@@ -10905,7 +10934,7 @@ insertSelectOptions(SelectStmt *stmt,
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
 					 errmsg("multiple LIMIT clauses not allowed"),
-					 scanner_errposition(exprLocation(limitCount))));
+					 parser_errposition(exprLocation(limitCount))));
 		stmt->limitCount = limitCount;
 	}
 	if (withClause)
@@ -10914,7 +10943,7 @@ insertSelectOptions(SelectStmt *stmt,
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
 					 errmsg("multiple WITH clauses not allowed"),
-					 scanner_errposition(exprLocation((Node *) withClause))));
+					 parser_errposition(exprLocation((Node *) withClause))));
 		stmt->withClause = withClause;
 	}
 }
@@ -11046,9 +11075,10 @@ makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args,
  * Initialize to parse one query string
  */
 void
-parser_init(void)
+parser_init(base_yy_extra_type *yyext)
 {
-	QueryIsRule = FALSE;
+	yyext->parsetree = NIL;		/* in case grammar forgets to set it */
+	yyext->QueryIsRule = FALSE;
 }
 
 /*
@@ -11102,4 +11132,9 @@ TableFuncTypeName(List *columns)
  */
 #undef base_yylex
 
+/* Undefine some other stuff that would conflict in scan.c, too */
+#undef yyerror
+#undef yylval
+#undef yylloc
+
 #include "scan.c"
diff --git a/src/backend/parser/parser.c b/src/backend/parser/parser.c
index 1e7f93af536ba8ac45adeb345ae88027bba5d989..cb8ff8a339401d1a67ab2f10006d1a2edf726fa1 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.79 2009/07/12 17:12:34 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/parser.c,v 1.80 2009/07/13 02:02:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -25,14 +25,6 @@
 #include "parser/parser.h"
 
 
-List	   *parsetree;			/* result of parsing is left here */
-
-static bool have_lookahead;		/* is lookahead info valid? */
-static int	lookahead_token;	/* one-token lookahead */
-static YYSTYPE lookahead_yylval;	/* yylval for lookahead token */
-static YYLTYPE lookahead_yylloc;	/* yylloc for lookahead token */
-
-
 /*
  * raw_parser
  *		Given a query in string form, do lexical and grammatical analysis.
@@ -42,22 +34,29 @@ static YYLTYPE lookahead_yylloc;	/* yylloc for lookahead token */
 List *
 raw_parser(const char *str)
 {
+	base_yyscan_t yyscanner;
+	base_yy_extra_type yyextra;
 	int			yyresult;
 
-	parsetree = NIL;			/* in case grammar forgets to set it */
-	have_lookahead = false;
+	/* initialize the flex scanner */
+	yyscanner = scanner_init(str, &yyextra);
+
+	/* filtered_base_yylex() only needs this much initialization */
+	yyextra.have_lookahead = false;
 
-	scanner_init(str);
-	parser_init();
+	/* initialize the bison parser */
+	parser_init(&yyextra);
 
-	yyresult = base_yyparse();
+	/* Parse! */
+	yyresult = base_yyparse(yyscanner);
 
-	scanner_finish();
+	/* Clean up (release memory) */
+	scanner_finish(yyscanner);
 
 	if (yyresult)				/* error */
 		return NIL;
 
-	return parsetree;
+	return yyextra.parsetree;
 }
 
 
@@ -69,25 +68,27 @@ raw_parser(const char *str)
  * passed string does represent one single string literal.
  *
  * We export this function to avoid having plpgsql depend on internal details
- * of the core grammar (such as the token code assigned to SCONST).  Note
- * that since the scanner isn't presently re-entrant, this cannot be used
- * during use of the main parser/scanner.
+ * of the core grammar (such as the token code assigned to SCONST).
  */
 char *
 pg_parse_string_token(const char *token)
 {
+	base_yyscan_t yyscanner;
+	base_yy_extra_type yyextra;
 	int			ctoken;
+	YYSTYPE		yylval;
+	YYLTYPE		yylloc;
 
-	scanner_init(token);
+	yyscanner = scanner_init(token, &yyextra);
 
-	ctoken = base_yylex();
+	ctoken = base_yylex(&yylval, &yylloc, yyscanner);
 
 	if (ctoken != SCONST)		/* caller error */
 		elog(ERROR, "expected string constant, got token code %d", ctoken);
 
-	scanner_finish();
+	scanner_finish(yyscanner);
 
-	return base_yylval.str;
+	return yylval.str;
 }
 
 
@@ -105,23 +106,24 @@ pg_parse_string_token(const char *token)
  * layer does.
  */
 int
-filtered_base_yylex(void)
+filtered_base_yylex(YYSTYPE *lvalp, YYLTYPE *llocp, base_yyscan_t yyscanner)
 {
+	base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner);
 	int			cur_token;
 	int			next_token;
 	YYSTYPE		cur_yylval;
 	YYLTYPE		cur_yylloc;
 
 	/* Get next token --- we might already have it */
-	if (have_lookahead)
+	if (yyextra->have_lookahead)
 	{
-		cur_token = lookahead_token;
-		base_yylval = lookahead_yylval;
-		base_yylloc = lookahead_yylloc;
-		have_lookahead = false;
+		cur_token = yyextra->lookahead_token;
+		*lvalp = yyextra->lookahead_yylval;
+		*llocp = yyextra->lookahead_yylloc;
+		yyextra->have_lookahead = false;
 	}
 	else
-		cur_token = base_yylex();
+		cur_token = base_yylex(lvalp, llocp, yyscanner);
 
 	/* Do we need to look ahead for a possible multiword token? */
 	switch (cur_token)
@@ -131,9 +133,9 @@ filtered_base_yylex(void)
 			/*
 			 * NULLS FIRST and NULLS LAST must be reduced to one token
 			 */
-			cur_yylval = base_yylval;
-			cur_yylloc = base_yylloc;
-			next_token = base_yylex();
+			cur_yylval = *lvalp;
+			cur_yylloc = *llocp;
+			next_token = base_yylex(lvalp, llocp, yyscanner);
 			switch (next_token)
 			{
 				case FIRST_P:
@@ -144,13 +146,13 @@ filtered_base_yylex(void)
 					break;
 				default:
 					/* save the lookahead token for next time */
-					lookahead_token = next_token;
-					lookahead_yylval = base_yylval;
-					lookahead_yylloc = base_yylloc;
-					have_lookahead = true;
+					yyextra->lookahead_token = next_token;
+					yyextra->lookahead_yylval = *lvalp;
+					yyextra->lookahead_yylloc = *llocp;
+					yyextra->have_lookahead = true;
 					/* and back up the output info to cur_token */
-					base_yylval = cur_yylval;
-					base_yylloc = cur_yylloc;
+					*lvalp = cur_yylval;
+					*llocp = cur_yylloc;
 					break;
 			}
 			break;
@@ -160,9 +162,9 @@ filtered_base_yylex(void)
 			/*
 			 * WITH TIME must be reduced to one token
 			 */
-			cur_yylval = base_yylval;
-			cur_yylloc = base_yylloc;
-			next_token = base_yylex();
+			cur_yylval = *lvalp;
+			cur_yylloc = *llocp;
+			next_token = base_yylex(lvalp, llocp, yyscanner);
 			switch (next_token)
 			{
 				case TIME:
@@ -170,13 +172,13 @@ filtered_base_yylex(void)
 					break;
 				default:
 					/* save the lookahead token for next time */
-					lookahead_token = next_token;
-					lookahead_yylval = base_yylval;
-					lookahead_yylloc = base_yylloc;
-					have_lookahead = true;
+					yyextra->lookahead_token = next_token;
+					yyextra->lookahead_yylval = *lvalp;
+					yyextra->lookahead_yylloc = *llocp;
+					yyextra->have_lookahead = true;
 					/* and back up the output info to cur_token */
-					base_yylval = cur_yylval;
-					base_yylloc = cur_yylloc;
+					*lvalp = cur_yylval;
+					*llocp = cur_yylloc;
 					break;
 			}
 			break;
diff --git a/src/backend/parser/scan.l b/src/backend/parser/scan.l
index 1483627510f6058ef418e3d641dd9596c2ed4d23..06e9f6d8c1659c38171eb5f7e8a0fdc44b462b9a 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.154 2009/07/12 17:12:34 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/scan.l,v 1.155 2009/07/13 02:02:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -43,9 +43,6 @@
 #undef fprintf
 #define fprintf(file, fmt, msg)  ereport(ERROR, (errmsg_internal("%s", msg)))
 
-static int		xcdepth = 0;	/* depth of nesting in slash-star comments */
-static char    *dolqstart;      /* current $foo$ quote start string */
-
 /*
  * GUC variables.  This is a DIRECT violation of the warning given at the
  * head of gram.y, ie flex/bison code must not depend on any GUC variables;
@@ -57,29 +54,11 @@ int				backslash_quote = BACKSLASH_QUOTE_SAFE_ENCODING;
 bool			escape_string_warning = true;
 bool			standard_conforming_strings = false;
 
-static bool		warn_on_first_escape;
-static bool		saw_non_ascii = false;
-
 /*
- * literalbuf is used to accumulate literal values when multiple rules
- * are needed to parse a single literal.  Call startlit to reset buffer
- * to empty, addlit to add text.  Note that the buffer is palloc'd and
- * starts life afresh on every parse cycle.
+ * Set the type of yyextra.  All state variables used by the scanner should
+ * be in yyextra, *not* statically allocated.
  */
-static char	   *literalbuf;		/* expandable buffer */
-static int		literallen;		/* actual current length */
-static int		literalalloc;	/* current allocated buffer size */
-
-#define startlit()  (literalbuf[0] = '\0', literallen = 0)
-static void addlit(char *ytext, int yleng);
-static void addlitchar(unsigned char ychar);
-static char *litbufdup(void);
-static char *litbuf_udeescape(unsigned char escape);
-
-#define lexer_errposition()  scanner_errposition(yylloc)
-
-static void check_escape_warning(void);
-static void check_string_escape_warning(unsigned char ychar);
+#define YY_EXTRA_TYPE base_yy_extra_type *
 
 /*
  * Each call to yylex must set yylloc to the location of the found token
@@ -88,22 +67,51 @@ static void check_string_escape_warning(unsigned char ychar);
  * this should be done in the first such rule, else yylloc will point
  * into the middle of the token.
  */
-#define SET_YYLLOC()  (yylloc = yytext - scanbuf)
+#define SET_YYLLOC()  (*(yylloc) = yytext - yyextra->scanbuf)
+
+/*
+ * Advance yylloc by the given number of bytes.
+ */
+#define ADVANCE_YYLLOC(delta)  ( *(yylloc) += (delta) )
+
+#define startlit()  ( yyextra->literallen = 0 )
+static void addlit(char *ytext, int yleng, base_yyscan_t yyscanner);
+static void addlitchar(unsigned char ychar, base_yyscan_t yyscanner);
+static char *litbufdup(base_yyscan_t yyscanner);
+static char *litbuf_udeescape(unsigned char escape, base_yyscan_t yyscanner);
+static unsigned char unescape_single_char(unsigned char c, base_yyscan_t yyscanner);
+
+#define yyerror(msg)  scanner_yyerror(msg, yyscanner)
 
-/* Handles to the buffer that the lexer uses internally */
-static YY_BUFFER_STATE scanbufhandle;
-static char *scanbuf;
+#define lexer_errposition()  scanner_errposition(*(yylloc), yyscanner)
 
-static unsigned char unescape_single_char(unsigned char c);
+static void check_string_escape_warning(unsigned char ychar, base_yyscan_t yyscanner);
+static void check_escape_warning(base_yyscan_t yyscanner);
+
+/*
+ * Work around a bug in flex 2.5.35: it emits a couple of functions that
+ * it forgets to emit declarations for.  Since we use -Wmissing-prototypes,
+ * this would cause warnings.  Providing our own declarations should be
+ * harmless even when the bug gets fixed.
+ */
+extern int	base_yyget_column(yyscan_t yyscanner);
+extern void base_yyset_column(int column_no, yyscan_t yyscanner);
 
 %}
 
+%option reentrant
+%option bison-bridge
+%option bison-locations
 %option 8bit
 %option never-interactive
 %option nodefault
 %option noinput
 %option nounput
 %option noyywrap
+%option noyyalloc
+%option noyyrealloc
+%option noyyfree
+%option warn
 %option prefix="base_yy"
 
 /*
@@ -350,23 +358,23 @@ other			.
 {xcstart}		{
 					/* Set location in case of syntax error in comment */
 					SET_YYLLOC();
-					xcdepth = 0;
+					yyextra->xcdepth = 0;
 					BEGIN(xc);
 					/* Put back any characters past slash-star; see above */
 					yyless(2);
 				}
 
 <xc>{xcstart}	{
-					xcdepth++;
+					(yyextra->xcdepth)++;
 					/* Put back any characters past slash-star; see above */
 					yyless(2);
 				}
 
 <xc>{xcstop}	{
-					if (xcdepth <= 0)
+					if (yyextra->xcdepth <= 0)
 						BEGIN(INITIAL);
 					else
-						xcdepth--;
+						(yyextra->xcdepth)--;
 				}
 
 <xc>{xcinside}	{
@@ -393,18 +401,18 @@ other			.
 					SET_YYLLOC();
 					BEGIN(xb);
 					startlit();
-					addlitchar('b');
+					addlitchar('b', yyscanner);
 				}
 <xb>{quotestop}	|
 <xb>{quotefail} {
 					yyless(1);
 					BEGIN(INITIAL);
-					yylval.str = litbufdup();
+					yylval->str = litbufdup(yyscanner);
 					return BCONST;
 				}
 <xh>{xhinside}	|
 <xb>{xbinside}	{
-					addlit(yytext, yyleng);
+					addlit(yytext, yyleng, yyscanner);
 				}
 <xh>{quotecontinue}	|
 <xb>{quotecontinue}	{
@@ -422,13 +430,13 @@ other			.
 					SET_YYLLOC();
 					BEGIN(xh);
 					startlit();
-					addlitchar('x');
+					addlitchar('x', yyscanner);
 				}
 <xh>{quotestop}	|
 <xh>{quotefail} {
 					yyless(1);
 					BEGIN(INITIAL);
-					yylval.str = litbufdup();
+					yylval->str = litbufdup(yyscanner);
 					return XCONST;
 				}
 <xh><<EOF>>		{ yyerror("unterminated hexadecimal string literal"); }
@@ -445,13 +453,13 @@ other			.
 					/* nchar had better be a keyword! */
 					keyword = ScanKeywordLookup("nchar");
 					Assert(keyword != NULL);
-					yylval.keyword = keyword->name;
+					yylval->keyword = keyword->name;
 					return keyword->value;
 				}
 
 {xqstart}		{
-					warn_on_first_escape = true;
-					saw_non_ascii = false;
+					yyextra->warn_on_first_escape = true;
+					yyextra->saw_non_ascii = false;
 					SET_YYLLOC();
 					if (standard_conforming_strings)
 						BEGIN(xq);
@@ -460,8 +468,8 @@ other			.
 					startlit();
 				}
 {xestart}		{
-					warn_on_first_escape = false;
-					saw_non_ascii = false;
+					yyextra->warn_on_first_escape = false;
+					yyextra->saw_non_ascii = false;
 					SET_YYLLOC();
 					BEGIN(xe);
 					startlit();
@@ -485,31 +493,33 @@ other			.
 					 * check that the data remains valid if it might have been
 					 * made invalid by unescaping any chars.
 					 */
-					if (saw_non_ascii)
-						pg_verifymbstr(literalbuf, literallen, false);
-					yylval.str = litbufdup();
+					if (yyextra->saw_non_ascii)
+						pg_verifymbstr(yyextra->literalbuf,
+									   yyextra->literallen,
+									   false);
+					yylval->str = litbufdup(yyscanner);
 					return SCONST;
 				}
 <xus>{xusstop1} {
 					/* throw back all but the quote */
 					yyless(1);
 					BEGIN(INITIAL);
-					yylval.str = litbuf_udeescape('\\');
+					yylval->str = litbuf_udeescape('\\', yyscanner);
 					return SCONST;
 				}
 <xus>{xusstop2} {
 					BEGIN(INITIAL);
-					yylval.str = litbuf_udeescape(yytext[yyleng-2]);
+					yylval->str = litbuf_udeescape(yytext[yyleng-2], yyscanner);
 					return SCONST;
 				}
 <xq,xe,xus>{xqdouble} {
-					addlitchar('\'');
+					addlitchar('\'', yyscanner);
 				}
 <xq,xus>{xqinside}  {
-					addlit(yytext, yyleng);
+					addlit(yytext, yyleng, yyscanner);
 				}
 <xe>{xeinside}  {
-					addlit(yytext, yyleng);
+					addlit(yytext, yyleng, yyscanner);
 				}
 <xe>{xeescape}  {
 					if (yytext[1] == '\'')
@@ -523,37 +533,38 @@ other			.
 									 errhint("Use '' to write quotes in strings. \\' is insecure in client-only encodings."),
 									 lexer_errposition()));
 					}
-					check_string_escape_warning(yytext[1]);
-					addlitchar(unescape_single_char(yytext[1]));
+					check_string_escape_warning(yytext[1], yyscanner);
+					addlitchar(unescape_single_char(yytext[1], yyscanner),
+							   yyscanner);
 				}
 <xe>{xeoctesc}  {
 					unsigned char c = strtoul(yytext+1, NULL, 8);
 
-					check_escape_warning();
-					addlitchar(c);
+					check_escape_warning(yyscanner);
+					addlitchar(c, yyscanner);
 					if (c == '\0' || IS_HIGHBIT_SET(c))
-						saw_non_ascii = true;
+						yyextra->saw_non_ascii = true;
 				}
 <xe>{xehexesc}  {
 					unsigned char c = strtoul(yytext+2, NULL, 16);
 
-					check_escape_warning();
-					addlitchar(c);
+					check_escape_warning(yyscanner);
+					addlitchar(c, yyscanner);
 					if (c == '\0' || IS_HIGHBIT_SET(c))
-						saw_non_ascii = true;
+						yyextra->saw_non_ascii = true;
 				}
 <xq,xe,xus>{quotecontinue} {
 					/* ignore */
 				}
 <xe>.			{
 					/* This is only needed for \ just before EOF */
-					addlitchar(yytext[0]);
+					addlitchar(yytext[0], yyscanner);
 				}
 <xq,xe,xus><<EOF>>		{ yyerror("unterminated quoted string"); }
 
 {dolqdelim}		{
 					SET_YYLLOC();
-					dolqstart = pstrdup(yytext);
+					yyextra->dolqstart = pstrdup(yytext);
 					BEGIN(xdolq);
 					startlit();
 				}
@@ -565,11 +576,12 @@ other			.
 					return yytext[0];
 				}
 <xdolq>{dolqdelim} {
-					if (strcmp(yytext, dolqstart) == 0)
+					if (strcmp(yytext, yyextra->dolqstart) == 0)
 					{
-						pfree(dolqstart);
+						pfree(yyextra->dolqstart);
+						yyextra->dolqstart = NULL;
 						BEGIN(INITIAL);
-						yylval.str = litbufdup();
+						yylval->str = litbufdup(yyscanner);
 						return SCONST;
 					}
 					else
@@ -579,19 +591,19 @@ other			.
 						 * the $... part to the output, but put back the final
 						 * $ for rescanning.  Consider $delim$...$junk$delim$
 						 */
-						addlit(yytext, yyleng-1);
+						addlit(yytext, yyleng-1, yyscanner);
 						yyless(yyleng-1);
 					}
 				}
 <xdolq>{dolqinside} {
-					addlit(yytext, yyleng);
+					addlit(yytext, yyleng, yyscanner);
 				}
 <xdolq>{dolqfailed} {
-					addlit(yytext, yyleng);
+					addlit(yytext, yyleng, yyscanner);
 				}
 <xdolq>.		{
 					/* This is only needed for $ inside the quoted text */
-					addlitchar(yytext[0]);
+					addlitchar(yytext[0], yyscanner);
 				}
 <xdolq><<EOF>>	{ yyerror("unterminated dollar-quoted string"); }
 
@@ -609,24 +621,24 @@ other			.
 					char		   *ident;
 
 					BEGIN(INITIAL);
-					if (literallen == 0)
+					if (yyextra->literallen == 0)
 						yyerror("zero-length delimited identifier");
-					ident = litbufdup();
-					if (literallen >= NAMEDATALEN)
-						truncate_identifier(ident, literallen, true);
-					yylval.str = ident;
+					ident = litbufdup(yyscanner);
+					if (yyextra->literallen >= NAMEDATALEN)
+						truncate_identifier(ident, yyextra->literallen, true);
+					yylval->str = ident;
 					return IDENT;
 				}
 <xui>{xuistop1}	{
 					char		   *ident;
 
 					BEGIN(INITIAL);
-					if (literallen == 0)
+					if (yyextra->literallen == 0)
 						yyerror("zero-length delimited identifier");
-					ident = litbuf_udeescape('\\');
-					if (literallen >= NAMEDATALEN)
-						truncate_identifier(ident, literallen, true);
-					yylval.str = ident;
+					ident = litbuf_udeescape('\\', yyscanner);
+					if (yyextra->literallen >= NAMEDATALEN)
+						truncate_identifier(ident, yyextra->literallen, true);
+					yylval->str = ident;
 					/* throw back all but the quote */
 					yyless(1);
 					return IDENT;
@@ -635,19 +647,19 @@ other			.
 					char		   *ident;
 
 					BEGIN(INITIAL);
-					if (literallen == 0)
+					if (yyextra->literallen == 0)
 						yyerror("zero-length delimited identifier");
-					ident = litbuf_udeescape(yytext[yyleng - 2]);
-					if (literallen >= NAMEDATALEN)
-						truncate_identifier(ident, literallen, true);
-					yylval.str = ident;
+					ident = litbuf_udeescape(yytext[yyleng - 2], yyscanner);
+					if (yyextra->literallen >= NAMEDATALEN)
+						truncate_identifier(ident, yyextra->literallen, true);
+					yylval->str = ident;
 					return IDENT;
 				}
 <xd,xui>{xddouble}	{
-					addlitchar('"');
+					addlitchar('"', yyscanner);
 				}
 <xd,xui>{xdinside}	{
-					addlit(yytext, yyleng);
+					addlit(yytext, yyleng, yyscanner);
 				}
 <xd,xui><<EOF>>		{ yyerror("unterminated quoted identifier"); }
 
@@ -659,7 +671,7 @@ other			.
 					yyless(1);
 					/* and treat it as {identifier} */
 					ident = downcase_truncate_identifier(yytext, yyleng, true);
-					yylval.str = ident;
+					yylval->str = ident;
 					return IDENT;
 				}
 
@@ -747,15 +759,15 @@ other			.
 
 					/* Convert "!=" operator to "<>" for compatibility */
 					if (strcmp(yytext, "!=") == 0)
-						yylval.str = pstrdup("<>");
+						yylval->str = pstrdup("<>");
 					else
-						yylval.str = pstrdup(yytext);
+						yylval->str = pstrdup(yytext);
 					return Op;
 				}
 
 {param}			{
 					SET_YYLLOC();
-					yylval.ival = atol(yytext + 1);
+					yylval->ival = atol(yytext + 1);
 					return PARAM;
 				}
 
@@ -774,20 +786,20 @@ other			.
 						)
 					{
 						/* integer too large, treat it as a float */
-						yylval.str = pstrdup(yytext);
+						yylval->str = pstrdup(yytext);
 						return FCONST;
 					}
-					yylval.ival = val;
+					yylval->ival = val;
 					return ICONST;
 				}
 {decimal}		{
 					SET_YYLLOC();
-					yylval.str = pstrdup(yytext);
+					yylval->str = pstrdup(yytext);
 					return FCONST;
 				}
 {real}			{
 					SET_YYLLOC();
-					yylval.str = pstrdup(yytext);
+					yylval->str = pstrdup(yytext);
 					return FCONST;
 				}
 {realfail1}		{
@@ -799,14 +811,14 @@ other			.
 					 */
 					yyless(yyleng-1);
 					SET_YYLLOC();
-					yylval.str = pstrdup(yytext);
+					yylval->str = pstrdup(yytext);
 					return FCONST;
 				}
 {realfail2}		{
 					/* throw back the [Ee][+-], and proceed as above */
 					yyless(yyleng-2);
 					SET_YYLLOC();
-					yylval.str = pstrdup(yytext);
+					yylval->str = pstrdup(yytext);
 					return FCONST;
 				}
 
@@ -821,7 +833,7 @@ other			.
 					keyword = ScanKeywordLookup(yytext);
 					if (keyword != NULL)
 					{
-						yylval.keyword = keyword->name;
+						yylval->keyword = keyword->name;
 						return keyword->value;
 					}
 
@@ -830,7 +842,7 @@ other			.
 					 * if necessary.
 					 */
 					ident = downcase_truncate_identifier(yytext, yyleng, true);
-					yylval.str = ident;
+					yylval->str = ident;
 					return IDENT;
 				}
 
@@ -846,6 +858,22 @@ other			.
 
 %%
 
+/*
+ * Arrange access to yyextra for subroutines of the main yylex() function.
+ * We expect each subroutine to have a yyscanner parameter.  Rather than
+ * use the yyget_xxx functions, which might or might not get inlined by the
+ * compiler, we cheat just a bit and cast yyscanner to the right type.
+ */
+#undef yyextra
+#define yyextra  (((struct yyguts_t *) yyscanner)->yyextra_r)
+
+/* Likewise for a couple of other things we need. */
+#undef yylloc
+#define yylloc  (((struct yyguts_t *) yyscanner)->yylloc_r)
+#undef yyleng
+#define yyleng  (((struct yyguts_t *) yyscanner)->yyleng_r)
+
+
 /*
  * scanner_errposition
  *		Report a lexer or grammar error cursor position, if possible.
@@ -854,38 +882,39 @@ other			.
  * is a dummy (always 0, in fact).
  *
  * Note that this can only be used for messages emitted during raw parsing
- * (essentially, scan.l and gram.y), since it requires scanbuf to still be
- * valid.
+ * (essentially, scan.l and gram.y), since it requires the yyscanner struct
+ * to still be available.
  */
 int
-scanner_errposition(int location)
+scanner_errposition(int location, base_yyscan_t yyscanner)
 {
 	int		pos;
 
-	Assert(scanbuf != NULL);	/* else called from wrong place */
 	if (location < 0)
 		return 0;				/* no-op if location is unknown */
 
 	/* Convert byte offset to character number */
-	pos = pg_mbstrlen_with_len(scanbuf, location) + 1;
+	pos = pg_mbstrlen_with_len(yyextra->scanbuf, location) + 1;
 	/* And pass it to the ereport mechanism */
 	return errposition(pos);
 }
 
 /*
- * yyerror
+ * scanner_yyerror
  *		Report a lexer or grammar error.
  *
- * The message's cursor position identifies the most recently lexed token.
+ * The message's cursor position is whatever YYLLOC was last set to,
+ * ie, the start of the current token if called within yylex(), or the
+ * most recently lexed token if called from the grammar.
  * This is OK for syntax error messages from the Bison parser, because Bison
  * parsers report error as soon as the first unparsable token is reached.
  * Beware of using yyerror for other purposes, as the cursor position might
  * be misleading!
  */
 void
-yyerror(const char *message)
+scanner_yyerror(const char *message, base_yyscan_t yyscanner)
 {
-	const char *loc = scanbuf + yylloc;
+	const char *loc = yyextra->scanbuf + *yylloc;
 
 	if (*loc == YY_END_OF_BUFFER_CHAR)
 	{
@@ -909,31 +938,32 @@ yyerror(const char *message)
 /*
  * Called before any actual parsing is done
  */
-void
-scanner_init(const char *str)
+base_yyscan_t
+scanner_init(const char *str, base_yy_extra_type *yyext)
 {
-	Size	slen = strlen(str);
+	Size		slen = strlen(str);
+	yyscan_t	scanner;
 
-	/*
-	 * Might be left over after ereport()
-	 */
-	if (YY_CURRENT_BUFFER)
-		yy_delete_buffer(YY_CURRENT_BUFFER);
+	if (yylex_init(&scanner) != 0)
+		elog(ERROR, "yylex_init() failed: %m");
+
+	base_yyset_extra(yyext, scanner);
 
 	/*
 	 * Make a scan buffer with special termination needed by flex.
 	 */
-	scanbuf = palloc(slen + 2);
-	memcpy(scanbuf, str, slen);
-	scanbuf[slen] = scanbuf[slen + 1] = YY_END_OF_BUFFER_CHAR;
-	scanbufhandle = yy_scan_buffer(scanbuf, slen + 2);
+	yyext->scanbuf = (char *) palloc(slen + 2);
+	yyext->scanbuflen = slen;
+	memcpy(yyext->scanbuf, str, slen);
+	yyext->scanbuf[slen] = yyext->scanbuf[slen + 1] = YY_END_OF_BUFFER_CHAR;
+	yy_scan_buffer(yyext->scanbuf, slen + 2, scanner);
 
 	/* initialize literal buffer to a reasonable but expansible size */
-	literalalloc = 1024;
-	literalbuf = (char *) palloc(literalalloc);
-	startlit();
+	yyext->literalalloc = 1024;
+	yyext->literalbuf = (char *) palloc(yyext->literalalloc);
+	yyext->literallen = 0;
 
-	BEGIN(INITIAL);
+	return scanner;
 }
 
 
@@ -941,60 +971,71 @@ scanner_init(const char *str)
  * Called after parsing is done to clean up after scanner_init()
  */
 void
-scanner_finish(void)
+scanner_finish(base_yyscan_t yyscanner)
 {
-	yy_delete_buffer(scanbufhandle);
-	pfree(scanbuf);
-	scanbuf = NULL;
+	/*
+	 * We don't bother to call yylex_destroy(), because all it would do
+	 * is pfree a small amount of control storage.  It's cheaper to leak
+	 * the storage until the parsing context is destroyed.  The amount of
+	 * space involved is usually negligible compared to the output parse
+	 * tree anyway.
+	 *
+	 * We do bother to pfree the scanbuf and literal buffer, but only if they
+	 * represent a nontrivial amount of space.  The 8K cutoff is arbitrary.
+	 */
+	if (yyextra->scanbuflen >= 8192)
+		pfree(yyextra->scanbuf);
+	if (yyextra->literalalloc >= 8192)
+		pfree(yyextra->literalbuf);
 }
 
 
 static void
-addlit(char *ytext, int yleng)
+addlit(char *ytext, int yleng, base_yyscan_t yyscanner)
 {
 	/* enlarge buffer if needed */
-	if ((literallen+yleng) >= literalalloc)
+	if ((yyextra->literallen + yleng) >= yyextra->literalalloc)
 	{
 		do {
-			literalalloc *= 2;
-		} while ((literallen+yleng) >= literalalloc);
-		literalbuf = (char *) repalloc(literalbuf, literalalloc);
+			yyextra->literalalloc *= 2;
+		} while ((yyextra->literallen + yleng) >= yyextra->literalalloc);
+		yyextra->literalbuf = (char *) repalloc(yyextra->literalbuf,
+												yyextra->literalalloc);
 	}
-	/* append new data, add trailing null */
-	memcpy(literalbuf+literallen, ytext, yleng);
-	literallen += yleng;
-	literalbuf[literallen] = '\0';
+	/* append new data */
+	memcpy(yyextra->literalbuf + yyextra->literallen, ytext, yleng);
+	yyextra->literallen += yleng;
 }
 
 
 static void
-addlitchar(unsigned char ychar)
+addlitchar(unsigned char ychar, base_yyscan_t yyscanner)
 {
 	/* enlarge buffer if needed */
-	if ((literallen+1) >= literalalloc)
+	if ((yyextra->literallen + 1) >= yyextra->literalalloc)
 	{
-		literalalloc *= 2;
-		literalbuf = (char *) repalloc(literalbuf, literalalloc);
+		yyextra->literalalloc *= 2;
+		yyextra->literalbuf = (char *) repalloc(yyextra->literalbuf,
+												yyextra->literalalloc);
 	}
-	/* append new data, add trailing null */
-	literalbuf[literallen] = ychar;
-	literallen += 1;
-	literalbuf[literallen] = '\0';
+	/* append new data */
+	yyextra->literalbuf[yyextra->literallen] = ychar;
+	yyextra->literallen += 1;
 }
 
 
 /*
- * One might be tempted to write pstrdup(literalbuf) instead of this,
- * but for long literals this is much faster because the length is
- * already known.
+ * Create a palloc'd copy of literalbuf, adding a trailing null.
  */
 static char *
-litbufdup(void)
+litbufdup(base_yyscan_t yyscanner)
 {
-	char *new;
+	int			llen = yyextra->literallen;
+	char	   *new;
 
-	new = palloc(literallen + 1);
-	memcpy(new, literalbuf, literallen+1);
+	new = palloc(llen + 1);
+	memcpy(new, yyextra->literalbuf, llen);
+	new[llen] = '\0';
 	return new;
 }
 
@@ -1012,23 +1053,23 @@ hexval(unsigned char c)
 }
 
 static void
-check_unicode_value(pg_wchar c, char * loc)
+check_unicode_value(pg_wchar c, char *loc, base_yyscan_t yyscanner)
 {
 	if (GetDatabaseEncoding() == PG_UTF8)
 		return;
 
 	if (c > 0x7F)
 	{
-		yylloc += (char *) loc - literalbuf + 3;   /* 3 for U&" */
+		ADVANCE_YYLLOC(loc - yyextra->literalbuf + 3);   /* 3 for U&" */
 		yyerror("Unicode escape values cannot be used for code point values above 007F when the server encoding is not UTF8");
 	}
 }
 
 static char *
-litbuf_udeescape(unsigned char escape)
+litbuf_udeescape(unsigned char escape, base_yyscan_t yyscanner)
 {
 	char *new;
-	char *in, *out;
+	char *litbuf, *in, *out;
 
 	if (isxdigit(escape)
 		|| escape == '+'
@@ -1036,17 +1077,21 @@ litbuf_udeescape(unsigned char escape)
 		|| escape == '"'
 		|| scanner_isspace(escape))
 	{
-		yylloc += literallen + yyleng + 1;
+		ADVANCE_YYLLOC(yyextra->literallen + yyleng + 1);
 		yyerror("invalid Unicode escape character");
 	}
 
+	/* Make literalbuf null-terminated to simplify the scanning loop */
+	litbuf = yyextra->literalbuf;
+	litbuf[yyextra->literallen] = '\0';
+
 	/*
 	 * This relies on the subtle assumption that a UTF-8 expansion
 	 * cannot be longer than its escaped representation.
 	 */
-	new = palloc(literallen + 1);
+	new = palloc(yyextra->literallen + 1);
 
-	in = literalbuf;
+	in = litbuf;
 	out = new;
 	while (*in)
 	{
@@ -1060,7 +1105,7 @@ litbuf_udeescape(unsigned char escape)
 			else if (isxdigit(in[1]) && isxdigit(in[2]) && isxdigit(in[3]) && isxdigit(in[4]))
 			{
 				pg_wchar unicode = hexval(in[1]) * 16*16*16 + hexval(in[2]) * 16*16 + hexval(in[3]) * 16 + hexval(in[4]);
-				check_unicode_value(unicode, in);
+				check_unicode_value(unicode, in, yyscanner);
 				unicode_to_utf8(unicode, (unsigned char *) out);
 				in += 5;
 				out += pg_mblen(out);
@@ -1072,14 +1117,14 @@ litbuf_udeescape(unsigned char escape)
 			{
 				pg_wchar unicode = hexval(in[2]) * 16*16*16*16*16 + hexval(in[3]) * 16*16*16*16 + hexval(in[4]) * 16*16*16
 									+ hexval(in[5]) * 16*16 + hexval(in[6]) * 16 + hexval(in[7]);
-				check_unicode_value(unicode, in);
+				check_unicode_value(unicode, in, yyscanner);
 				unicode_to_utf8(unicode, (unsigned char *) out);
 				in += 8;
 				out += pg_mblen(out);
 			}
 			else
 			{
-				yylloc += in - literalbuf + 3;   /* 3 for U&" */
+				ADVANCE_YYLLOC(in - litbuf + 3);   /* 3 for U&" */
 				yyerror("invalid Unicode escape value");
 			}
 		}
@@ -1098,7 +1143,7 @@ litbuf_udeescape(unsigned char escape)
 }
 
 static unsigned char
-unescape_single_char(unsigned char c)
+unescape_single_char(unsigned char c, base_yyscan_t yyscanner)
 {
 	switch (c)
 	{
@@ -1115,47 +1160,74 @@ unescape_single_char(unsigned char c)
 		default:
 			/* check for backslash followed by non-7-bit-ASCII */
 			if (c == '\0' || IS_HIGHBIT_SET(c))
-				saw_non_ascii = true;
+				yyextra->saw_non_ascii = true;
 
 			return c;
 	}
 }
 
 static void
-check_string_escape_warning(unsigned char ychar)
+check_string_escape_warning(unsigned char ychar, base_yyscan_t yyscanner)
 {
 	if (ychar == '\'')
 	{
-		if (warn_on_first_escape && escape_string_warning)
+		if (yyextra->warn_on_first_escape && escape_string_warning)
 			ereport(WARNING,
 					(errcode(ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER),
 					 errmsg("nonstandard use of \\' in a string literal"),
 					 errhint("Use '' to write quotes in strings, or use the escape string syntax (E'...')."),
 					 lexer_errposition()));
-		warn_on_first_escape = false;	/* warn only once per string */
+		yyextra->warn_on_first_escape = false;	/* warn only once per string */
 	}
 	else if (ychar == '\\')
 	{
-		if (warn_on_first_escape && escape_string_warning)
+		if (yyextra->warn_on_first_escape && escape_string_warning)
 			ereport(WARNING,
 					(errcode(ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER),
 					 errmsg("nonstandard use of \\\\ in a string literal"),
 					 errhint("Use the escape string syntax for backslashes, e.g., E'\\\\'."),
 					 lexer_errposition()));
-		warn_on_first_escape = false;	/* warn only once per string */
+		yyextra->warn_on_first_escape = false;	/* warn only once per string */
 	}
 	else
-		check_escape_warning();
+		check_escape_warning(yyscanner);
 }
 
 static void
-check_escape_warning(void)
+check_escape_warning(base_yyscan_t yyscanner)
 {
-	if (warn_on_first_escape && escape_string_warning)
+	if (yyextra->warn_on_first_escape && escape_string_warning)
 		ereport(WARNING,
 				(errcode(ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER),
 				 errmsg("nonstandard use of escape in a string literal"),
 				 errhint("Use the escape string syntax for escapes, e.g., E'\\r\\n'."),
 				 lexer_errposition()));
-	warn_on_first_escape = false;	/* warn only once per string */
+	yyextra->warn_on_first_escape = false;	/* warn only once per string */
+}
+
+/*
+ * Interface functions to make flex use palloc() instead of malloc().
+ * It'd be better to make these static, but flex insists otherwise.
+ */
+
+void *
+base_yyalloc(size_t bytes, base_yyscan_t yyscanner)
+{
+	return palloc(bytes);
+}
+
+void *
+base_yyrealloc(void *ptr, size_t bytes, base_yyscan_t yyscanner)
+{
+	if (ptr)
+		return repalloc(ptr, bytes);
+	else
+		return palloc(bytes);
+}
+
+void
+base_yyfree(void *ptr, base_yyscan_t yyscanner)
+{
+	if (ptr)
+		pfree(ptr);
 }
diff --git a/src/include/parser/gramparse.h b/src/include/parser/gramparse.h
index 31290a270c8488093b9b1d8c0636761bde772ae9..a8c2f407e4bfee0b915f9d072e753da300f351ae 100644
--- a/src/include/parser/gramparse.h
+++ b/src/include/parser/gramparse.h
@@ -11,7 +11,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/parser/gramparse.h,v 1.45 2009/07/12 17:12:34 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/parser/gramparse.h,v 1.46 2009/07/13 02:02:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -36,19 +36,85 @@
  */
 #include "parser/gram.h"
 
+/*
+ * The YY_EXTRA data that a flex scanner allows us to pass around.  Private
+ * state needed for raw parsing/lexing goes here.
+ */
+typedef struct base_yy_extra_type
+{
+	/*
+	 * The string the lexer is physically scanning.  We keep this mainly so
+	 * that we can cheaply compute the offset of the current token (yytext).
+	 */
+	char	   *scanbuf;
+	Size		scanbuflen;
+
+	/*
+	 * literalbuf is used to accumulate literal values when multiple rules
+	 * are needed to parse a single literal.  Call startlit() to reset buffer
+	 * to empty, addlit() to add text.  NOTE: the string in literalbuf is
+	 * NOT necessarily null-terminated, but there always IS room to add a
+	 * trailing null at offset literallen.  We store a null only when we
+	 * need it.
+	 */
+	char	   *literalbuf;		/* palloc'd expandable buffer */
+	int			literallen;		/* actual current string length */
+	int			literalalloc;	/* current allocated buffer size */
+
+	int			xcdepth;		/* depth of nesting in slash-star comments */
+	char	   *dolqstart;		/* current $foo$ quote start string */
+
+	/* state variables for literal-lexing warnings */
+	bool		warn_on_first_escape;
+	bool		saw_non_ascii;
+
+	/*
+	 * State variables for filtered_base_yylex().
+	 */
+	bool		have_lookahead;		/* is lookahead info valid? */
+	int			lookahead_token;	/* one-token lookahead */
+	YYSTYPE		lookahead_yylval;	/* yylval for lookahead token */
+	YYLTYPE		lookahead_yylloc;	/* yylloc for lookahead token */
+
+	/*
+	 * State variables that belong to the grammar, not the lexer.  It's
+	 * simpler to keep these here than to invent a separate structure.
+	 * These fields are unused/undefined if the lexer is invoked on its own.
+	 */
+
+	List	   *parsetree;		/* final parse result is delivered here */
+
+	bool		QueryIsRule;	/* signals we are parsing CREATE RULE */
+} base_yy_extra_type;
+
+/*
+ * The type of yyscanner is opaque outside scan.l.
+ */
+typedef void *base_yyscan_t;
+
+/*
+ * In principle we should use yyget_extra() to fetch the yyextra field
+ * from a yyscanner struct.  However, flex always puts that field first,
+ * and this is sufficiently performance-critical to make it seem worth
+ * cheating a bit to use an inline macro.
+ */
+#define pg_yyget_extra(yyscanner) (*((base_yy_extra_type **) (yyscanner)))
+
 
 /* from parser.c */
-extern int	filtered_base_yylex(void);
+extern int	filtered_base_yylex(YYSTYPE *lvalp, YYLTYPE *llocp,
+								base_yyscan_t yyscanner);
 
 /* from scan.l */
-extern void scanner_init(const char *str);
-extern void scanner_finish(void);
-extern int	base_yylex(void);
-extern int	scanner_errposition(int location);
-extern void base_yyerror(const char *message);
+extern base_yyscan_t scanner_init(const char *str, base_yy_extra_type *yyext);
+extern void scanner_finish(base_yyscan_t yyscanner);
+extern int	base_yylex(YYSTYPE *lvalp, YYLTYPE *llocp,
+					   base_yyscan_t yyscanner);
+extern int	scanner_errposition(int location, base_yyscan_t yyscanner);
+extern void scanner_yyerror(const char *message, base_yyscan_t yyscanner);
 
 /* from gram.y */
-extern void parser_init(void);
-extern int	base_yyparse(void);
+extern void parser_init(base_yy_extra_type *yyext);
+extern int	base_yyparse(base_yyscan_t yyscanner);
 
 #endif   /* GRAMPARSE_H */